IOTop
[deliverable/lttng-analyses.git] / analyzes.py
CommitLineData
1b09221e 1#!/usr/bin/env python3
d03b82af
JD
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
13import sys
fd893e53 14import argparse
0790ad37
JD
15import shutil
16import time
d03b82af 17from babeltrace import *
b0e6c900
JD
18from LTTngAnalyzes.common import *
19from LTTngAnalyzes.jsonreport import *
20from LTTngAnalyzes.textreport import *
0790ad37 21from LTTngAnalyzes.graphitereport import *
34a788b4 22from LTTngAnalyzes.sched import *
1595fe2d 23from LTTngAnalyzes.syscalls import *
4957863f 24from LTTngAnalyzes.block_bio import *
eb9efdcb 25from LTTngAnalyzes.net import *
87ea2bb1 26from LTTngAnalyzes.statedump import *
65d937db 27
4957863f 28class Analyzes():
d03b82af 29 def __init__(self, traces):
fd893e53
JD
30 self.trace_start_ts = 0
31 self.trace_end_ts = 0
d03b82af
JD
32 self.traces = traces
33 self.tids = {}
646f0fe6 34 self.cpus = {}
b0e6c900 35 self.syscalls = {}
4957863f 36 self.disks = {}
eb9efdcb 37 self.ifaces = {}
646f0fe6 38
a0da5181 39 def output(self, args, begin_ns, end_ns, final=0):
fd893e53 40 if args.text:
0790ad37 41 r = TextReport(self.trace_start_ts, self.trace_end_ts,
f1839094
JD
42 self.cpus, self.tids, self.syscalls, self.disks,
43 self.ifaces)
0790ad37 44 r.report(begin_ns, end_ns, final, args)
eb9efdcb 45 if not final and (args.cpu or args.tid or args.disk or args.net):
a0da5181 46 print("")
fd893e53 47 if args.json:
0790ad37 48 r = JsonReport(self.trace_start_ts, self.trace_end_ts,
b0e6c900 49 self.cpus, self.tids)
0790ad37
JD
50 r.report(begin_ns, end_ns, final, args)
51 if args.graphite:
52 r = GraphiteReport(self.trace_start_ts, self.trace_end_ts,
eb9efdcb 53 self.cpus, self.tids, self.syscalls, self.disks, self.ifaces)
0790ad37 54 r.report(begin_ns, end_ns, final, args)
fd893e53
JD
55
56 def check_refresh(self, args, event):
57 """Check if we need to output something"""
58 if args.refresh == 0:
59 return
60 event_sec = event.timestamp / NSEC_PER_SEC
61 if self.current_sec == 0:
62 self.current_sec = event_sec
63 elif self.current_sec != event_sec and \
64 (self.current_sec + args.refresh) <= event_sec:
65 self.compute_stats()
a0da5181 66 self.output(args, self.start_ns, event.timestamp)
fd893e53
JD
67 self.reset_total(event.timestamp)
68 self.current_sec = event_sec
69 self.start_ns = event.timestamp
8e784ad6 70
65d937db 71 def reset_total(self, start_ts):
8e784ad6 72 for cpu in self.cpus.keys():
a0da5181
JD
73 current_cpu = self.cpus[cpu]
74 current_cpu.cpu_ns = 0
75 if current_cpu.start_task_ns != 0:
76 current_cpu.start_task_ns = start_ts
77 if current_cpu.current_tid >= 0:
78 self.tids[current_cpu.current_tid].last_sched = start_ts
65d937db 79
d03b82af 80 for tid in self.tids.keys():
8e784ad6 81 self.tids[tid].cpu_ns = 0
b4376047 82 self.tids[tid].migrate_count = 0
b1dd3851
JD
83 self.tids[tid].read = 0
84 self.tids[tid].write = 0
ffd315c0
JD
85 for syscall in self.tids[tid].syscalls.keys():
86 self.tids[tid].syscalls[syscall].count = 0
8e784ad6 87
1595fe2d
JD
88 for syscall in self.syscalls.keys():
89 self.syscalls[syscall].count = 0
90
4957863f
JD
91 for dev in self.disks.keys():
92 self.disks[dev].nr_sector = 0
93 self.disks[dev].nr_requests = 0
94 self.disks[dev].completed_requests = 0
95 self.disks[dev].request_time = 0
96
eb9efdcb
JD
97 for iface in self.ifaces.keys():
98 self.ifaces[iface].recv_bytes = 0
99 self.ifaces[iface].recv_packets = 0
100 self.ifaces[iface].send_bytes = 0
101 self.ifaces[iface].send_packets = 0
102
103 def clear(self):
104 self.trace_start_ts = 0
105 self.trace_end_ts = 0
106 self.traces = traces
107 self.tids = {}
108 self.cpus = {}
109 self.syscalls = {}
110 self.disks = {}
111 self.ifaces = {}
112
fd893e53 113 def compute_stats(self):
65d937db 114 for cpu in self.cpus.keys():
a0da5181 115 current_cpu = self.cpus[cpu]
fd893e53 116 total_ns = self.end_ns - self.start_ns
a0da5181
JD
117 if current_cpu.start_task_ns != 0:
118 current_cpu.cpu_ns += self.end_ns - current_cpu.start_task_ns
119 cpu_total_ns = current_cpu.cpu_ns
120 current_cpu.cpu_pc = (cpu_total_ns * 100)/total_ns
121 if current_cpu.current_tid >= 0:
122 self.tids[current_cpu.current_tid].cpu_ns += \
123 self.end_ns - current_cpu.start_task_ns
65d937db 124
fd893e53 125 def run(self, args):
8e784ad6 126 """Process the trace"""
fd893e53
JD
127 self.current_sec = 0
128 self.start_ns = 0
129 self.end_ns = 0
1595fe2d 130
34a788b4 131 sched = Sched(self.cpus, self.tids)
1595fe2d 132 syscall = Syscalls(self.cpus, self.tids, self.syscalls)
4957863f 133 block_bio = BlockBio(self.cpus, self.disks)
eb9efdcb 134 net = Net(self.ifaces)
87ea2bb1 135 statedump = Statedump(self.tids)
b99fb31f 136
8e784ad6 137 for event in self.traces.events:
fd893e53
JD
138 if self.start_ns == 0:
139 self.start_ns = event.timestamp
140 if self.trace_start_ts == 0:
141 self.trace_start_ts = event.timestamp
142 self.end_ns = event.timestamp
fd893e53 143 self.check_refresh(args, event)
fd893e53 144 self.trace_end_ts = event.timestamp
8e784ad6
JD
145
146 if event.name == "sched_switch":
34a788b4 147 sched.switch(event)
b4376047 148 elif event.name == "sched_migrate_task":
34a788b4 149 sched.migrate_task(event)
da2b3096
JD
150 elif event.name == "sched_process_fork":
151 sched.process_fork(event)
152 elif event.name == "sched_process_exec":
153 sched.process_exec(event)
ffd315c0 154 elif event.name[0:4] == "sys_" and \
b9922d40
JD
155 (args.global_syscalls or args.tid_syscalls or
156 args.fds):
b99fb31f 157 syscall.entry(event)
ffd315c0 158 elif event.name == "exit_syscall" and \
b9922d40
JD
159 (args.global_syscalls or args.tid_syscalls or
160 args.fds):
b99fb31f 161 syscall.exit(event)
acf4f8f1
JD
162 elif event.name == "block_bio_complete" or \
163 event.name == "block_rq_complete":
4957863f
JD
164 block_bio.complete(event)
165 elif event.name == "block_bio_queue":
166 block_bio.queue(event)
eb9efdcb
JD
167 elif event.name == "netif_receive_skb":
168 net.recv(event)
169 elif event.name == "net_dev_xmit":
170 net.send(event)
87ea2bb1
JD
171 elif event.name == "lttng_statedump_process_state":
172 statedump.process_state(event)
173 elif event.name == "lttng_statedump_file_descriptor":
174 statedump.file_descriptor(event)
fd893e53 175 if args.refresh == 0:
a0da5181 176 # stats for the whole trace
fd893e53 177 self.compute_stats()
a0da5181 178 self.output(args, self.trace_start_ts, self.trace_end_ts, final=1)
4021d2e7 179 else:
a0da5181 180 # stats only for the last segment
fd893e53 181 self.compute_stats()
a0da5181 182 self.output(args, self.start_ns, self.trace_end_ts,
fd893e53 183 final=1)
d03b82af
JD
184
185if __name__ == "__main__":
fd893e53
JD
186 parser = argparse.ArgumentParser(description='CPU usage analysis')
187 parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
188 parser.add_argument('-r', '--refresh', type=int,
189 help='Refresh period in seconds', default=0)
1595fe2d
JD
190 parser.add_argument('--text', action="store_true",
191 help='Output in text (default)')
192 parser.add_argument('--json', action="store_true",
193 help='Output in JSON')
0790ad37
JD
194 parser.add_argument('--graphite', action="store_true",
195 help='Output to graphite')
1595fe2d
JD
196 parser.add_argument('--cpu', action="store_true",
197 help='Per-CPU stats (default)')
4957863f
JD
198 parser.add_argument('--disk', action="store_true",
199 help='Per-Disk stats (default)')
1595fe2d
JD
200 parser.add_argument('--tid', action="store_true",
201 help='Per-TID stats (default)')
eb9efdcb
JD
202 parser.add_argument('--net', action="store_true",
203 help='Per-interface network stats (default)')
1595fe2d
JD
204 parser.add_argument('--global-syscalls', action="store_true",
205 help='Global syscalls (default)')
206 parser.add_argument('--tid-syscalls', action="store_true",
207 help='Per-TID syscalls (default)')
b9922d40
JD
208 parser.add_argument('--fds', action="store_true",
209 help='Per-PID FD stats (default)')
1595fe2d
JD
210 parser.add_argument('--overall', action="store_true",
211 help='Overall CPU Usage (default)')
212 parser.add_argument('--info', action="store_true",
213 help='Trace info (default)')
214 parser.add_argument('--top', type=int, default=0,
215 help='Limit to top X TIDs')
216 parser.add_argument('--name', type=str, default=0,
217 help='Show results only for the list of processes')
fd893e53
JD
218 args = parser.parse_args()
219
0790ad37 220 if not args.json and not args.graphite:
fd893e53
JD
221 args.text = True
222
b9922d40 223 if args.tid_syscalls or args.fds:
ffd315c0 224 args.tid = True
1595fe2d 225 if not (args.cpu or args.tid or args.overall or args.info or \
eb9efdcb 226 args.global_syscalls or args.tid_syscalls or args.disk \
b9922d40 227 or args.net or args.fds):
fd893e53
JD
228 args.cpu = True
229 args.tid = True
230 args.overall = True
4957863f 231 args.disk = True
fd893e53 232 args.info = True
1595fe2d
JD
233 args.global_syscalls = True
234 args.tid_syscalls = True
eb9efdcb 235 args.net = True
b9922d40 236 args.fds = True
ffd315c0
JD
237 if args.name:
238 args.global_syscalls = False
6260255a
JD
239 args.display_proc_list = []
240 if args.name:
241 args.display_proc_list = args.name.split(",")
d03b82af 242
0790ad37
JD
243 while True:
244 if args.graphite:
eb9efdcb
JD
245 events="sched_switch,block_bio_complete,block_bio_queue," \
246 "netif_receive_skb,net_dev_xmit"
0790ad37 247 os.system("lttng create graphite -o graphite-live >/dev/null")
4957863f 248 os.system("lttng enable-event -k %s -s graphite >/dev/null" % events)
0790ad37
JD
249 os.system("lttng start graphite >/dev/null")
250 time.sleep(2)
251 os.system("lttng stop graphite >/dev/null")
252 os.system("lttng destroy graphite >/dev/null")
253 traces = TraceCollection()
254 handle = traces.add_trace(args.path, "ctf")
255 if handle is None:
256 sys.exit(1)
257
4957863f 258 c = Analyzes(traces)
0790ad37 259 c.run(args)
eb9efdcb 260 c.clear()
0790ad37
JD
261
262 traces.remove_trace(handle)
263
264 if not args.graphite:
265 break
This page took 0.03872 seconds and 5 git commands to generate.