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