Asterisk - The Open Source Telephony Project GIT-master-f36a736
refstats.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""Process a ref debug log for memory usage
3
4 This will provide information about total and peak
5 allocations.
6
7 See http://www.asterisk.org for more information about
8 the Asterisk project. Please do not directly contact
9 any of the maintainers of this project for assistance;
10 the project provides a web site, mailing lists and IRC
11 channels for your use.
12
13 This program is free software, distributed under the terms of
14 the GNU General Public License Version 2. See the LICENSE file
15 at the top of the source tree.
16
17 Copyright (C) 2018, CFWare, LLC
18 Corey Farrell <git@cfware.com>
19"""
20
21from __future__ import print_function
22import sys
23import os
24
25from optparse import OptionParser
26
27
29 """Create statistics object"""
30 return {
31 'count': 0,
32 'overhead': 0,
33 'user_data': 0,
34 'totalmem': 0
35 }
36
37
38def update_stats(current, peak, total, key, direction, delta):
39 """Update statistics objects"""
40
41 if direction == 1:
42 total[key] += delta
43
44 delta *= direction
45 current[key] += delta
46 if current[key] > peak[key]:
47 peak[key] = current[key]
48
49
50def process_file(options):
51 """The routine that kicks off processing a ref file"""
52
53 current = create_stats()
54 total = create_stats()
55 peak = create_stats()
56 object_types = {}
57 objects = {}
58 filename = options.filepath
59
60 with open(filename, 'r') as ref_file:
61 for line in ref_file:
62 if 'constructor' not in line and 'destructor' not in line:
63 continue
64 # The line format is:
65 # addr,delta,thread_id,file,line,function,state,tag
66 # Only addr, file, line, function, state are used by reflocks.py
67 tokens = line.strip().split(',', 7)
68 addr = tokens[0]
69 state = tokens[6]
70 if 'constructor' in state:
71 split_state = state.split("**")
72 if len(split_state) < 4:
73 print("File does not contain object size information", file=sys.stderr)
74 sys.exit(1)
75
76 obj_type = '%s:%s:%s' % (tokens[3], tokens[4], tokens[5])
77 if obj_type not in object_types:
78 object_types[obj_type] = {
79 'used': 0,
80 'unused': 0,
81 'none': 0
82 }
83 overhead = int(split_state[2])
84 user_data = int(split_state[3])
85 obj = objects[addr] = {
86 'overhead': overhead,
87 'user_data': user_data,
88 'obj_type': obj_type
89 }
90
91 direction = 1
92 else:
93 if addr not in objects:
94 # This error would be reported by refcounter.py.
95 continue
96 obj = objects[addr]
97 del objects[addr]
98 direction = -1
99 obj_type = obj['obj_type']
100 if '**lock-state:unused**' in state:
101 object_types[obj_type]['unused'] += 1
102 elif '**lock-state:used**' in state:
103 object_types[obj_type]['used'] += 1
104
105 # Increment current and peak usage
106 update_stats(current, peak, total, 'count', direction, 1)
107 update_stats(current, peak, total, 'overhead', direction, obj['overhead'])
108 update_stats(current, peak, total, 'user_data', direction, obj['user_data'])
109 update_stats(current, peak, total, 'totalmem', direction, obj['overhead'] + obj['user_data'])
110
111 print("Total usage statistics:")
112 print("%20s: %d" % ("Count", total['count']))
113 print("%20s: %d" % ("Total Memory (k)", total['totalmem'] / 1024))
114 print("%20s: %d (%.2f%%)" % ("Overhead (k)", total['overhead'] / 1024, total['overhead'] * 100.0 / total['totalmem']))
115 print("%20s: %d" % ("User Data (k)", total['user_data'] / 1024))
116 print("")
117 print("Peak usage statistics:")
118 print("%20s: %d" % ("Count", peak['count']))
119 print("%20s: %d" % ("Total Memory (k)", peak['totalmem'] / 1024))
120 print("%20s: %d (%.2f%%)" % ("Overhead (k)", peak['overhead'] / 1024, peak['overhead'] * 100.0 / peak['totalmem']))
121 print("%20s: %d" % ("User Data (k)", peak['user_data'] / 1024))
122 print("")
123
124 lockbyobj = {'used': 0, 'total': 0}
125 lockbytype = {'used': 0, 'total': 0}
126 for (allocator, info) in object_types.items():
127 lockbyobj['used'] += info['used']
128 lockbyobj['total'] += info['used'] + info['unused']
129
130 if info['used'] != 0:
131 lockbytype['used'] += 1
132 elif info['unused'] == 0:
133 # This object type doesn't have locking.
134 continue
135 lockbytype['total'] += 1
136
137 print("Lock usage statistics:")
138 print("%20s: %d of %d used (%.2f%%)" % (
139 "By object",
140 lockbyobj['used'],
141 lockbyobj['total'],
142 lockbyobj['used'] * 100.0 / lockbyobj['total']))
143 print("%20s: %d of %d used (%.2f%%)" % (
144 "By type",
145 lockbytype['used'],
146 lockbytype['total'],
147 lockbytype['used'] * 100.0 / lockbytype['total']))
148
149
150def main(argv=None):
151 """Main entry point for the script"""
152
153 ret_code = 0
154
155 if argv is None:
156 argv = sys.argv
157
158 parser = OptionParser()
159
160 parser.add_option("-f", "--file", action="store", type="string",
161 dest="filepath", default="/var/log/asterisk/refs",
162 help="The full path to the refs file to process")
163
164 (options, args) = parser.parse_args(argv)
165
166 if not os.path.isfile(options.filepath):
167 print("File not found: %s" % options.filepath, file=sys.stderr)
168 return -1
169
170 try:
171 process_file(options)
172 except (KeyboardInterrupt, SystemExit, IOError):
173 print("File processing cancelled", file=sys.stderr)
174 return -1
175
176 return ret_code
177
178
179if __name__ == "__main__":
180 sys.exit(main(sys.argv))
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
def main(argv=None)
Definition: refstats.py:150
def update_stats(current, peak, total, key, direction, delta)
Definition: refstats.py:38
def process_file(options)
Definition: refstats.py:50
def create_stats()
Definition: refstats.py:28