+++ /dev/null
-# The MIT License (MIT)
-#
-# Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
-# 2015 - Antoine Busque <abusque@efficios.com>
-# 2015 - Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import operator
-from . import mi
-from ..core import cputop
-from .command import Command
-from ..ascii_graph import Pyasciigraph
-
-
-class Cputop(Command):
- _DESC = """The cputop command."""
- _ANALYSIS_CLASS = cputop.Cputop
- _MI_TITLE = 'Top CPU usage'
- _MI_DESCRIPTION = 'Per-TID, per-CPU, and total top CPU usage'
- _MI_TAGS = [mi.Tags.CPU, mi.Tags.TOP]
- _MI_TABLE_CLASS_PER_PROC = 'per-process'
- _MI_TABLE_CLASS_PER_CPU = 'per-cpu'
- _MI_TABLE_CLASS_TOTAL = 'total'
- _MI_TABLE_CLASS_SUMMARY = 'summary'
- _MI_TABLE_CLASSES = [
- (
- _MI_TABLE_CLASS_PER_PROC,
- 'Per-TID top CPU usage', [
- ('process', 'Process', mi.Process),
- ('migrations', 'Migration count', mi.Integer, 'migrations'),
- ('usage', 'CPU usage', mi.Ratio),
- ]
- ),
- (
- _MI_TABLE_CLASS_PER_CPU,
- 'Per-CPU top CPU usage', [
- ('cpu', 'CPU', mi.Cpu),
- ('usage', 'CPU usage', mi.Ratio),
- ]),
- (
- _MI_TABLE_CLASS_TOTAL,
- 'Total CPU usage', [
- ('usage', 'CPU usage', mi.Ratio),
- ]
- ),
- (
- _MI_TABLE_CLASS_SUMMARY,
- 'CPU usage - summary', [
- ('time_range', 'Time range', mi.TimeRange),
- ('usage', 'Total CPU usage', mi.Ratio),
- ]
- ),
- ]
-
- def _filter_process(self, proc):
- # Exclude swapper
- if proc.tid == 0:
- return False
-
- if self._args.proc_list and proc.comm not in self._args.proc_list:
- return False
-
- return True
-
- def _analysis_tick(self, begin_ns, end_ns):
- per_tid_table = self._get_per_tid_usage_result_table(begin_ns, end_ns)
- per_cpu_table = self._get_per_cpu_usage_result_table(begin_ns, end_ns)
- total_table = self._get_total_usage_result_table(begin_ns, end_ns)
-
- if self._mi_mode:
- self._mi_append_result_table(per_tid_table)
- self._mi_append_result_table(per_cpu_table)
- self._mi_append_result_table(total_table)
- else:
- self._print_date(begin_ns, end_ns)
- self._print_per_tid_usage(per_tid_table)
- self._print_per_cpu_usage(per_cpu_table)
-
- if total_table:
- self._print_total_cpu_usage(total_table)
-
- def _create_summary_result_tables(self):
- total_tables = self._mi_get_result_tables(self._MI_TABLE_CLASS_TOTAL)
- begin = total_tables[0].timerange.begin
- end = total_tables[-1].timerange.end
- summary_table = \
- self._mi_create_result_table(self._MI_TABLE_CLASS_SUMMARY,
- begin, end)
-
- for total_table in total_tables:
- usage = total_table.rows[0].usage
- summary_table.append_row(
- time_range=total_table.timerange,
- usage=usage,
- )
-
- self._mi_clear_result_tables()
- self._mi_append_result_table(summary_table)
-
- def _get_per_tid_usage_result_table(self, begin_ns, end_ns):
- result_table = \
- self._mi_create_result_table(self._MI_TABLE_CLASS_PER_PROC,
- begin_ns, end_ns)
- count = 0
-
- for tid in sorted(self._analysis.tids.values(),
- key=operator.attrgetter('usage_percent'),
- reverse=True):
- if not self._filter_process(tid):
- continue
-
- result_table.append_row(
- process=mi.Process(tid.comm, tid=tid.tid),
- migrations=mi.Integer(tid.migrate_count),
- usage=mi.Ratio.from_percentage(tid.usage_percent)
- )
- count += 1
-
- if self._args.limit > 0 and count >= self._args.limit:
- break
-
- return result_table
-
- def _get_per_cpu_usage_result_table(self, begin_ns, end_ns):
- result_table = \
- self._mi_create_result_table(self._MI_TABLE_CLASS_PER_CPU,
- begin_ns, end_ns)
-
- for cpu in sorted(self._analysis.cpus.values(),
- key=operator.attrgetter('usage_percent'),
- reverse=True):
- result_table.append_row(
- cpu=mi.Cpu(cpu.cpu_id),
- usage=mi.Ratio.from_percentage(cpu.usage_percent)
- )
-
- return result_table
-
- def _get_total_usage_result_table(self, begin_ns, end_ns):
- result_table = \
- self._mi_create_result_table(self._MI_TABLE_CLASS_TOTAL,
- begin_ns, end_ns)
-
- cpu_count = len(self.state.cpus)
- usage_percent = 0
-
- if not cpu_count:
- return
-
- for cpu in sorted(self._analysis.cpus.values(),
- key=operator.attrgetter('usage_percent'),
- reverse=True):
- usage_percent += cpu.usage_percent
-
- # average per CPU
- usage_percent /= cpu_count
- result_table.append_row(
- usage=mi.Ratio.from_percentage(usage_percent),
- )
-
- return result_table
-
- def _print_per_tid_usage(self, result_table):
- graph = Pyasciigraph()
- values = []
-
- for row in result_table.rows:
- process_do = row.process
- migration_count = row.migrations.value
- output_str = '%s (%d)' % (process_do.name, process_do.tid)
-
- if migration_count > 0:
- output_str += ', %d migrations' % (migration_count)
-
- values.append((output_str, row.usage.to_percentage()))
-
- for line in graph.graph('Per-TID CPU Usage', values, unit=' %'):
- print(line)
-
- def _print_per_cpu_usage(self, result_table):
- graph = Pyasciigraph()
- values = []
-
- for row in result_table.rows:
- cpu = row.cpu
- values.append(('CPU %d' % cpu.id, row.usage.to_percentage()))
-
- for line in graph.graph('Per-CPU Usage', values, unit=' %'):
- print(line)
-
- def _print_total_cpu_usage(self, result_table):
- usage_percent = result_table.rows[0].usage.to_percentage()
- print('\nTotal CPU Usage: %0.02f%%\n' % usage_percent)
-
- def _add_arguments(self, ap):
- Command._add_proc_filter_args(ap)
-
-
-def _run(mi_mode):
- cputopcmd = Cputop(mi_mode=mi_mode)
- cputopcmd.run()
-
-
-# entry point (human)
-def run():
- _run(mi_mode=False)
-
-
-# entry point (MI)
-def run_mi():
- _run(mi_mode=True)
+++ /dev/null
-#!/usr/bin/python3
-
-import json
-import string
-import random
-import argparse
-from lttnganalyses.cli import mi
-
-
-_TABLE_CLASS_PER_PROC = 'per-proc'
-_TABLE_CLASS_PER_SYSCALL = 'per-syscall'
-_TABLE_CLASS_PER_IRQ = 'per-irq'
-_TABLE_CLASSES = {
- _TABLE_CLASS_PER_PROC: mi.TableClass(
- _TABLE_CLASS_PER_PROC,
- 'Per-process stuff', [
- ('proc', 'Process', mi.Process),
- ('count', 'Count', mi.Integer, 'things'),
- ('flag', 'Flag', mi.Boolean),
- ('value', 'Value', mi.Float, 'thou'),
- ('name', 'Name', mi.String),
- ('ratio', 'Ratio', mi.Ratio),
- ('ts', 'Timestamp', mi.Timestamp),
- ]
- ),
- _TABLE_CLASS_PER_SYSCALL: mi.TableClass(
- _TABLE_CLASS_PER_SYSCALL,
- 'Per-syscall stuff', [
- ('syscall', 'System call', mi.Syscall),
- ('duration', 'Duration', mi.Duration),
- ('size', 'Size', mi.Size),
- ('bitrate', 'Bitrate', mi.Bitrate),
- ('time_range', 'Time range', mi.TimeRange),
- ]
- ),
- _TABLE_CLASS_PER_IRQ: mi.TableClass(
- _TABLE_CLASS_PER_IRQ,
- 'Per-interrupt stuff', [
- ('interrupt', 'Interrupt', mi.Irq),
- ('fd', 'File descriptor', mi.Fd),
- ('path', 'File path', mi.Path),
- ('cpu', 'CPU', mi.Cpu),
- ('disk', 'Disk', mi.Disk),
- ('part', 'Partition', mi.Partition),
- ('netif', 'Network interface', mi.NetIf),
- ]
- )
-}
-
-
-def _print_metadata():
- infos = mi.get_metadata(version=[1, 2, 3, 'dev'], title='LAMI test',
- description='LTTng analyses machine interface test',
- authors=['Phil Proulx'], url='http://perdu.com',
- tags=['lami', 'test'],
- table_classes=_TABLE_CLASSES.values())
- print(json.dumps(infos))
-
-
-def _parse_args():
- ap = argparse.ArgumentParser()
- ap.add_argument('--metadata', action='store_true')
- ap.add_argument('--begin', type=int, default=1000)
- ap.add_argument('--end', type=int, default=2000)
- ap.add_argument('-d', '--dynamic', action='store_true')
- ap.add_argument('-r', '--dynamic-rows', type=int, default=25)
- ap.add_argument('-c', '--dynamic-columns', type=int, default=10)
-
- return ap.parse_args()
-
-
-def _print_tables(tables):
- obj = {
- 'results': [t.to_native_object() for t in tables],
- }
-
- print(json.dumps(obj))
-
-
-def _print_dynamic_table(begin, end, rows, columns):
- def gen_irq_name(size=6, chars=string.ascii_uppercase + string.digits):
- return ''.join(random.choice(chars) for _ in range(size))
-
- column_tuples = [
- ('irq', 'Interrupt', mi.Irq),
- ]
-
- for i in range(columns):
- column_tuples.append((
- 'count{}'.format(i),
- 'Count ({} to {})'.format(i * 5, (i + 1) * 5),
- mi.Integer,
- 'interrupts'
- ))
-
- table_class = mi.TableClass(None, 'What a dynamic table!', column_tuples)
- result_table = mi.ResultTable(table_class, begin, end)
-
- for i in range(rows):
- row_tuple = [
- mi.Irq(bool(random.getrandbits(1)), i, gen_irq_name())
- ]
-
- for j in range(columns):
- row_tuple.append(mi.Integer(random.randint(0, 5000)))
-
- result_table.append_row_tuple(tuple(row_tuple))
-
- _print_tables([result_table])
-
-
-def _print_static_tables(begin, end):
- per_proc_table = mi.ResultTable(_TABLE_CLASSES[_TABLE_CLASS_PER_PROC], begin, end)
- per_syscall_table = mi.ResultTable(_TABLE_CLASSES[_TABLE_CLASS_PER_SYSCALL], begin, end)
- per_irq_table = mi.ResultTable(_TABLE_CLASSES[_TABLE_CLASS_PER_IRQ], begin, end)
- per_irq_table_sub = mi.ResultTable(_TABLE_CLASSES[_TABLE_CLASS_PER_IRQ], begin, end,
- 'with overridden title')
-
- # per-process
- per_proc_table.append_row_tuple((
- mi.Process('zsh', pid=23),
- mi.Integer(23),
- mi.Boolean(False),
- mi.Float(17.2832),
- mi.String('typical'),
- mi.Ratio(0.154),
- mi.Timestamp(817232),
- ))
- per_proc_table.append_row_tuple((
- mi.Process('chromium', tid=4987),
- mi.Integer(19),
- mi.Boolean(False),
- mi.Float(-19457.15),
- mi.String('beam'),
- mi.Ratio(0.001),
- mi.Timestamp(1194875),
- ))
- per_proc_table.append_row_tuple((
- mi.Process('terminator'),
- mi.Integer(-145),
- mi.Unknown(),
- mi.Float(22.22),
- mi.String('dry'),
- mi.Ratio(0.94),
- mi.Timestamp(984987658),
- ))
- per_proc_table.append_row_tuple((
- mi.Process(pid=1945, tid=4497),
- mi.Integer(31416),
- mi.Boolean(True),
- mi.Float(17.34),
- mi.Empty(),
- mi.Ratio(1.5),
- mi.Timestamp(154484512),
- ))
-
- # per-syscall
- per_syscall_table.append_row_tuple((
- mi.Syscall('read'),
- mi.Duration(2398123),
- mi.Size(8123982),
- mi.Bitrate(223232),
- mi.TimeRange(98233, 1293828),
- ))
- per_syscall_table.append_row_tuple((
- mi.Syscall('write'),
- mi.Duration(412434),
- mi.Size(5645),
- mi.Bitrate(25235343),
- mi.TimeRange(5454, 2354523),
- ))
- per_syscall_table.append_row_tuple((
- mi.Syscall('sync'),
- mi.Duration(2312454),
- mi.Size(23433),
- mi.Empty(),
- mi.TimeRange(12, 645634545454),
- ))
- per_syscall_table.append_row_tuple((
- mi.Syscall('fstat'),
- mi.Unknown(),
- mi.Size(2343334),
- mi.Bitrate(5864684),
- mi.TimeRange(2134, 645634545),
- ))
- per_syscall_table.append_row_tuple((
- mi.Syscall('sync'),
- mi.Duration(564533),
- mi.Size(56875),
- mi.Bitrate(4494494494),
- mi.Empty(),
- ))
-
- # per-interrupt
- per_irq_table.append_row_tuple((
- mi.Irq(True, 15, 'keyboard'),
- mi.Fd(3),
- mi.Path('/etc/passwd'),
- mi.Cpu(2),
- mi.Disk('sda'),
- mi.Partition('sdb3'),
- mi.NetIf('eth0'),
- ))
- per_irq_table.append_row_tuple((
- mi.Irq(False, 7, 'soft-timer'),
- mi.Fd(1),
- mi.Path('/dev/null'),
- mi.Unknown(),
- mi.Disk('hda'),
- mi.Partition('mmcblk0p2'),
- mi.NetIf('enp3s25'),
- ))
- per_irq_table.append_row_tuple((
- mi.Irq(True, 34),
- mi.Empty(),
- mi.Empty(),
- mi.Cpu(1),
- mi.Disk('sdc'),
- mi.Partition('sdc3'),
- mi.NetIf('lo'),
- ))
-
- # per-interrupt with subtitle
- per_irq_table_sub.append_row_tuple((
- mi.Irq(False, 12, 'soft-like-silk'),
- mi.Fd(10),
- mi.Path('/home/bob/meowmix.txt'),
- mi.Cpu(0),
- mi.Disk('sdb'),
- mi.Partition('sdb2'),
- mi.NetIf('eth1'),
- ))
- per_irq_table_sub.append_row_tuple((
- mi.Irq(True, 1, 'mouse2'),
- mi.Fd(5),
- mi.Empty(),
- mi.Cpu(7),
- mi.Disk('vda'),
- mi.Partition('vda3'),
- mi.NetIf('wlp3s0'),
- ))
-
- # print
- _print_tables([
- per_proc_table,
- per_syscall_table,
- per_irq_table,
- per_irq_table_sub,
- ])
-
-
-def _mitest():
- args = _parse_args()
-
- if args.metadata:
- _print_metadata()
- return
-
- if args.dynamic:
- _print_dynamic_table(args.begin, args.end,
- args.dynamic_rows, args.dynamic_columns)
- else:
- _print_static_tables(args.begin, args.end)
-
-
-if __name__ == '__main__':
- _mitest()