Fix: correct typo in author email address
[deliverable/lttng-analyses.git] / lttnganalysescli / lttnganalysescli / cputop.py
1 #!/usr/bin/env python3
2 #
3 # The MIT License (MIT)
4 #
5 # Copyright (C) 2015 - Julien Desfossez <jdesfossez@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 import lttnganalyses.cputop
27 from linuxautomaton import common
28 from ascii_graph import Pyasciigraph
29 import operator
30
31
32 class Cputop(Command):
33 _VERSION = '0.1.0'
34 _DESC = """The cputop command."""
35
36 def __init__(self):
37 super().__init__(self._add_arguments, enable_proc_filter_args=True)
38
39 def _validate_transform_args(self):
40 pass
41
42 def run(self):
43 # parse arguments first
44 self._parse_args()
45 # validate, transform and save specific arguments
46 self._validate_transform_args()
47 # open the trace
48 self._open_trace()
49 # create the appropriate analysis/analyses
50 self._create_analysis()
51 # run the analysis
52 self._run_analysis(self._reset_total, self._refresh)
53 # process the results
54 self._compute_stats()
55 # print results
56 self._print_results(self.start_ns, self.trace_end_ts, final=1)
57 # close the trace
58 self._close_trace()
59
60 def _create_analysis(self):
61 self._analysis = lttnganalyses.cputop.Cputop(self._automaton.state)
62
63 def _compute_stats(self):
64 self.state = self._automaton.state
65 for cpu in self.state.cpus.keys():
66 current_cpu = self.state.cpus[cpu]
67 total_ns = self.end_ns - self.start_ns
68 if current_cpu.start_task_ns != 0:
69 current_cpu.cpu_ns += self.end_ns - current_cpu.start_task_ns
70 cpu_total_ns = current_cpu.cpu_ns
71 current_cpu.cpu_pc = (cpu_total_ns * 100)/total_ns
72 if current_cpu.current_tid >= 0:
73 self.state.tids[current_cpu.current_tid].cpu_ns += \
74 self.end_ns - current_cpu.start_task_ns
75
76 def _reset_total(self, start_ts):
77 self.state = self._automaton.state
78 for cpu in self.state.cpus.keys():
79 current_cpu = self.state.cpus[cpu]
80 current_cpu.cpu_ns = 0
81 if current_cpu.start_task_ns != 0:
82 current_cpu.start_task_ns = start_ts
83 if current_cpu.current_tid >= 0:
84 self.state.tids[current_cpu.current_tid].last_sched = start_ts
85 for tid in self.state.tids.keys():
86 self.state.tids[tid].cpu_ns = 0
87 self.state.tids[tid].migrate_count = 0
88 self.state.tids[tid].read = 0
89 self.state.tids[tid].write = 0
90 for syscall in self.state.tids[tid].syscalls.keys():
91 self.state.tids[tid].syscalls[syscall].count = 0
92
93 def _refresh(self, begin, end):
94 self._compute_stats()
95 self._print_results(begin, end, final=0)
96 self._reset_total(end)
97
98 def _print_results(self, begin_ns, end_ns, final=0):
99 # print('event count: {}'.format(self._analysis.event_count))
100 count = 0
101 limit = self._arg_limit
102 total_ns = end_ns - begin_ns
103 graph = Pyasciigraph()
104 values = []
105 print('Timerange: [%s, %s]' % (
106 common.ns_to_hour_nsec(begin_ns, gmt=self._arg_gmt,
107 multi_day=True),
108 common.ns_to_hour_nsec(end_ns, gmt=self._arg_gmt,
109 multi_day=True)))
110 for tid in sorted(self.state.tids.values(),
111 key=operator.attrgetter('cpu_ns'), reverse=True):
112 if self._arg_proc_list and tid.comm not in self._arg_proc_list:
113 continue
114 if tid.tid == 0:
115 continue
116 pc = float("%0.02f" % ((tid.cpu_ns * 100) / total_ns))
117 if tid.migrate_count > 0:
118 migrations = ", %d migrations" % (tid.migrate_count)
119 else:
120 migrations = ""
121 values.append(("%s (%d)%s" % (tid.comm, tid.tid, migrations), pc))
122 count = count + 1
123 if limit > 0 and count >= limit:
124 break
125 for line in graph.graph("Per-TID CPU Usage", values, unit=" %"):
126 print(line)
127
128 values = []
129 total_cpu_pc = 0
130 for cpu in sorted(self.state.cpus.values(),
131 key=operator.attrgetter('cpu_ns'), reverse=True):
132 cpu_pc = float("%0.02f" % cpu.cpu_pc)
133 total_cpu_pc += cpu_pc
134 values.append(("CPU %d" % cpu.cpu_id, cpu_pc))
135 for line in graph.graph("Per-CPU Usage", values, unit=" %"):
136 print(line)
137 print("\nTotal CPU Usage: %0.02f%%\n" %
138 (total_cpu_pc / len(self.state.cpus.keys())))
139
140 def _add_arguments(self, ap):
141 # specific argument
142 pass
143
144
145 # entry point
146 def run():
147 # create command
148 cputopcmd = Cputop()
149
150 # execute command
151 cputopcmd.run()
This page took 0.034161 seconds and 5 git commands to generate.