Use core/stats in cputop and sched, add prio_list support
[deliverable/lttng-analyses.git] / lttnganalyses / cli / mitest.py
CommitLineData
9e5ccbbf
PP
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
9e5ccbbf
PP
25import operator
26from . import mi
0b250a71
AB
27from ..core import cputop
28from .command import Command
29from ..ascii_graph import Pyasciigraph
9e5ccbbf
PP
30
31
32class Cputop(Command):
33 _DESC = """The cputop command."""
34 _ANALYSIS_CLASS = cputop.Cputop
35 _MI_TITLE = 'Top CPU usage'
36 _MI_DESCRIPTION = 'Per-TID, per-CPU, and total top CPU usage'
37 _MI_TAGS = [mi.Tags.CPU, mi.Tags.TOP]
38 _MI_TABLE_CLASS_PER_PROC = 'per-process'
39 _MI_TABLE_CLASS_PER_CPU = 'per-cpu'
40 _MI_TABLE_CLASS_TOTAL = 'total'
41 _MI_TABLE_CLASS_SUMMARY = 'summary'
42 _MI_TABLE_CLASSES = [
43 (
44 _MI_TABLE_CLASS_PER_PROC,
45 'Per-TID top CPU usage', [
46 ('process', 'Process', mi.Process),
47 ('migrations', 'Migration count', mi.Integer, 'migrations'),
48 ('usage', 'CPU usage', mi.Ratio),
49 ]
50 ),
51 (
52 _MI_TABLE_CLASS_PER_CPU,
53 'Per-CPU top CPU usage', [
54 ('cpu', 'CPU', mi.Cpu),
55 ('usage', 'CPU usage', mi.Ratio),
56 ]),
57 (
58 _MI_TABLE_CLASS_TOTAL,
59 'Total CPU usage', [
60 ('usage', 'CPU usage', mi.Ratio),
61 ]
62 ),
63 (
64 _MI_TABLE_CLASS_SUMMARY,
65 'CPU usage - summary', [
66 ('time_range', 'Time range', mi.TimeRange),
67 ('usage', 'Total CPU usage', mi.Ratio),
68 ]
69 ),
70 ]
71
72 def _filter_process(self, proc):
73 # Exclude swapper
74 if proc.tid == 0:
75 return False
76
77 if self._args.proc_list and proc.comm not in self._args.proc_list:
78 return False
79
80 return True
81
82 def _analysis_tick(self, begin_ns, end_ns):
83 per_tid_table = self._get_per_tid_usage_result_table(begin_ns, end_ns)
84 per_cpu_table = self._get_per_cpu_usage_result_table(begin_ns, end_ns)
85 total_table = self._get_total_usage_result_table(begin_ns, end_ns)
86
87 if self._mi_mode:
88 self._mi_append_result_table(per_tid_table)
89 self._mi_append_result_table(per_cpu_table)
90 self._mi_append_result_table(total_table)
91 else:
92 self._print_date(begin_ns, end_ns)
93 self._print_per_tid_usage(per_tid_table)
94 self._print_per_cpu_usage(per_cpu_table)
95
96 if total_table:
97 self._print_total_cpu_usage(total_table)
98
99 def _create_summary_result_tables(self):
100 total_tables = self._mi_get_result_tables(self._MI_TABLE_CLASS_TOTAL)
101 begin = total_tables[0].timerange.begin
102 end = total_tables[-1].timerange.end
103 summary_table = \
104 self._mi_create_result_table(self._MI_TABLE_CLASS_SUMMARY,
105 begin, end)
106
107 for total_table in total_tables:
108 usage = total_table.rows[0].usage
109 summary_table.append_row(
110 time_range=total_table.timerange,
111 usage=usage,
112 )
113
114 self._mi_clear_result_tables()
115 self._mi_append_result_table(summary_table)
116
117 def _get_per_tid_usage_result_table(self, begin_ns, end_ns):
118 result_table = \
119 self._mi_create_result_table(self._MI_TABLE_CLASS_PER_PROC,
120 begin_ns, end_ns)
121 count = 0
122
123 for tid in sorted(self._analysis.tids.values(),
124 key=operator.attrgetter('usage_percent'),
125 reverse=True):
126 if not self._filter_process(tid):
127 continue
128
129 result_table.append_row(
130 process=mi.Process(tid.comm, tid=tid.tid),
131 migrations=mi.Integer(tid.migrate_count),
132 usage=mi.Ratio.from_percentage(tid.usage_percent)
133 )
134 count += 1
135
136 if self._args.limit > 0 and count >= self._args.limit:
137 break
138
139 return result_table
140
141 def _get_per_cpu_usage_result_table(self, begin_ns, end_ns):
142 result_table = \
143 self._mi_create_result_table(self._MI_TABLE_CLASS_PER_CPU,
144 begin_ns, end_ns)
145
146 for cpu in sorted(self._analysis.cpus.values(),
147 key=operator.attrgetter('usage_percent'),
148 reverse=True):
149 result_table.append_row(
150 cpu=mi.Cpu(cpu.cpu_id),
151 usage=mi.Ratio.from_percentage(cpu.usage_percent)
152 )
153
154 return result_table
155
156 def _get_total_usage_result_table(self, begin_ns, end_ns):
157 result_table = \
158 self._mi_create_result_table(self._MI_TABLE_CLASS_TOTAL,
159 begin_ns, end_ns)
160
161 cpu_count = len(self.state.cpus)
162 usage_percent = 0
163
164 if not cpu_count:
165 return
166
167 for cpu in sorted(self._analysis.cpus.values(),
168 key=operator.attrgetter('usage_percent'),
169 reverse=True):
170 usage_percent += cpu.usage_percent
171
172 # average per CPU
173 usage_percent /= cpu_count
174 result_table.append_row(
175 usage=mi.Ratio.from_percentage(usage_percent),
176 )
177
178 return result_table
179
180 def _print_per_tid_usage(self, result_table):
181 graph = Pyasciigraph()
182 values = []
183
184 for row in result_table.rows:
185 process_do = row.process
186 migration_count = row.migrations.value
187 output_str = '%s (%d)' % (process_do.name, process_do.tid)
188
189 if migration_count > 0:
190 output_str += ', %d migrations' % (migration_count)
191
192 values.append((output_str, row.usage.to_percentage()))
193
194 for line in graph.graph('Per-TID CPU Usage', values, unit=' %'):
195 print(line)
196
197 def _print_per_cpu_usage(self, result_table):
198 graph = Pyasciigraph()
199 values = []
200
201 for row in result_table.rows:
202 cpu = row.cpu
203 values.append(('CPU %d' % cpu.id, row.usage.to_percentage()))
204
205 for line in graph.graph('Per-CPU Usage', values, unit=' %'):
206 print(line)
207
208 def _print_total_cpu_usage(self, result_table):
209 usage_percent = result_table.rows[0].usage.to_percentage()
210 print('\nTotal CPU Usage: %0.02f%%\n' % usage_percent)
211
212 def _add_arguments(self, ap):
213 Command._add_proc_filter_args(ap)
214
215
216def _run(mi_mode):
217 cputopcmd = Cputop(mi_mode=mi_mode)
218 cputopcmd.run()
219
220
221# entry point (human)
222def run():
223 _run(mi_mode=False)
224
225
226# entry point (MI)
227def run_mi():
228 _run(mi_mode=True)
This page took 0.031861 seconds and 5 git commands to generate.