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