Fix: correct typo in author email address
[deliverable/lttng-analyses.git] / lttnganalysescli / lttnganalysescli / syscallstats.py
1 #!/usr/bin/env python3
2 #
3 # The MIT License (MIT)
4 #
5 # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com>
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
25 from .command import Command
26 import lttnganalyses.syscalls
27 from linuxautomaton import common
28 import operator
29 import statistics
30 import errno
31
32
33 class SyscallsAnalysis(Command):
34 _VERSION = '0.1.0'
35 _DESC = """The I/O command."""
36
37 def __init__(self):
38 super().__init__(self._add_arguments,
39 enable_proc_filter_args=True)
40 # enable_max_min_args=True,
41 # enable_max_min_size_arg=True,
42 # enable_freq_arg=True,
43 # enable_log_arg=True,
44 # enable_stats_arg=True)
45
46 def _validate_transform_args(self):
47 pass
48
49 def run(self):
50 # parse arguments first
51 self._parse_args()
52 # validate, transform and save specific arguments
53 self._validate_transform_args()
54 # open the trace
55 self._open_trace()
56 # create the appropriate analysis/analyses
57 self._create_analysis()
58 # run the analysis
59 self._run_analysis(self._reset_total, self._refresh)
60 # process the results
61 self._compute_stats()
62 # print results
63 self._print_results(self.start_ns, self.trace_end_ts, final=1)
64 # close the trace
65 self._close_trace()
66
67 def _create_analysis(self):
68 self._analysis = lttnganalyses.syscalls.SyscallsAnalysis(
69 self._automaton.state)
70
71 def _compute_stats(self):
72 self.state = self._automaton.state
73 pass
74
75 def _refresh(self, begin, end):
76 self._compute_stats()
77 self._print_results(begin, end, final=0)
78 self._reset_total(end)
79
80 def filter_process(self, proc):
81 if self._arg_proc_list and proc.comm not in self._arg_proc_list:
82 return False
83 if self._arg_pid_list and str(proc.pid) not in self._arg_pid_list:
84 return False
85 return True
86
87 def _print_results(self, begin_ns, end_ns, final=0):
88 print('Timerange: [%s, %s]' % (
89 common.ns_to_hour_nsec(begin_ns, gmt=self._arg_gmt,
90 multi_day=True),
91 common.ns_to_hour_nsec(end_ns, gmt=self._arg_gmt,
92 multi_day=True)))
93 strformat = "{:<28} {:>14} {:>14} {:>14} {:>12} {:>10} {:<14}"
94 print("Per-TID syscalls statistics (usec)")
95 for tid in sorted(self.state.tids.values(),
96 key=operator.attrgetter('total_syscalls'),
97 reverse=True):
98 if not self.filter_process(tid):
99 continue
100 if tid.total_syscalls == 0:
101 continue
102 print(strformat.format("%s (%d, tid = %d)" % (
103 tid.comm, tid.pid, tid.tid),
104 "Count", "Min", "Average", "Max", "Stdev", "Return values"))
105 for syscall in sorted(tid.syscalls.values(),
106 key=operator.attrgetter('count'),
107 reverse=True):
108 sysvalues = []
109 rets = {}
110 for s in syscall.rq:
111 sysvalues.append(s.duration)
112 if s.ret >= 0:
113 key = "success"
114 else:
115 try:
116 key = errno.errorcode[-s.ret]
117 except:
118 key = str(s.ret)
119 if key in rets.keys():
120 rets[key] += 1
121 else:
122 rets[key] = 1
123 if syscall.min is None:
124 syscallmin = "?"
125 else:
126 syscallmin = "%0.03f" % (syscall.min / 1000)
127 syscallmax = "%0.03f" % (syscall.max / 1000)
128 syscallavg = "%0.03f" % \
129 (syscall.total_duration/(syscall.count*1000))
130 if len(sysvalues) > 2:
131 stdev = "%0.03f" % (statistics.stdev(sysvalues) / 1000)
132 else:
133 stdev = "?"
134 name = syscall.name.replace("syscall_entry_", "")
135 name = name.replace("sys_", "")
136 print(strformat.format(" - " + name, syscall.count,
137 syscallmin, syscallavg, syscallmax,
138 stdev, str(rets)))
139 print(strformat.format("Total:", tid.total_syscalls, "", "", "",
140 "", ""))
141 print("-" * 113)
142
143 print("\nTotal syscalls: %d" % (self.state.syscalls["total"]))
144
145 def _reset_total(self, start_ts):
146 pass
147
148 def _add_arguments(self, ap):
149 # specific argument
150 pass
151
152
153 # entry point
154 def run():
155 # create command
156 syscallscmd = SyscallsAnalysis()
157
158 # execute command
159 syscallscmd.run()
This page took 0.038163 seconds and 5 git commands to generate.