Style: fix minor pep8 style issues
[deliverable/lttng-analyses.git] / lttnganalyses / cli / io.py
CommitLineData
4ed24f86
JD
1# The MIT License (MIT)
2#
a3fa57c0 3# Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
6cd52af3 4# 2015 - Antoine Busque <abusque@efficios.com>
cee855a2 5# 2015 - Philippe Proulx <pproulx@efficios.com>
4ed24f86
JD
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
0b250a71 25import collections
a9c9a2a6
JD
26import operator
27import statistics
b6d9132b 28import sys
0b250a71 29from . import mi
8400227b 30from . import termgraph
0b250a71 31from ..core import io
8400227b 32from ..common import format_utils
0b250a71
AB
33from .command import Command
34from ..linuxautomaton import common
a9c9a2a6
JD
35
36
a0acc08c
PP
37_UsageTables = collections.namedtuple('_UsageTables', [
38 'per_proc_read',
39 'per_proc_write',
40 'per_file_read',
41 'per_file_write',
42 'per_proc_block_read',
43 'per_proc_block_write',
44 'per_disk_sector',
45 'per_disk_request',
46 'per_disk_rtps',
47 'per_netif_recv',
48 'per_netif_send',
49])
50
51
087e5d00 52class IoAnalysisCommand(Command):
a9c9a2a6 53 _DESC = """The I/O command."""
b6d9132b 54 _ANALYSIS_CLASS = io.IoAnalysis
a0acc08c
PP
55 _MI_TITLE = 'I/O analysis'
56 _MI_DESCRIPTION = 'System call/disk latency statistics, system call ' + \
57 'latency distribution, system call top latencies, ' + \
58 'I/O usage top, and I/O operations log'
59 _MI_TAGS = [
60 mi.Tags.IO,
61 mi.Tags.SYSCALL,
62 mi.Tags.STATS,
63 mi.Tags.FREQ,
64 mi.Tags.LOG,
65 mi.Tags.TOP,
66 ]
67 _MI_TABLE_CLASS_SYSCALL_LATENCY_STATS = 'syscall-latency-stats'
68 _MI_TABLE_CLASS_PART_LATENCY_STATS = 'disk-latency-stats'
69 _MI_TABLE_CLASS_FREQ = 'freq'
70 _MI_TABLE_CLASS_TOP_SYSCALL = 'top-syscall'
71 _MI_TABLE_CLASS_LOG = 'log'
72 _MI_TABLE_CLASS_PER_PROCESS_TOP = 'per-process-top'
73 _MI_TABLE_CLASS_PER_FILE_TOP = 'per-file-top'
74 _MI_TABLE_CLASS_PER_PROCESS_TOP_BLOCK = 'per-process-top-block'
75 _MI_TABLE_CLASS_PER_DISK_TOP_SECTOR = 'per-disk-top-sector'
76 _MI_TABLE_CLASS_PER_DISK_TOP_REQUEST = 'per-disk-top-request'
77 _MI_TABLE_CLASS_PER_DISK_TOP_RTPS = 'per-disk-top-rps'
78 _MI_TABLE_CLASS_PER_NETIF_TOP = 'per-netif-top'
79 _MI_TABLE_CLASSES = [
80 (
81 _MI_TABLE_CLASS_SYSCALL_LATENCY_STATS,
82 'System call latency statistics', [
83 ('obj', 'System call category', mi.String),
84 ('count', 'Call count', mi.Integer, 'calls'),
85 ('min_latency', 'Minimum call latency', mi.Duration),
86 ('avg_latency', 'Average call latency', mi.Duration),
87 ('max_latency', 'Maximum call latency', mi.Duration),
650e7f57
AB
88 ('stdev_latency', 'System call latency standard deviation',
89 mi.Duration),
a0acc08c
PP
90 ]
91 ),
92 (
93 _MI_TABLE_CLASS_PART_LATENCY_STATS,
94 'Partition latency statistics', [
95 ('obj', 'Partition', mi.Disk),
96 ('count', 'Access count', mi.Integer, 'accesses'),
97 ('min_latency', 'Minimum access latency', mi.Duration),
98 ('avg_latency', 'Average access latency', mi.Duration),
99 ('max_latency', 'Maximum access latency', mi.Duration),
650e7f57
AB
100 ('stdev_latency', 'System access latency standard deviation',
101 mi.Duration),
a0acc08c
PP
102 ]
103 ),
104 (
105 _MI_TABLE_CLASS_FREQ,
106 'I/O request latency distribution', [
107 ('latency_lower', 'Latency (lower bound)', mi.Duration),
108 ('latency_upper', 'Latency (upper bound)', mi.Duration),
109 ('count', 'Request count', mi.Integer, 'requests'),
110 ]
111 ),
112 (
113 _MI_TABLE_CLASS_TOP_SYSCALL,
114 'Top system call latencies', [
115 ('time_range', 'Call time range', mi.TimeRange),
116 ('out_of_range', 'System call out of range?', mi.Boolean),
117 ('duration', 'Call duration', mi.Duration),
118 ('syscall', 'System call', mi.Syscall),
119 ('size', 'Read/write size', mi.Size),
120 ('process', 'Process', mi.Process),
121 ('path', 'File path', mi.Path),
122 ('fd', 'File descriptor', mi.Fd),
123 ]
124 ),
125 (
126 _MI_TABLE_CLASS_LOG,
127 'I/O operations log', [
128 ('time_range', 'Call time range', mi.TimeRange),
129 ('out_of_range', 'System call out of range?', mi.Boolean),
130 ('duration', 'Call duration', mi.Duration),
131 ('syscall', 'System call', mi.Syscall),
132 ('size', 'Read/write size', mi.Size),
133 ('process', 'Process', mi.Process),
134 ('path', 'File path', mi.Path),
135 ('fd', 'File descriptor', mi.Fd),
136 ]
137 ),
138 (
139 _MI_TABLE_CLASS_PER_PROCESS_TOP,
140 'Per-process top I/O operations', [
141 ('process', 'Process', mi.Process),
142 ('size', 'Total operations size', mi.Size),
143 ('disk_size', 'Disk operations size', mi.Size),
144 ('net_size', 'Network operations size', mi.Size),
145 ('unknown_size', 'Unknown operations size', mi.Size),
146 ]
147 ),
148 (
149 _MI_TABLE_CLASS_PER_FILE_TOP,
150 'Per-file top I/O operations', [
151 ('path', 'File path/info', mi.Path),
152 ('size', 'Operations size', mi.Size),
153 ('fd_owners', 'File descriptor owners', mi.String),
154 ]
155 ),
156 (
157 _MI_TABLE_CLASS_PER_PROCESS_TOP_BLOCK,
158 'Per-process top block I/O operations', [
159 ('process', 'Process', mi.Process),
160 ('size', 'Operations size', mi.Size),
161 ]
162 ),
163 (
164 _MI_TABLE_CLASS_PER_DISK_TOP_SECTOR,
165 'Per-disk top sector I/O operations', [
166 ('disk', 'Disk', mi.Disk),
167 ('count', 'Sector count', mi.Integer, 'sectors'),
168 ]
169 ),
170 (
171 _MI_TABLE_CLASS_PER_DISK_TOP_REQUEST,
172 'Per-disk top I/O requests', [
173 ('disk', 'Disk', mi.Disk),
174 ('count', 'Request count', mi.Integer, 'I/O requests'),
175 ]
176 ),
177 (
178 _MI_TABLE_CLASS_PER_DISK_TOP_RTPS,
179 'Per-disk top I/O request time/sector', [
180 ('disk', 'Disk', mi.Disk),
181 ('rtps', 'Request time/sector', mi.Duration),
182 ]
183 ),
184 (
185 _MI_TABLE_CLASS_PER_NETIF_TOP,
186 'Per-network interface top I/O operations', [
187 ('netif', 'Network interface', mi.NetIf),
188 ('size', 'Operations size', mi.Size),
189 ]
190 ),
191 ]
ef49c8de
AB
192 _LATENCY_STATS_FORMAT = '{:<14} {:>14} {:>14} {:>14} {:>14} {:>14}'
193 _SECTION_SEPARATOR_STRING = '-' * 89
194
a0acc08c
PP
195 def _analysis_tick(self, begin_ns, end_ns):
196 syscall_latency_stats_table = None
197 disk_latency_stats_table = None
198 freq_tables = None
199 top_tables = None
200 log_table = None
201 usage_tables = None
202
203 if self._args.stats:
204 syscall_latency_stats_table, disk_latency_stats_table = \
205 self._get_latency_stats_result_tables(begin_ns, end_ns)
206
207 if self._args.freq:
208 freq_tables = self._get_freq_result_tables(begin_ns, end_ns)
209
210 if self._args.usage:
211 usage_tables = self._get_usage_result_tables(begin_ns, end_ns)
212
213 if self._args.top:
214 top_tables = self._get_top_result_tables(begin_ns, end_ns)
215
216 if self._args.log:
217 log_table = self._get_log_result_table(begin_ns, end_ns)
218
219 if self._mi_mode:
220 self._mi_append_result_tables([
221 log_table,
222 syscall_latency_stats_table,
223 disk_latency_stats_table,
224 ])
225 self._mi_append_result_tables(top_tables)
226 self._mi_append_result_tables(usage_tables)
227 self._mi_append_result_tables(freq_tables)
228 else:
229 self._print_date(begin_ns, end_ns)
230
231 if self._args.usage:
232 self._print_usage(usage_tables)
233
234 if self._args.stats:
235 self._print_latency_stats(syscall_latency_stats_table,
236 disk_latency_stats_table)
237
238 if self._args.top:
239 self._print_top(top_tables)
240
241 if self._args.freq:
242 self._print_freq(freq_tables)
243
244 if self._args.log:
245 self._print_log(log_table)
246
247 def _create_summary_result_tables(self):
248 # TODO: create a summary table here
249 self._mi_clear_result_tables()
250
882fcd19 251 # Filter predicates
882fcd19
AB
252 def _filter_size(self, size):
253 if size is None:
254 return True
b6d9132b 255 if self._args.maxsize is not None and size > self._args.maxsize:
882fcd19 256 return False
b6d9132b 257 if self._args.minsize is not None and size < self._args.minsize:
882fcd19
AB
258 return False
259 return True
260
261 def _filter_latency(self, duration):
b6d9132b 262 if self._args.max is not None and duration > self._args.max:
882fcd19 263 return False
b6d9132b 264 if self._args.min is not None and duration < self._args.min:
882fcd19
AB
265 return False
266 return True
267
ef49c8de 268 def _filter_time_range(self, begin, end):
b6d9132b
AB
269 # Note: we only want to return False only when a request has
270 # ended and is completely outside the timerange (i.e. begun
271 # after the end of the time range).
272 return not (self._args.begin and self._args.end and end and
273 begin > self._args.end)
ef49c8de
AB
274
275 def _filter_io_request(self, io_rq):
43b66dd6 276 return self._filter_size(io_rq.size) and \
ef49c8de
AB
277 self._filter_latency(io_rq.duration) and \
278 self._filter_time_range(io_rq.begin_ts, io_rq.end_ts)
279
7e73fe34 280 def _is_io_rq_out_of_range(self, io_rq):
b6d9132b
AB
281 return self._args.begin and io_rq.begin_ts < self._args.begin or \
282 self._args.end and io_rq.end_ts > self._args.end
7e73fe34 283
a0acc08c 284 def _append_per_proc_read_usage_row(self, proc_stats, result_table):
a0acc08c
PP
285 result_table.append_row(
286 process=mi.Process(proc_stats.comm, pid=proc_stats.pid,
287 tid=proc_stats.tid),
288 size=mi.Size(proc_stats.total_read),
f67842f8
AB
289 disk_size=mi.Size(proc_stats.disk_io.read),
290 net_size=mi.Size(proc_stats.net_io.read),
291 unknown_size=mi.Size(proc_stats.unk_io.read),
a0acc08c 292 )
88cfa546 293
a0acc08c 294 return True
88cfa546 295
a0acc08c 296 def _append_per_proc_write_usage_row(self, proc_stats, result_table):
a0acc08c
PP
297 result_table.append_row(
298 process=mi.Process(proc_stats.comm, pid=proc_stats.pid,
299 tid=proc_stats.tid),
300 size=mi.Size(proc_stats.total_write),
f67842f8
AB
301 disk_size=mi.Size(proc_stats.disk_io.write),
302 net_size=mi.Size(proc_stats.net_io.write),
303 unknown_size=mi.Size(proc_stats.unk_io.write),
a0acc08c 304 )
91765fd2 305
a0acc08c 306 return True
91765fd2 307
a0acc08c 308 def _append_per_proc_block_read_usage_row(self, proc_stats, result_table):
f67842f8 309 if proc_stats.block_io.read == 0:
a0acc08c 310 return False
91765fd2 311
a0acc08c
PP
312 if proc_stats.comm:
313 proc_name = proc_stats.comm
91765fd2 314 else:
a0acc08c 315 proc_name = None
91765fd2 316
a0acc08c
PP
317 result_table.append_row(
318 process=mi.Process(proc_name, pid=proc_stats.pid,
319 tid=proc_stats.tid),
f67842f8 320 size=mi.Size(proc_stats.block_io.read),
a0acc08c 321 )
91765fd2 322
a0acc08c 323 return True
91765fd2 324
a0acc08c 325 def _append_per_proc_block_write_usage_row(self, proc_stats, result_table):
f67842f8 326 if proc_stats.block_io.write == 0:
a0acc08c 327 return False
91765fd2 328
a0acc08c
PP
329 if proc_stats.comm:
330 proc_name = proc_stats.comm
91765fd2 331 else:
a0acc08c 332 proc_name = None
91765fd2 333
a0acc08c
PP
334 result_table.append_row(
335 process=mi.Process(proc_name, pid=proc_stats.pid,
336 tid=proc_stats.tid),
f67842f8 337 size=mi.Size(proc_stats.block_io.write),
a0acc08c 338 )
91765fd2 339
a0acc08c 340 return True
91765fd2 341
a0acc08c
PP
342 def _append_disk_sector_usage_row(self, disk_stats, result_table):
343 if disk_stats.total_rq_sectors == 0:
91765fd2
AB
344 return None
345
a0acc08c
PP
346 result_table.append_row(
347 disk=mi.Disk(disk_stats.disk_name),
348 count=mi.Integer(disk_stats.total_rq_sectors),
349 )
91765fd2 350
a0acc08c 351 return True
91765fd2 352
a0acc08c
PP
353 def _append_disk_request_usage_row(self, disk_stats, result_table):
354 if disk_stats.rq_count == 0:
355 return False
91765fd2 356
a0acc08c
PP
357 result_table.append_row(
358 disk=mi.Disk(disk_stats.disk_name),
359 count=mi.Integer(disk_stats.rq_count),
360 )
91765fd2 361
a0acc08c 362 return True
91765fd2 363
a0acc08c
PP
364 def _append_disk_rtps_usage_row(self, disk_stats, result_table):
365 if disk_stats.rq_count == 0:
366 return False
91765fd2 367
a0acc08c
PP
368 avg_latency = (disk_stats.total_rq_duration / disk_stats.rq_count)
369 result_table.append_row(
370 disk=mi.Disk(disk_stats.disk_name),
371 rtps=mi.Duration(avg_latency),
372 )
91765fd2 373
a0acc08c 374 return True
91765fd2 375
a0acc08c
PP
376 def _append_netif_recv_usage_row(self, netif_stats, result_table):
377 result_table.append_row(
378 netif=mi.NetIf(netif_stats.name),
379 size=mi.Size(netif_stats.recv_bytes)
380 )
91765fd2 381
a0acc08c 382 return True
91765fd2 383
a0acc08c
PP
384 def _append_netif_send_usage_row(self, netif_stats, result_table):
385 result_table.append_row(
386 netif=mi.NetIf(netif_stats.name),
387 size=mi.Size(netif_stats.sent_bytes)
388 )
91765fd2 389
a0acc08c 390 return True
e0e5f1fd 391
a0acc08c 392 def _get_file_stats_fd_owners_str(self, file_stats):
e0e5f1fd 393 fd_by_pid_str = ''
a0acc08c 394
e0e5f1fd
AB
395 for pid, fd in file_stats.fd_by_pid.items():
396 comm = self._analysis.tids[pid].comm
397 fd_by_pid_str += 'fd %d in %s (%s) ' % (fd, comm, pid)
398
a0acc08c
PP
399 return fd_by_pid_str
400
401 def _append_file_read_usage_row(self, file_stats, result_table):
f67842f8 402 if file_stats.io.read == 0:
a0acc08c 403 return False
e0e5f1fd 404
a0acc08c
PP
405 fd_owners = self._get_file_stats_fd_owners_str(file_stats)
406 result_table.append_row(
407 path=mi.Path(file_stats.filename),
f67842f8 408 size=mi.Size(file_stats.io.read),
a0acc08c
PP
409 fd_owners=mi.String(fd_owners),
410 )
411
412 return True
e0e5f1fd 413
a0acc08c 414 def _append_file_write_usage_row(self, file_stats, result_table):
f67842f8 415 if file_stats.io.write == 0:
a0acc08c 416 return False
e0e5f1fd 417
a0acc08c
PP
418 fd_owners = self._get_file_stats_fd_owners_str(file_stats)
419 result_table.append_row(
420 path=mi.Path(file_stats.filename),
f67842f8 421 size=mi.Size(file_stats.io.write),
a0acc08c
PP
422 fd_owners=mi.String(fd_owners),
423 )
e0e5f1fd 424
a0acc08c 425 return True
e0e5f1fd 426
650e7f57
AB
427 def _fill_usage_result_table(self, input_list, append_row_cb,
428 result_table):
a0acc08c
PP
429 count = 0
430 limit = self._args.limit
e0e5f1fd 431
a0acc08c
PP
432 for elem in input_list:
433 if append_row_cb(elem, result_table):
434 count += 1
435
436 if limit is not None and count >= limit:
437 break
438
439 def _fill_per_process_read_usage_result_table(self, result_table):
91765fd2
AB
440 input_list = sorted(self._analysis.tids.values(),
441 key=operator.attrgetter('total_read'),
442 reverse=True)
a0acc08c
PP
443 self._fill_usage_result_table(input_list,
444 self._append_per_proc_read_usage_row,
445 result_table)
91765fd2 446
a0acc08c 447 def _fill_per_process_write_usage_result_table(self, result_table):
91765fd2
AB
448 input_list = sorted(self._analysis.tids.values(),
449 key=operator.attrgetter('total_write'),
450 reverse=True)
a0acc08c
PP
451 self._fill_usage_result_table(input_list,
452 self._append_per_proc_write_usage_row,
453 result_table)
91765fd2 454
a0acc08c 455 def _fill_per_process_block_read_usage_result_table(self, result_table):
91765fd2 456 input_list = sorted(self._analysis.tids.values(),
f67842f8 457 key=operator.attrgetter('block_io.read'),
91765fd2 458 reverse=True)
650e7f57
AB
459 self._fill_usage_result_table(
460 input_list, self._append_per_proc_block_read_usage_row,
461 result_table)
91765fd2 462
a0acc08c 463 def _fill_per_process_block_write_usage_result_table(self, result_table):
91765fd2 464 input_list = sorted(self._analysis.tids.values(),
f67842f8 465 key=operator.attrgetter('block_io.write'),
91765fd2 466 reverse=True)
650e7f57
AB
467 self._fill_usage_result_table(
468 input_list, self._append_per_proc_block_write_usage_row,
469 result_table)
91765fd2 470
a0acc08c 471 def _fill_disk_sector_usage_result_table(self, result_table):
91765fd2
AB
472 input_list = sorted(self._analysis.disks.values(),
473 key=operator.attrgetter('total_rq_sectors'),
474 reverse=True)
a0acc08c
PP
475 self._fill_usage_result_table(input_list,
476 self._append_disk_sector_usage_row,
477 result_table)
91765fd2 478
a0acc08c 479 def _fill_disk_request_usage_result_table(self, result_table):
91765fd2
AB
480 input_list = sorted(self._analysis.disks.values(),
481 key=operator.attrgetter('rq_count'),
482 reverse=True)
a0acc08c
PP
483 self._fill_usage_result_table(input_list,
484 self._append_disk_request_usage_row,
485 result_table)
91765fd2 486
a0acc08c 487 def _fill_disk_rtps_usage_result_table(self, result_table):
91765fd2 488 input_list = self._analysis.disks.values()
a0acc08c
PP
489 self._fill_usage_result_table(input_list,
490 self._append_disk_rtps_usage_row,
491 result_table)
91765fd2 492
a0acc08c 493 def _fill_netif_recv_usage_result_table(self, result_table):
91765fd2
AB
494 input_list = sorted(self._analysis.ifaces.values(),
495 key=operator.attrgetter('recv_bytes'),
496 reverse=True)
a0acc08c
PP
497 self._fill_usage_result_table(input_list,
498 self._append_netif_recv_usage_row,
499 result_table)
91765fd2 500
a0acc08c 501 def _fill_netif_send_usage_result_table(self, result_table):
91765fd2
AB
502 input_list = sorted(self._analysis.ifaces.values(),
503 key=operator.attrgetter('sent_bytes'),
504 reverse=True)
a0acc08c
PP
505 self._fill_usage_result_table(input_list,
506 self._append_netif_send_usage_row,
507 result_table)
91765fd2 508
a0acc08c 509 def _fill_file_read_usage_result_table(self, files, result_table):
e0e5f1fd 510 input_list = sorted(files.values(),
f67842f8 511 key=lambda file_stats: file_stats.io.read,
e0e5f1fd 512 reverse=True)
a0acc08c
PP
513 self._fill_usage_result_table(input_list,
514 self._append_file_read_usage_row,
515 result_table)
a9c9a2a6 516
a0acc08c 517 def _fill_file_write_usage_result_table(self, files, result_table):
e0e5f1fd 518 input_list = sorted(files.values(),
f67842f8 519 key=lambda file_stats: file_stats.io.write,
e0e5f1fd 520 reverse=True)
a0acc08c
PP
521 self._fill_usage_result_table(input_list,
522 self._append_file_write_usage_row,
523 result_table)
a9c9a2a6 524
a0acc08c 525 def _fill_file_usage_result_tables(self, read_table, write_table):
b9f05f8d 526 files = self._analysis.get_files_stats()
a0acc08c
PP
527 self._fill_file_read_usage_result_table(files, read_table)
528 self._fill_file_write_usage_result_table(files, write_table)
529
530 def _get_usage_result_tables(self, begin, end):
531 # create result tables
650e7f57
AB
532 per_proc_read_table = self._mi_create_result_table(
533 self._MI_TABLE_CLASS_PER_PROCESS_TOP, begin, end, 'read')
534 per_proc_write_table = self._mi_create_result_table(
535 self._MI_TABLE_CLASS_PER_PROCESS_TOP, begin, end, 'written')
536 per_file_read_table = self._mi_create_result_table(
537 self._MI_TABLE_CLASS_PER_FILE_TOP, begin, end, 'read')
538 per_file_write_table = self._mi_create_result_table(
539 self._MI_TABLE_CLASS_PER_FILE_TOP, begin, end, 'written')
540 per_proc_block_read_table = self._mi_create_result_table(
541 self._MI_TABLE_CLASS_PER_PROCESS_TOP_BLOCK, begin, end, 'read')
542 per_proc_block_write_table = self._mi_create_result_table(
543 self._MI_TABLE_CLASS_PER_PROCESS_TOP_BLOCK, begin, end, 'written')
544 per_disk_sector_table = self._mi_create_result_table(
545 self._MI_TABLE_CLASS_PER_DISK_TOP_SECTOR, begin, end)
546 per_disk_request_table = self._mi_create_result_table(
547 self._MI_TABLE_CLASS_PER_DISK_TOP_REQUEST, begin, end)
548 per_disk_rtps_table = self._mi_create_result_table(
549 self._MI_TABLE_CLASS_PER_DISK_TOP_RTPS, begin, end)
550 per_netif_recv_table = self._mi_create_result_table(
551 self._MI_TABLE_CLASS_PER_NETIF_TOP, begin, end, 'received')
552 per_netif_send_table = self._mi_create_result_table(
553 self._MI_TABLE_CLASS_PER_NETIF_TOP, begin, end, 'sent')
a0acc08c
PP
554
555 # fill result tables
556 self._fill_per_process_read_usage_result_table(per_proc_read_table)
557 self._fill_per_process_write_usage_result_table(per_proc_write_table)
558 self._fill_file_usage_result_tables(per_file_read_table,
559 per_file_write_table)
650e7f57
AB
560 self._fill_per_process_block_read_usage_result_table(
561 per_proc_block_read_table)
92b29247 562 self._fill_per_process_block_write_usage_result_table(
650e7f57 563 per_proc_block_write_table)
a0acc08c
PP
564 self._fill_disk_sector_usage_result_table(per_disk_sector_table)
565 self._fill_disk_request_usage_result_table(per_disk_request_table)
566 self._fill_disk_rtps_usage_result_table(per_disk_rtps_table)
567 self._fill_netif_recv_usage_result_table(per_netif_recv_table)
568 self._fill_netif_send_usage_result_table(per_netif_send_table)
569
570 return _UsageTables(
571 per_proc_read=per_proc_read_table,
572 per_proc_write=per_proc_write_table,
573 per_file_read=per_file_read_table,
574 per_file_write=per_file_write_table,
575 per_proc_block_read=per_proc_block_read_table,
576 per_proc_block_write=per_proc_block_write_table,
577 per_disk_sector=per_disk_sector_table,
578 per_disk_request=per_disk_request_table,
579 per_disk_rtps=per_disk_rtps_table,
580 per_netif_recv=per_netif_recv_table,
581 per_netif_send=per_netif_send_table,
582 )
583
8400227b
AB
584 def _print_per_proc_io(self, result_table, title):
585 header_format = '{:<25} {:<10} {:<10} {:<10}'
586 label_header = header_format.format(
587 'Process', 'Disk', 'Net', 'Unknown'
588 )
a0acc08c 589
8400227b
AB
590 def get_label(row):
591 label_format = '{:<25} {:>10} {:>10} {:>10}'
592 if row.process.pid is None:
593 pid_str = 'unknown (tid=%d)' % (row.process.tid)
594 else:
595 pid_str = str(row.process.pid)
a0acc08c 596
8400227b
AB
597 label = label_format.format(
598 '%s (%s)' % (row.process.name, pid_str),
599 format_utils.format_size(row.disk_size.value),
600 format_utils.format_size(row.net_size.value),
601 format_utils.format_size(row.unknown_size.value)
602 )
a0acc08c 603
8400227b 604 return label
a0acc08c 605
8400227b
AB
606 graph = termgraph.BarGraph(
607 title='Per-process I/O ' + title,
608 label_header=label_header,
609 get_value=lambda row: row.size.value,
610 get_value_str=format_utils.format_size,
611 get_label=get_label,
612 data=result_table.rows
613 )
a0acc08c 614
8400227b 615 graph.print_graph()
a0acc08c 616
8400227b
AB
617 def _print_per_proc_block_io(self, result_table, title):
618 def get_label(row):
619 proc_name = row.process.name
a0acc08c 620
8400227b
AB
621 if not proc_name:
622 proc_name = 'unknown'
a0acc08c 623
8400227b
AB
624 if row.process.pid is None:
625 pid_str = 'unknown (tid={})'.format(row.process.tid)
626 else:
627 pid_str = str(row.process.pid)
a0acc08c 628
8400227b 629 return '{} (pid={})'.format(proc_name, pid_str)
a0acc08c 630
8400227b
AB
631 graph = termgraph.BarGraph(
632 title='Block I/O ' + title,
633 label_header='Process',
634 get_value=lambda row: row.size.value,
635 get_value_str=format_utils.format_size,
636 get_label=get_label,
637 data=result_table.rows
638 )
a0acc08c 639
8400227b 640 graph.print_graph()
a0acc08c 641
8400227b
AB
642 def _print_per_disk_sector(self, result_table):
643 graph = termgraph.BarGraph(
644 title='Disk Requests Sector Count',
645 label_header='Disk',
646 unit='sectors',
647 get_value=lambda row: row.count.value,
648 get_label=lambda row: row.disk.name,
649 data=result_table.rows
650 )
a0acc08c 651
8400227b 652 graph.print_graph()
a0acc08c 653
8400227b
AB
654 def _print_per_disk_request(self, result_table):
655 graph = termgraph.BarGraph(
656 title='Disk Request Count',
657 label_header='Disk',
658 unit='requests',
659 get_value=lambda row: row.count.value,
660 get_label=lambda row: row.disk.name,
661 data=result_table.rows
662 )
a0acc08c 663
8400227b 664 graph.print_graph()
a0acc08c 665
8400227b
AB
666 def _print_per_disk_rtps(self, result_table):
667 graph = termgraph.BarGraph(
668 title='Disk Request Average Latency',
669 label_header='Disk',
670 unit='ms',
671 get_value=lambda row: row.rtps.value / common.NSEC_PER_MSEC,
672 get_label=lambda row: row.disk.name,
673 data=result_table.rows
674 )
a0acc08c 675
8400227b 676 graph.print_graph()
a0acc08c 677
8400227b
AB
678 def _print_per_netif_io(self, result_table, title):
679 graph = termgraph.BarGraph(
680 title='Network ' + title + ' Bytes',
681 label_header='Interface',
682 get_value=lambda row: row.size.value,
683 get_value_str=format_utils.format_size,
684 get_label=lambda row: row.netif.name,
685 data=result_table.rows
686 )
a0acc08c 687
8400227b
AB
688 graph.print_graph()
689
690 def _print_per_file_io(self, result_table, title):
691 # FIXME add option to show FD owners
692 # FIXME why are read and write values the same?
693 graph = termgraph.BarGraph(
694 title='Per-file I/O ' + title,
695 label_header='Path',
696 get_value=lambda row: row.size.value,
697 get_value_str=format_utils.format_size,
698 get_label=lambda row: row.path.path,
699 data=result_table.rows
700 )
a0acc08c 701
8400227b 702 graph.print_graph()
a0acc08c
PP
703
704 def _print_usage(self, usage_tables):
8400227b
AB
705 self._print_per_proc_io(usage_tables.per_proc_read, 'Read')
706 self._print_per_proc_io(usage_tables.per_proc_write, 'Write')
707 self._print_per_file_io(usage_tables.per_file_read, 'Read')
708 self._print_per_file_io(usage_tables.per_file_write, 'Write')
709 self._print_per_proc_block_io(usage_tables.per_proc_block_read, 'Read')
710 self._print_per_proc_block_io(
711 usage_tables.per_proc_block_write, 'Write'
712 )
a0acc08c
PP
713 self._print_per_disk_sector(usage_tables.per_disk_sector)
714 self._print_per_disk_request(usage_tables.per_disk_request)
715 self._print_per_disk_rtps(usage_tables.per_disk_rtps)
8400227b
AB
716 self._print_per_netif_io(usage_tables.per_netif_recv, 'Received')
717 self._print_per_netif_io(usage_tables.per_netif_send, 'Sent')
a0acc08c
PP
718
719 def _fill_freq_result_table(self, duration_list, result_table):
9ac03ff5
AB
720 if not duration_list:
721 return
722
723 # The number of bins for the histogram
b6d9132b 724 resolution = self._args.freq_resolution
9ac03ff5
AB
725
726 min_duration = min(duration_list)
727 max_duration = max(duration_list)
728 # ns to µs
729 min_duration /= 1000
730 max_duration /= 1000
731
732 step = (max_duration - min_duration) / resolution
a0acc08c 733
a9c9a2a6
JD
734 if step == 0:
735 return
9ac03ff5 736
a9c9a2a6
JD
737 buckets = []
738 values = []
a0acc08c 739
9ac03ff5 740 for i in range(resolution):
a9c9a2a6
JD
741 buckets.append(i * step)
742 values.append(0)
a0acc08c 743
9ac03ff5
AB
744 for duration in duration_list:
745 duration /= 1000
746 index = min(int((duration - min_duration) / step), resolution - 1)
747 values[index] += 1
748
9ac03ff5 749 for index, value in enumerate(values):
a0acc08c
PP
750 result_table.append_row(
751 latency_lower=mi.Duration.from_us(index * step + min_duration),
650e7f57
AB
752 latency_upper=mi.Duration.from_us((index + 1) * step +
753 min_duration),
a0acc08c
PP
754 count=mi.Integer(value),
755 )
756
757 def _get_disk_freq_result_tables(self, begin, end):
758 result_tables = []
759
760 for disk in self._analysis.disks.values():
761 rq_durations = [rq.duration for rq in disk.rq_list if
762 self._filter_io_request(rq)]
763 subtitle = 'disk: {}'.format(disk.disk_name)
764 result_table = \
765 self._mi_create_result_table(self._MI_TABLE_CLASS_FREQ,
766 begin, end, subtitle)
767 self._fill_freq_result_table(rq_durations, result_table)
768 result_tables.append(result_table)
769
770 return result_tables
771
772 def _get_syscall_freq_result_tables(self, begin, end):
773 open_table = \
774 self._mi_create_result_table(self._MI_TABLE_CLASS_FREQ,
775 begin, end, 'open')
776 read_table = \
777 self._mi_create_result_table(self._MI_TABLE_CLASS_FREQ,
778 begin, end, 'read')
779 write_table = \
780 self._mi_create_result_table(self._MI_TABLE_CLASS_FREQ,
781 begin, end, 'write')
782 sync_table = \
783 self._mi_create_result_table(self._MI_TABLE_CLASS_FREQ,
784 begin, end, 'sync')
785 self._fill_freq_result_table([io_rq.duration for io_rq in
786 self._analysis.open_io_requests if
787 self._filter_io_request(io_rq)],
650e7f57 788 open_table)
a0acc08c
PP
789 self._fill_freq_result_table([io_rq.duration for io_rq in
790 self._analysis.read_io_requests if
791 self._filter_io_request(io_rq)],
650e7f57 792 read_table)
a0acc08c
PP
793 self._fill_freq_result_table([io_rq.duration for io_rq in
794 self._analysis.write_io_requests if
795 self._filter_io_request(io_rq)],
650e7f57 796 write_table)
a0acc08c
PP
797 self._fill_freq_result_table([io_rq.duration for io_rq in
798 self._analysis.sync_io_requests if
799 self._filter_io_request(io_rq)],
650e7f57 800 sync_table)
a0acc08c
PP
801
802 return [open_table, read_table, write_table, sync_table]
803
804 def _get_freq_result_tables(self, begin, end):
805 syscall_tables = self._get_syscall_freq_result_tables(begin, end)
806 disk_tables = self._get_disk_freq_result_tables(begin, end)
807
808 return syscall_tables + disk_tables
809
810 def _print_one_freq(self, result_table):
74fd1623
AB
811 graph = termgraph.FreqGraph(
812 data=result_table.rows,
813 get_value=lambda row: row.count.value,
814 get_lower_bound=lambda row: row.latency_lower.to_us(),
815 title='{} {}'.format(result_table.title, result_table.subtitle),
816 unit='µs'
9ac03ff5
AB
817 )
818
74fd1623 819 graph.print_graph()
9ac03ff5 820
a0acc08c
PP
821 def _print_freq(self, freq_tables):
822 for freq_table in freq_tables:
823 self._print_one_freq(freq_table)
7e73fe34 824
a0acc08c 825 def _append_log_row(self, io_rq, result_table):
7e73fe34 826 if io_rq.size is None:
a0acc08c 827 size = mi.Empty()
7e73fe34 828 else:
a0acc08c 829 size = mi.Size(io_rq.size)
7e73fe34
AB
830
831 tid = io_rq.tid
832 proc_stats = self._analysis.tids[tid]
a0acc08c 833 proc_name = proc_stats.comm
7e73fe34
AB
834
835 # TODO: handle fd_in/fd_out for RW type operations
836 if io_rq.fd is None:
a0acc08c
PP
837 path = mi.Empty()
838 fd = mi.Empty()
7e73fe34 839 else:
a0acc08c 840 fd = mi.Fd(io_rq.fd)
7e73fe34 841 parent_proc = proc_stats
a0acc08c 842
7e73fe34
AB
843 if parent_proc.pid is not None:
844 parent_proc = self._analysis.tids[parent_proc.pid]
845
a0acc08c
PP
846 fd_stats = parent_proc.get_fd(io_rq.fd, io_rq.end_ts)
847
7e73fe34 848 if fd_stats is not None:
a0acc08c 849 path = mi.Path(fd_stats.filename)
7e73fe34 850 else:
a0acc08c
PP
851 path = mi.Unknown()
852
853 result_table.append_row(
854 time_range=mi.TimeRange(io_rq.begin_ts, io_rq.end_ts),
855 out_of_range=mi.Boolean(self._is_io_rq_out_of_range(io_rq)),
856 duration=mi.Duration(io_rq.duration),
857 syscall=mi.Syscall(io_rq.syscall_name),
858 size=size,
859 process=mi.Process(proc_name, tid=tid),
860 path=path,
861 fd=fd,
862 )
863
864 def _fill_log_result_table(self, rq_list, sort_key, is_top, result_table):
865 if not rq_list:
866 return
867
868 count = 0
7e73fe34 869
a0acc08c
PP
870 for io_rq in sorted(rq_list, key=operator.attrgetter(sort_key),
871 reverse=is_top):
872 if is_top and count > self._args.limit:
873 break
874
875 self._append_log_row(io_rq, result_table)
876 count += 1
877
878 def _fill_log_result_table_from_io_requests(self, io_requests, sort_key,
879 is_top, result_table):
880 io_requests = [io_rq for io_rq in io_requests if
881 self._filter_io_request(io_rq)]
650e7f57
AB
882 self._fill_log_result_table(io_requests, sort_key, is_top,
883 result_table)
a0acc08c
PP
884
885 def _get_top_result_tables(self, begin, end):
886 open_table = \
887 self._mi_create_result_table(self._MI_TABLE_CLASS_TOP_SYSCALL,
888 begin, end, 'open')
889 read_table = \
890 self._mi_create_result_table(self._MI_TABLE_CLASS_TOP_SYSCALL,
891 begin, end, 'read')
892 write_table = \
893 self._mi_create_result_table(self._MI_TABLE_CLASS_TOP_SYSCALL,
894 begin, end, 'write')
895 sync_table = \
896 self._mi_create_result_table(self._MI_TABLE_CLASS_TOP_SYSCALL,
897 begin, end, 'sync')
898 self._fill_log_result_table_from_io_requests(
899 self._analysis.open_io_requests, 'duration', True, open_table)
900 self._fill_log_result_table_from_io_requests(
901 self._analysis.read_io_requests, 'duration', True, read_table)
902 self._fill_log_result_table_from_io_requests(
903 self._analysis.write_io_requests, 'duration', True, write_table)
904 self._fill_log_result_table_from_io_requests(
905 self._analysis.sync_io_requests, 'duration', True, sync_table)
906
907 return [open_table, read_table, write_table, sync_table]
908
909 def _print_log_row(self, row):
910 fmt = '{:<40} {:<16} {:>16} {:>11} {:<24} {:<8} {:<14}'
911 begin_time = common.ns_to_hour_nsec(row.time_range.begin,
912 self._args.multi_day,
913 self._args.gmt)
914 end_time = common.ns_to_hour_nsec(row.time_range.end,
915 self._args.multi_day,
916 self._args.gmt)
917 time_range_str = '[' + begin_time + ',' + end_time + ']'
918 duration_str = '%0.03f' % row.duration.to_us()
7e73fe34 919
a0acc08c
PP
920 if type(row.size) is mi.Empty:
921 size = 'N/A'
922 else:
8400227b 923 size = format_utils.format_size(row.size.value)
a0acc08c
PP
924
925 tid = row.process.tid
926 proc_name = row.process.name
927
928 if type(row.fd) is mi.Empty:
929 file_str = 'N/A'
930 else:
931 if type(row.path) is mi.Unknown:
932 path = 'unknown'
933 else:
934 path = row.path.path
935
936 file_str = '%s (fd=%s)' % (path, row.fd.fd)
937
938 if row.out_of_range.value:
7e73fe34
AB
939 time_range_str += '*'
940 duration_str += '*'
941 else:
942 time_range_str += ' '
943 duration_str += ' '
944
a0acc08c
PP
945 print(fmt.format(time_range_str, row.syscall.name, duration_str,
946 size, proc_name, tid, file_str))
7e73fe34 947
a0acc08c
PP
948 def _print_log(self, result_table):
949 if not result_table.rows:
a9c9a2a6 950 return
7e73fe34 951
7e73fe34
AB
952 has_out_of_range_rq = False
953
954 print()
a0acc08c
PP
955 fmt = '{} {} (usec)'
956 print(fmt.format(result_table.title, result_table.subtitle))
7e73fe34
AB
957 header_fmt = '{:<19} {:<20} {:<16} {:<23} {:<5} {:<24} {:<8} {:<14}'
958 print(header_fmt.format(
959 'Begin', 'End', 'Name', 'Duration (usec)', 'Size', 'Proc', 'PID',
960 'Filename'))
961
a0acc08c
PP
962 for row in result_table.rows:
963 self._print_log_row(row)
7e73fe34 964
a0acc08c 965 if not has_out_of_range_rq and row.out_of_range.value:
7e73fe34
AB
966 has_out_of_range_rq = True
967
7e73fe34 968 if has_out_of_range_rq:
73b71522
AB
969 print('*: Syscalls started and/or completed outside of the '
970 'range specified')
a9c9a2a6 971
a0acc08c
PP
972 def _print_top(self, top_tables):
973 for table in top_tables:
974 self._print_log(table)
975
976 def _get_log_result_table(self, begin, end):
977 log_table = self._mi_create_result_table(self._MI_TABLE_CLASS_LOG,
978 begin, end)
979 self._fill_log_result_table_from_io_requests(
980 self._analysis.io_requests, 'begin_ts', False, log_table)
981
982 return log_table
983
984 def _append_latency_stats_row(self, obj, rq_durations, result_table):
a205a2b4
JD
985 rq_count = len(rq_durations)
986 total_duration = sum(rq_durations)
a0acc08c 987
a205a2b4
JD
988 if len(rq_durations) > 0:
989 min_duration = min(rq_durations)
990 max_duration = max(rq_durations)
991 else:
992 min_duration = 0
993 max_duration = 0
994
ef49c8de 995 if rq_count < 2:
a0acc08c 996 stdev = mi.Unknown()
ef49c8de 997 else:
a0acc08c 998 stdev = mi.Duration(statistics.stdev(rq_durations))
ef49c8de 999
d872de29 1000 if rq_count > 0:
a0acc08c 1001 avg = total_duration / rq_count
d872de29 1002 else:
a0acc08c
PP
1003 avg = 0
1004
1005 result_table.append_row(
1006 obj=obj,
1007 count=mi.Integer(rq_count),
1008 min_latency=mi.Duration(min_duration),
1009 avg_latency=mi.Duration(avg),
1010 max_latency=mi.Duration(max_duration),
1011 stdev_latency=stdev,
1012 )
ef49c8de 1013
a0acc08c
PP
1014 def _append_latency_stats_row_from_requests(self, obj, io_requests,
1015 result_table):
ef49c8de
AB
1016 rq_durations = [io_rq.duration for io_rq in io_requests if
1017 self._filter_io_request(io_rq)]
a0acc08c
PP
1018 self._append_latency_stats_row(obj, rq_durations, result_table)
1019
1020 def _get_syscall_latency_stats_result_table(self, begin, end):
650e7f57
AB
1021 result_table = self._mi_create_result_table(
1022 self._MI_TABLE_CLASS_SYSCALL_LATENCY_STATS, begin, end)
a0acc08c
PP
1023 append_fn = self._append_latency_stats_row_from_requests
1024 append_fn(mi.String('Open'), self._analysis.open_io_requests,
1025 result_table)
1026 append_fn(mi.String('Read'), self._analysis.read_io_requests,
1027 result_table)
1028 append_fn(mi.String('Write'), self._analysis.write_io_requests,
1029 result_table)
1030 append_fn(mi.String('Sync'), self._analysis.sync_io_requests,
1031 result_table)
1032
1033 return result_table
1034
1035 def _get_disk_latency_stats_result_table(self, begin, end):
1036 if not self._analysis.disks:
1037 return
1038
650e7f57
AB
1039 result_table = self._mi_create_result_table(
1040 self._MI_TABLE_CLASS_PART_LATENCY_STATS, begin, end)
a0acc08c
PP
1041
1042 for disk in self._analysis.disks.values():
1043 if disk.rq_count:
1044 rq_durations = [rq.duration for rq in disk.rq_list if
1045 self._filter_io_request(rq)]
1046 disk = mi.Disk(disk.disk_name)
650e7f57
AB
1047 self._append_latency_stats_row(disk, rq_durations,
1048 result_table)
a0acc08c
PP
1049
1050 return result_table
1051
1052 def _get_latency_stats_result_tables(self, begin, end):
1053 syscall_tbl = self._get_syscall_latency_stats_result_table(begin, end)
1054 disk_tbl = self._get_disk_latency_stats_result_table(begin, end)
1055
1056 return syscall_tbl, disk_tbl
ef49c8de 1057
a0acc08c
PP
1058 def _print_latency_stats_row(self, row):
1059 if type(row.stdev_latency) is mi.Unknown:
1060 stdev = '?'
1061 else:
1062 stdev = '%0.03f' % row.stdev_latency.to_us()
1063
1064 avg = '%0.03f' % row.avg_latency.to_us()
1065 min_duration = '%0.03f' % row.min_latency.to_us()
1066 max_duration = '%0.03f' % row.max_latency.to_us()
1067
1068 print(IoAnalysisCommand._LATENCY_STATS_FORMAT.format(
1069 str(row.obj), row.count.value, min_duration,
1070 avg, max_duration, stdev))
1071
1072 def _print_syscall_latency_stats(self, stats_table):
ef49c8de
AB
1073 print('\nSyscalls latency statistics (usec):')
1074 print(IoAnalysisCommand._LATENCY_STATS_FORMAT.format(
1075 'Type', 'Count', 'Min', 'Average', 'Max', 'Stdev'))
1076 print(IoAnalysisCommand._SECTION_SEPARATOR_STRING)
1077
a0acc08c
PP
1078 for row in stats_table.rows:
1079 self._print_latency_stats_row(row)
ef49c8de 1080
a0acc08c
PP
1081 def _print_disk_latency_stats(self, stats_table):
1082 if not stats_table.rows:
a9c9a2a6 1083 return
a9c9a2a6 1084
ef49c8de
AB
1085 print('\nDisk latency statistics (usec):')
1086 print(IoAnalysisCommand._LATENCY_STATS_FORMAT.format(
1087 'Name', 'Count', 'Min', 'Average', 'Max', 'Stdev'))
1088 print(IoAnalysisCommand._SECTION_SEPARATOR_STRING)
1089
a0acc08c
PP
1090 for row in stats_table.rows:
1091 self._print_latency_stats_row(row)
a9c9a2a6 1092
a0acc08c
PP
1093 def _print_latency_stats(self, syscall_latency_stats_table,
1094 disk_latency_stats_table):
1095 self._print_syscall_latency_stats(syscall_latency_stats_table)
1096 self._print_disk_latency_stats(disk_latency_stats_table)
a9c9a2a6 1097
a9c9a2a6 1098 def _add_arguments(self, ap):
b6d9132b
AB
1099 Command._add_proc_filter_args(ap)
1100 Command._add_min_max_args(ap)
1101 Command._add_log_args(
1102 ap, help='Output the I/O requests in chronological order')
b9f05f8d
AB
1103 Command._add_top_args(
1104 ap, help='Output the top I/O latencies by category')
b6d9132b
AB
1105 Command._add_stats_args(ap, help='Output the I/O latency statistics')
1106 Command._add_freq_args(
1107 ap, help='Output the I/O latency frequency distribution')
73b71522 1108 ap.add_argument('--usage', action='store_true',
b6d9132b
AB
1109 help='Output the I/O usage')
1110 ap.add_argument('--minsize', type=float,
1111 help='Filter out, I/O operations working with '
1112 'less that minsize bytes')
1113 ap.add_argument('--maxsize', type=float,
1114 help='Filter out, I/O operations working with '
1115 'more that maxsize bytes')
b6d9132b
AB
1116
1117
a0acc08c
PP
1118def _run(mi_mode):
1119 iocmd = IoAnalysisCommand(mi_mode=mi_mode)
b6d9132b 1120 iocmd.run()
1c0f0e3c 1121
a9c9a2a6 1122
a0acc08c
PP
1123def _runstats(mi_mode):
1124 sys.argv.insert(1, '--stats')
1125 _run(mi_mode)
1126
1127
1128def _runlog(mi_mode):
1129 sys.argv.insert(1, '--log')
1130 _run(mi_mode)
1131
1132
1133def _runfreq(mi_mode):
1134 sys.argv.insert(1, '--freq')
1135 _run(mi_mode)
1136
1137
1138def _runlatencytop(mi_mode):
b6d9132b 1139 sys.argv.insert(1, '--top')
a0acc08c
PP
1140 _run(mi_mode)
1141
1142
1143def _runusage(mi_mode):
1144 sys.argv.insert(1, '--usage')
1145 _run(mi_mode)
1146
1147
1148def runstats():
1149 _runstats(mi_mode=False)
275bdbb4
JD
1150
1151
1c0f0e3c 1152def runlog():
a0acc08c 1153 _runlog(mi_mode=False)
1c0f0e3c
JD
1154
1155
1156def runfreq():
a0acc08c
PP
1157 _runfreq(mi_mode=False)
1158
1159
1160def runlatencytop():
1161 _runlatencytop(mi_mode=False)
1c0f0e3c
JD
1162
1163
1164def runusage():
a0acc08c
PP
1165 _runusage(mi_mode=False)
1166
1167
1168def runstats_mi():
1169 _runstats(mi_mode=True)
1170
1171
1172def runlog_mi():
1173 _runlog(mi_mode=True)
1174
1175
1176def runfreq_mi():
1177 _runfreq(mi_mode=True)
1178
1179
1180def runlatencytop_mi():
1181 _runlatencytop(mi_mode=True)
1182
1183
1184def runusage_mi():
1185 _runusage(mi_mode=True)
This page took 0.081867 seconds and 5 git commands to generate.