IOTop
[deliverable/lttng-analyses.git] / cputop.py
1 #!/usr/bin/env python3
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12
13 import sys
14 import argparse
15 import shutil
16 import time
17 from babeltrace import *
18 from LTTngAnalyzes.common import *
19 from LTTngAnalyzes.sched import *
20 from analyzes import *
21 from ascii_graph import Pyasciigraph
22
23 class CPUTop():
24 def __init__(self, traces):
25 self.trace_start_ts = 0
26 self.trace_end_ts = 0
27 self.traces = traces
28 self.tids = {}
29 self.cpus = {}
30
31 def run(self, args):
32 """Process the trace"""
33 self.current_sec = 0
34 self.start_ns = 0
35 self.end_ns = 0
36
37 sched = Sched(self.cpus, self.tids)
38 for event in self.traces.events:
39 if self.start_ns == 0:
40 self.start_ns = event.timestamp
41 if self.trace_start_ts == 0:
42 self.trace_start_ts = event.timestamp
43 self.end_ns = event.timestamp
44 self.check_refresh(args, event)
45 self.trace_end_ts = event.timestamp
46
47 if event.name == "sched_switch":
48 sched.switch(event)
49 if args.refresh == 0:
50 # stats for the whole trace
51 self.compute_stats()
52 self.output(args, self.trace_start_ts, self.trace_end_ts, final=1)
53 else:
54 # stats only for the last segment
55 self.compute_stats()
56 self.output(args, self.start_ns, self.trace_end_ts,
57 final=1)
58
59 def check_refresh(self, args, event):
60 """Check if we need to output something"""
61 if args.refresh == 0:
62 return
63 event_sec = event.timestamp / NSEC_PER_SEC
64 if self.current_sec == 0:
65 self.current_sec = event_sec
66 elif self.current_sec != event_sec and \
67 (self.current_sec + args.refresh) <= event_sec:
68 self.compute_stats()
69 self.output(args, self.start_ns, event.timestamp)
70 self.reset_total(event.timestamp)
71 self.current_sec = event_sec
72 self.start_ns = event.timestamp
73
74 def compute_stats(self):
75 for cpu in self.cpus.keys():
76 current_cpu = self.cpus[cpu]
77 total_ns = self.end_ns - self.start_ns
78 if current_cpu.start_task_ns != 0:
79 current_cpu.cpu_ns += self.end_ns - current_cpu.start_task_ns
80 cpu_total_ns = current_cpu.cpu_ns
81 current_cpu.cpu_pc = (cpu_total_ns * 100)/total_ns
82 if current_cpu.current_tid >= 0:
83 self.tids[current_cpu.current_tid].cpu_ns += \
84 self.end_ns - current_cpu.start_task_ns
85
86 def output(self, args, begin_ns, end_ns, final=0):
87 count = 0
88 limit = args.top
89 total_ns = end_ns - begin_ns
90 graph = Pyasciigraph()
91 values = []
92 print('%s to %s' % (ns_to_asctime(begin_ns), ns_to_asctime(end_ns)))
93 for tid in sorted(self.tids.values(),
94 key=operator.attrgetter('cpu_ns'), reverse=True):
95 if len(args.proc_list) > 0 and tid.comm not in args.proc_list:
96 continue
97 pc = float("%0.02f" % ((tid.cpu_ns * 100) / total_ns))
98 values.append(("%s (%d)" % (tid.comm, tid.tid), pc))
99 count = count + 1
100 if limit > 0 and count >= limit:
101 break
102 for line in graph.graph("Per-TID CPU Usage", values):
103 print(line)
104
105 values = []
106 nb_cpu = len(self.cpus.keys())
107 for cpu in sorted(self.cpus.values(),
108 key=operator.attrgetter('cpu_ns'), reverse=True):
109 cpu_total_ns = cpu.cpu_ns
110 cpu_pc = float("%0.02f" % cpu.cpu_pc)
111 values.append(("CPU %d" % cpu.cpu_id, cpu_pc))
112 for line in graph.graph("Per-CPU Usage", values):
113 print(line)
114
115 def reset_total(self, start_ts):
116 for cpu in self.cpus.keys():
117 current_cpu = self.cpus[cpu]
118 current_cpu.cpu_ns = 0
119 if current_cpu.start_task_ns != 0:
120 current_cpu.start_task_ns = start_ts
121 if current_cpu.current_tid >= 0:
122 self.tids[current_cpu.current_tid].last_sched = start_ts
123 for tid in self.tids.keys():
124 self.tids[tid].cpu_ns = 0
125 self.tids[tid].migrate_count = 0
126 self.tids[tid].read = 0
127 self.tids[tid].write = 0
128 for syscall in self.tids[tid].syscalls.keys():
129 self.tids[tid].syscalls[syscall].count = 0
130
131 if __name__ == "__main__":
132 parser = argparse.ArgumentParser(description='CPU usage analysis')
133 parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
134 parser.add_argument('-r', '--refresh', type=int,
135 help='Refresh period in seconds', default=0)
136 parser.add_argument('--top', type=int, default=10,
137 help='Limit to top X TIDs (default = 10)')
138 args = parser.parse_args()
139 args.proc_list = []
140
141 traces = TraceCollection()
142 handle = traces.add_trace(args.path, "ctf")
143 if handle is None:
144 sys.exit(1)
145
146 c = CPUTop(traces)
147
148 c.run(args)
149
150 traces.remove_trace(handle)
This page took 0.039149 seconds and 6 git commands to generate.