import statistics
import sys
from . import mi
+from . import termgraph
from ..core import io
+from ..common import format_utils
from .command import Command
from ..linuxautomaton import common
from ..ascii_graph import Pyasciigraph
per_netif_send=per_netif_send_table,
)
- def _get_per_process_read_write_usage_datum(self, row):
- if row.process.pid is None:
- pid_str = 'unknown (tid=%d)' % (row.process.tid)
- else:
- pid_str = str(row.process.pid)
-
- format_str = '{:>10} {:<25} {:>9} file {:>9} net {:>9} unknown'
- output_str = format_str.format(
- common.convert_size(row.size.value, padding_after=True),
- '%s (%s)' % (row.process.name, pid_str),
- common.convert_size(row.disk_size.value, padding_after=True),
- common.convert_size(row.net_size.value, padding_after=True),
- common.convert_size(row.unknown_size.value, padding_after=True))
+ def _print_per_proc_io(self, result_table, title):
+ header_format = '{:<25} {:<10} {:<10} {:<10}'
+ label_header = header_format.format(
+ 'Process', 'Disk', 'Net', 'Unknown'
+ )
- return (output_str, row.size.value)
+ def get_label(row):
+ label_format = '{:<25} {:>10} {:>10} {:>10}'
+ if row.process.pid is None:
+ pid_str = 'unknown (tid=%d)' % (row.process.tid)
+ else:
+ pid_str = str(row.process.pid)
- def _get_per_process_block_read_write_usage_datum(self, row):
- proc_name = row.process.name
+ label = label_format.format(
+ '%s (%s)' % (row.process.name, pid_str),
+ format_utils.format_size(row.disk_size.value),
+ format_utils.format_size(row.net_size.value),
+ format_utils.format_size(row.unknown_size.value)
+ )
- if not proc_name:
- proc_name = 'unknown'
+ return label
- if row.process.pid is None:
- pid_str = 'unknown (tid=%d)' % (row.process.tid)
- else:
- pid_str = str(row.process.pid)
+ graph = termgraph.BarGraph(
+ title='Per-process I/O ' + title,
+ label_header=label_header,
+ get_value=lambda row: row.size.value,
+ get_value_str=format_utils.format_size,
+ get_label=get_label,
+ data=result_table.rows
+ )
- format_str = '{:>10} {:<22}'
- output_str = format_str.format(
- common.convert_size(row.size.value, padding_after=True),
- '%s (pid=%s)' % (proc_name, pid_str))
+ graph.print_graph()
- return (output_str, row.size.value)
+ def _print_per_proc_block_io(self, result_table, title):
+ def get_label(row):
+ proc_name = row.process.name
- def _get_per_disk_count_usage_datum(self, row):
- return (row.disk.name, row.count.value)
+ if not proc_name:
+ proc_name = 'unknown'
- def _get_per_disk_rtps_usage_datum(self, row):
- avg_latency = row.rtps.value / common.NSEC_PER_MSEC
- avg_latency = round(avg_latency, 3)
+ if row.process.pid is None:
+ pid_str = 'unknown (tid={})'.format(row.process.tid)
+ else:
+ pid_str = str(row.process.pid)
- return (row.disk.name, avg_latency)
+ return '{} (pid={})'.format(proc_name, pid_str)
- def _get_per_netif_recv_send_usage_datum(self, row):
- return ('%s %s' %
- (common.convert_size(row.size.value), row.netif.name),
- row.size.value)
+ graph = termgraph.BarGraph(
+ title='Block I/O ' + title,
+ label_header='Process',
+ get_value=lambda row: row.size.value,
+ get_value_str=format_utils.format_size,
+ get_label=get_label,
+ data=result_table.rows
+ )
- def _get_per_file_read_write_usage_datum(self, row):
- format_str = '{:>10} {} {}'
- output_str = format_str.format(
- common.convert_size(row.size.value, padding_after=True),
- row.path.path, row.fd_owners.value)
+ graph.print_graph()
- return (output_str, row.size.value)
+ def _print_per_disk_sector(self, result_table):
+ graph = termgraph.BarGraph(
+ title='Disk Requests Sector Count',
+ label_header='Disk',
+ unit='sectors',
+ get_value=lambda row: row.count.value,
+ get_label=lambda row: row.disk.name,
+ data=result_table.rows
+ )
- def _print_usage_ascii_graph(self, result_table, get_datum_cb, graph_label,
- graph_args=None):
- graph = Pyasciigraph()
- data = []
+ graph.print_graph()
- if graph_args is None:
- graph_args = {}
+ def _print_per_disk_request(self, result_table):
+ graph = termgraph.BarGraph(
+ title='Disk Request Count',
+ label_header='Disk',
+ unit='requests',
+ get_value=lambda row: row.count.value,
+ get_label=lambda row: row.disk.name,
+ data=result_table.rows
+ )
- for row in result_table.rows:
- datum = get_datum_cb(row)
- data.append(datum)
+ graph.print_graph()
- for line in graph.graph(graph_label, data, **graph_args):
- print(line)
+ def _print_per_disk_rtps(self, result_table):
+ graph = termgraph.BarGraph(
+ title='Disk Request Average Latency',
+ label_header='Disk',
+ unit='ms',
+ get_value=lambda row: row.rtps.value / common.NSEC_PER_MSEC,
+ get_label=lambda row: row.disk.name,
+ data=result_table.rows
+ )
- def _print_per_process_read(self, result_table):
- label = 'Per-process I/O Read'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_process_read_write_usage_datum,
- label, graph_args)
-
- def _print_per_process_write(self, result_table):
- label = 'Per-process I/O Write'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_process_read_write_usage_datum,
- label, graph_args)
-
- def _print_per_process_block_read(self, result_table):
- label = 'Block I/O Read'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_process_block_read_write_usage_datum,
- label, graph_args)
-
- def _print_per_process_block_write(self, result_table):
- label = 'Block I/O Write'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_process_block_read_write_usage_datum,
- label, graph_args)
+ graph.print_graph()
- def _print_per_disk_sector(self, result_table):
- label = 'Disk requests sector count'
- graph_args = {'unit': ' sectors'}
- self._print_usage_ascii_graph(result_table,
- self._get_per_disk_count_usage_datum,
- label, graph_args)
+ def _print_per_netif_io(self, result_table, title):
+ graph = termgraph.BarGraph(
+ title='Network ' + title + ' Bytes',
+ label_header='Interface',
+ get_value=lambda row: row.size.value,
+ get_value_str=format_utils.format_size,
+ get_label=lambda row: row.netif.name,
+ data=result_table.rows
+ )
- def _print_per_disk_request(self, result_table):
- label = 'Disk request count'
- graph_args = {'unit': ' requests'}
- self._print_usage_ascii_graph(result_table,
- self._get_per_disk_count_usage_datum,
- label, graph_args)
+ graph.print_graph()
+
+ def _print_per_file_io(self, result_table, title):
+ # FIXME add option to show FD owners
+ # FIXME why are read and write values the same?
+ graph = termgraph.BarGraph(
+ title='Per-file I/O ' + title,
+ label_header='Path',
+ get_value=lambda row: row.size.value,
+ get_value_str=format_utils.format_size,
+ get_label=lambda row: row.path.path,
+ data=result_table.rows
+ )
- def _print_per_disk_rtps(self, result_table):
- label = 'Disk request average latency'
- graph_args = {'unit': ' ms', 'sort': 2}
- self._print_usage_ascii_graph(result_table,
- self._get_per_disk_rtps_usage_datum,
- label, graph_args)
-
- def _print_per_netif_recv(self, result_table):
- label = 'Network received bytes'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_netif_recv_send_usage_datum,
- label, graph_args)
-
- def _print_per_netif_send(self, result_table):
- label = 'Network sent bytes'
- graph_args = {'with_value': False}
- self._print_usage_ascii_graph(
- result_table, self._get_per_netif_recv_send_usage_datum,
- label, graph_args)
-
- def _print_per_file_read(self, result_table):
- label = 'Files read'
- graph_args = {'with_value': False, 'sort': 2}
- self._print_usage_ascii_graph(
- result_table, self._get_per_file_read_write_usage_datum,
- label, graph_args)
-
- def _print_per_file_write(self, result_table):
- label = 'Files write'
- graph_args = {'with_value': False, 'sort': 2}
- self._print_usage_ascii_graph(
- result_table, self._get_per_file_read_write_usage_datum,
- label, graph_args)
+ graph.print_graph()
def _print_usage(self, usage_tables):
- self._print_per_process_read(usage_tables.per_proc_read)
- self._print_per_process_write(usage_tables.per_proc_write)
- self._print_per_file_read(usage_tables.per_file_read)
- self._print_per_file_write(usage_tables.per_file_write)
- self._print_per_process_block_read(usage_tables.per_proc_block_read)
- self._print_per_process_block_write(usage_tables.per_proc_block_write)
+ self._print_per_proc_io(usage_tables.per_proc_read, 'Read')
+ self._print_per_proc_io(usage_tables.per_proc_write, 'Write')
+ self._print_per_file_io(usage_tables.per_file_read, 'Read')
+ self._print_per_file_io(usage_tables.per_file_write, 'Write')
+ self._print_per_proc_block_io(usage_tables.per_proc_block_read, 'Read')
+ self._print_per_proc_block_io(
+ usage_tables.per_proc_block_write, 'Write'
+ )
self._print_per_disk_sector(usage_tables.per_disk_sector)
self._print_per_disk_request(usage_tables.per_disk_request)
self._print_per_disk_rtps(usage_tables.per_disk_rtps)
- self._print_per_netif_recv(usage_tables.per_netif_recv)
- self._print_per_netif_send(usage_tables.per_netif_send)
+ self._print_per_netif_io(usage_tables.per_netif_recv, 'Received')
+ self._print_per_netif_io(usage_tables.per_netif_send, 'Sent')
def _fill_freq_result_table(self, duration_list, result_table):
if not duration_list:
if type(row.size) is mi.Empty:
size = 'N/A'
else:
- size = common.convert_size(row.size.value)
+ size = format_utils.format_size(row.size.value)
tid = row.process.tid
proc_name = row.process.name