Refactor in a single package with subpackages
[deliverable/lttng-analyses.git] / lttnganalyses / cli / cputop.py
1 #!/usr/bin/env python3
2 #
3 # The MIT License (MIT)
4 #
5 # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
6 # 2015 - Antoine Busque <abusque@efficios.com>
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is
13 # furnished to do so, subject to the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be included in
16 # all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 # SOFTWARE.
25
26 from .command import Command
27 from ..core import cputop
28 from ..ascii_graph import Pyasciigraph
29 import operator
30
31
32 class Cputop(Command):
33 _DESC = """The cputop command."""
34
35 def __init__(self):
36 super().__init__(self._add_arguments, enable_proc_filter_args=True)
37
38 def _validate_transform_args(self):
39 pass
40
41 def run(self):
42 # parse arguments first
43 self._parse_args()
44 # validate, transform and save specific arguments
45 self._validate_transform_args()
46 # open the trace
47 self._open_trace()
48 # create the appropriate analysis/analyses
49 self._create_analysis()
50 # run the analysis
51 self._run_analysis(self._reset_total, self._refresh)
52 # process the results
53 self._compute_stats()
54 # print results
55 self._print_results(self.start_ns, self.trace_end_ts)
56 # close the trace
57 self._close_trace()
58
59 def _create_analysis(self):
60 self._analysis = cputop.Cputop(self.state)
61
62 def _compute_stats(self):
63 self._analysis.compute_stats(self.start_ns, self.end_ns)
64
65 def _reset_total(self, start_ts):
66 self._analysis.reset(start_ts)
67
68 def _refresh(self, begin, end):
69 self._compute_stats()
70 self._print_results(begin, end)
71 self._reset_total(end)
72
73 def _filter_process(self, proc):
74 # Exclude swapper
75 if proc.tid == 0:
76 return False
77
78 if self._arg_proc_list and proc.comm not in self._arg_proc_list:
79 return False
80
81 return True
82
83 def _print_results(self, begin_ns, end_ns):
84 self._print_date(begin_ns, end_ns)
85 self._print_per_tid_usage()
86 self._print_per_cpu_usage()
87 self._print_total_cpu_usage()
88
89 def _print_per_tid_usage(self):
90 count = 0
91 limit = self._arg_limit
92 graph = Pyasciigraph()
93 values = []
94
95 for tid in sorted(self._analysis.tids.values(),
96 key=operator.attrgetter('usage_percent'),
97 reverse=True):
98 if not self._filter_process(tid):
99 continue
100
101 output_str = '%s (%d)' % (tid.comm, tid.tid)
102 if tid.migrate_count > 0:
103 output_str += ', %d migrations' % (tid.migrate_count)
104
105 values.append((output_str, tid.usage_percent))
106
107 count += 1
108 if limit > 0 and count >= limit:
109 break
110
111 for line in graph.graph('Per-TID CPU Usage', values, unit=' %'):
112 print(line)
113
114 def _print_per_cpu_usage(self):
115 graph = Pyasciigraph()
116 values = []
117
118 for cpu in sorted(self._analysis.cpus.values(),
119 key=operator.attrgetter('usage_percent'),
120 reverse=True):
121 values.append(('CPU %d' % cpu.cpu_id, cpu.usage_percent))
122
123 for line in graph.graph('Per-CPU Usage', values, unit=' %'):
124 print(line)
125
126 def _print_total_cpu_usage(self):
127 cpu_count = len(self.state.cpus)
128 usage_percent = 0
129
130 for cpu in sorted(self._analysis.cpus.values(),
131 key=operator.attrgetter('usage_percent'),
132 reverse=True):
133 usage_percent += cpu.usage_percent
134
135 # average per CPU
136 usage_percent /= cpu_count
137 print('\nTotal CPU Usage: %0.02f%%\n' % usage_percent)
138
139 def _add_arguments(self, ap):
140 # specific argument
141 pass
142
143
144 # entry point
145 def run():
146 # create command
147 cputopcmd = Cputop()
148
149 # execute command
150 cputopcmd.run()
This page took 0.034335 seconds and 5 git commands to generate.