Implement sched switch latency analysis
[deliverable/lttng-analyses.git] / lttnganalyses / cli / memtop.py
1 # The MIT License (MIT)
2 #
3 # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
4 # 2015 - Antoine Busque <abusque@efficios.com>
5 # 2015 - Philippe Proulx <pproulx@efficios.com>
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
24
25 from .command import Command
26 from ..core import memtop
27 from ..ascii_graph import Pyasciigraph
28 from . import mi
29 import operator
30
31
32 class Memtop(Command):
33 _DESC = """The memtop command."""
34 _ANALYSIS_CLASS = memtop.Memtop
35 _MI_TITLE = 'Top memory usage'
36 _MI_DESCRIPTION = 'Per-TID top allocated/freed memory'
37 _MI_TAGS = [mi.Tags.MEMORY, mi.Tags.TOP]
38 _MI_TABLE_CLASS_ALLOCD = 'allocd'
39 _MI_TABLE_CLASS_FREED = 'freed'
40 _MI_TABLE_CLASS_TOTAL = 'total'
41 _MI_TABLE_CLASS_SUMMARY = 'summary'
42 _MI_TABLE_CLASSES = [
43 (
44 _MI_TABLE_CLASS_ALLOCD,
45 'Per-TID top allocated memory', [
46 ('process', 'Process', mi.Process),
47 ('pages', 'Allocated pages', mi.Integer, 'pages'),
48 ]
49 ),
50 (
51 _MI_TABLE_CLASS_FREED,
52 'Per-TID top freed memory', [
53 ('process', 'Process', mi.Process),
54 ('pages', 'Freed pages', mi.Integer, 'pages'),
55 ]
56 ),
57 (
58 _MI_TABLE_CLASS_TOTAL,
59 'Total allocated/freed memory', [
60 ('allocd', 'Total allocated pages', mi.Integer, 'pages'),
61 ('freed', 'Total freed pages', mi.Integer, 'pages'),
62 ]
63 ),
64 (
65 _MI_TABLE_CLASS_SUMMARY,
66 'Memory usage - summary', [
67 ('time_range', 'Time range', mi.TimeRange),
68 ('allocd', 'Total allocated pages', mi.Integer, 'pages'),
69 ('freed', 'Total freed pages', mi.Integer, 'pages'),
70 ]
71 ),
72 ]
73
74 def _analysis_tick(self, begin_ns, end_ns):
75 allocd_table = self._get_per_tid_allocd_result_table(begin_ns, end_ns)
76 freed_table = self._get_per_tid_freed_result_table(begin_ns, end_ns)
77 total_table = self._get_total_result_table(begin_ns, end_ns)
78
79 if self._mi_mode:
80 self._mi_append_result_table(allocd_table)
81 self._mi_append_result_table(freed_table)
82 self._mi_append_result_table(total_table)
83 else:
84 self._print_date(begin_ns, end_ns)
85 self._print_per_tid_allocd(allocd_table)
86 self._print_per_tid_freed(freed_table)
87 self._print_total(total_table)
88
89 def _create_summary_result_tables(self):
90 total_tables = self._mi_get_result_tables(self._MI_TABLE_CLASS_TOTAL)
91 begin = total_tables[0].timerange.begin
92 end = total_tables[-1].timerange.end
93 summary_table = \
94 self._mi_create_result_table(self._MI_TABLE_CLASS_SUMMARY,
95 begin, end)
96
97 for total_table in total_tables:
98 total_allocd = total_table.rows[0].allocd
99 total_freed = total_table.rows[0].freed
100 summary_table.append_row(
101 time_range=total_table.timerange,
102 allocd=total_allocd,
103 freed=total_freed,
104 )
105
106 self._mi_clear_result_tables()
107 self._mi_append_result_table(summary_table)
108
109 def _get_per_tid_attr_result_table(self, table_class, attr,
110 begin_ns, end_ns):
111 result_table = self._mi_create_result_table(table_class,
112 begin_ns, end_ns)
113 count = 0
114
115 for tid in sorted(self._analysis.tids.values(),
116 key=operator.attrgetter(attr),
117 reverse=True):
118 if not self._filter_process(tid):
119 continue
120
121 result_table.append_row(
122 process=mi.Process(tid.comm, tid=tid.tid),
123 pages=mi.Integer(getattr(tid, attr)),
124 )
125 count += 1
126
127 if self._args.limit > 0 and count >= self._args.limit:
128 break
129
130 return result_table
131
132 def _get_per_tid_allocd_result_table(self, begin_ns, end_ns):
133 return self._get_per_tid_attr_result_table(self._MI_TABLE_CLASS_ALLOCD,
134 'allocated_pages',
135 begin_ns, end_ns)
136
137 def _get_per_tid_freed_result_table(self, begin_ns, end_ns):
138 return self._get_per_tid_attr_result_table(self._MI_TABLE_CLASS_FREED,
139 'freed_pages',
140 begin_ns, end_ns)
141
142 def _get_total_result_table(self, begin_ns, end_ns):
143 result_table = self._mi_create_result_table(self._MI_TABLE_CLASS_TOTAL,
144 begin_ns, end_ns)
145 alloc = 0
146 freed = 0
147
148 for tid in self._analysis.tids.values():
149 if not self._filter_process(tid):
150 continue
151
152 alloc += tid.allocated_pages
153 freed += tid.freed_pages
154
155 result_table.append_row(
156 allocd=mi.Integer(alloc),
157 freed=mi.Integer(freed),
158 )
159
160 return result_table
161
162 def _print_per_tid_result(self, result_table, title):
163 graph = Pyasciigraph()
164 values = []
165
166 for row in result_table.rows:
167 process_do = row.process
168 pages = row.pages.value
169 values.append(('%s (%d)' % (process_do.name, process_do.tid),
170 pages))
171
172 for line in graph.graph(title, values, unit=' pages'):
173 print(line)
174
175 def _print_per_tid_allocd(self, result_table):
176 self._print_per_tid_result(result_table, 'Per-TID Memory Allocations')
177
178 def _print_per_tid_freed(self, result_table):
179 self._print_per_tid_result(result_table,
180 'Per-TID Memory Deallocations')
181
182 def _print_total(self, result_table):
183 alloc = result_table.rows[0].allocd.value
184 freed = result_table.rows[0].freed.value
185 print('\nTotal memory usage:\n- %d pages allocated\n- %d pages freed' %
186 (alloc, freed))
187
188 def _add_arguments(self, ap):
189 Command._add_proc_filter_args(ap)
190 Command._add_top_args(ap)
191
192
193 def _run(mi_mode):
194 memtopcmd = Memtop(mi_mode=mi_mode)
195 memtopcmd.run()
196
197
198 # entry point (human)
199 def run():
200 _run(mi_mode=False)
201
202
203 # entry point (MI)
204 def run_mi():
205 _run(mi_mode=True)
This page took 0.035536 seconds and 5 git commands to generate.