Add reset method to Analysis classes
[deliverable/lttng-analyses.git] / lttnganalysescli / lttnganalysescli / command.py
CommitLineData
4ed24f86
JD
1#!/usr/bin/env python3
2#
3# The MIT License (MIT)
4#
a3fa57c0 5# Copyright (C) 2015 - Julien Desfossez <jdesfossez@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
323b3fd6 25import linuxautomaton.automaton
bd3cd7c5
JD
26from lttnganalysescli import progressbar
27from linuxautomaton import common
28from babeltrace import TraceCollection
323b3fd6
PP
29import argparse
30import sys
d3014022 31import subprocess
323b3fd6
PP
32
33
34class Command:
f89605f0
JD
35 def __init__(self, add_arguments_cb,
36 enable_proc_filter_args=False,
37 enable_max_min_args=False,
38 enable_max_min_size_arg=False,
39 enable_freq_arg=False,
40 enable_log_arg=False,
41 enable_stats_arg=False):
323b3fd6 42 self._add_arguments_cb = add_arguments_cb
47ba125c
JD
43 self._enable_proc_filter_args = enable_proc_filter_args
44 self._enable_max_min_arg = enable_max_min_args
f89605f0
JD
45 self._enable_max_min_size_arg = enable_max_min_size_arg
46 self._enable_freq_arg = enable_freq_arg
47 self._enable_log_arg = enable_log_arg
48 self._enable_stats_arg = enable_stats_arg
323b3fd6
PP
49 self._create_automaton()
50
51 def _error(self, msg, exit_code=1):
52 print(msg, file=sys.stderr)
53 sys.exit(exit_code)
54
55 def _gen_error(self, msg, exit_code=1):
56 self._error('Error: {}'.format(msg), exit_code)
57
58 def _cmdline_error(self, msg, exit_code=1):
59 self._error('Command line error: {}'.format(msg), exit_code)
60
bd3cd7c5
JD
61 def _open_trace(self):
62 traces = TraceCollection()
73b71522 63 handle = traces.add_traces_recursive(self._arg_path, 'ctf')
bd3cd7c5 64 if handle == {}:
73b71522 65 self._gen_error('Failed to open ' + self._arg_path, -1)
bd3cd7c5
JD
66 self._handle = handle
67 self._traces = traces
68 common.process_date_args(self)
d3014022
JD
69 if not self._arg_skip_validation:
70 self._check_lost_events()
bd3cd7c5
JD
71
72 def _close_trace(self):
73 for h in self._handle.values():
74 self._traces.remove_trace(h)
75
d3014022 76 def _check_lost_events(self):
73b71522 77 print('Checking the trace for lost events...')
d3014022 78 try:
73b71522 79 subprocess.check_output('babeltrace %s' % self._arg_path,
d3014022
JD
80 shell=True)
81 except subprocess.CalledProcessError:
73b71522
AB
82 print('Error running babeltrace on the trace, cannot verify if '
83 'events were lost during the trace recording')
d3014022 84
119f6cef 85 def _run_analysis(self, reset_cb, refresh_cb, break_cb=None):
bd3cd7c5
JD
86 self.trace_start_ts = 0
87 self.trace_end_ts = 0
88 self.current_sec = 0
89 self.start_ns = 0
90 self.end_ns = 0
64c77c5c 91 started = False
bd3cd7c5
JD
92 progressbar.progressbar_setup(self)
93 if not self._arg_begin:
64c77c5c 94 started = True
bd3cd7c5
JD
95 for event in self._traces.events:
96 progressbar.progressbar_update(self)
64c77c5c 97 if self._arg_begin and not started and \
bd3cd7c5 98 event.timestamp >= self._arg_begin:
64c77c5c 99 started = True
bd3cd7c5
JD
100 self.trace_start_ts = event.timestamp
101 self.start_ns = event.timestamp
102 reset_cb(event.timestamp)
103 if self._arg_end and event.timestamp > self._arg_end:
119f6cef
JD
104 if break_cb is not None:
105 # check if we really can break here
106 if break_cb():
107 break
108 else:
109 break
bd3cd7c5
JD
110 if self.start_ns == 0:
111 self.start_ns = event.timestamp
112 if self.trace_start_ts == 0:
113 self.trace_start_ts = event.timestamp
114 self.end_ns = event.timestamp
115 self._check_refresh(event, refresh_cb)
116 self.trace_end_ts = event.timestamp
bd3cd7c5
JD
117 # feed analysis
118 self._analysis.process_event(event)
47ba125c
JD
119 # feed automaton
120 self._automaton.process_event(event)
bd3cd7c5
JD
121 progressbar.progressbar_finish(self)
122
123 def _check_refresh(self, event, refresh_cb):
124 """Check if we need to output something"""
28ad5ec8 125 if self._arg_refresh is None:
bd3cd7c5
JD
126 return
127 event_sec = event.timestamp / common.NSEC_PER_SEC
128 if self.current_sec == 0:
129 self.current_sec = event_sec
130 elif self.current_sec != event_sec and \
131 (self.current_sec + self._arg_refresh) <= event_sec:
132 refresh_cb(self.start_ns, event.timestamp)
133 self.current_sec = event_sec
134 self.start_ns = event.timestamp
135
136 def _validate_transform_common_args(self, args):
137 self._arg_path = args.path
28ad5ec8 138
bd3cd7c5
JD
139 if args.limit:
140 self._arg_limit = args.limit
28ad5ec8 141
bd3cd7c5
JD
142 self._arg_begin = None
143 if args.begin:
144 self._arg_begin = args.begin
28ad5ec8 145
bd3cd7c5
JD
146 self._arg_end = None
147 if args.end:
148 self._arg_end = args.end
28ad5ec8 149
bd3cd7c5
JD
150 self._arg_timerange = None
151 if args.timerange:
152 self._arg_timerange = args.timerange
28ad5ec8 153
bd3cd7c5
JD
154 self._arg_gmt = None
155 if args.gmt:
156 self._arg_gmt = args.gmt
28ad5ec8 157
bd3cd7c5
JD
158 self._arg_refresh = args.refresh
159 self._arg_no_progress = args.no_progress
d3014022 160 self._arg_skip_validation = args.skip_validation
bd3cd7c5 161
47ba125c
JD
162 if self._enable_proc_filter_args:
163 self._arg_proc_list = None
164 if args.procname:
73b71522 165 self._arg_proc_list = args.procname.split(',')
28ad5ec8 166
47ba125c
JD
167 self._arg_pid_list = None
168 if args.pid:
73b71522 169 self._arg_pid_list = args.pid.split(',')
47ba125c
JD
170
171 if self._enable_max_min_arg:
2b4a3c12
AB
172 self._arg_max = args.max
173 self._arg_min = args.min
47ba125c 174
f89605f0 175 if self._enable_max_min_size_arg:
2b4a3c12
AB
176 self._arg_maxsize = args.maxsize
177 self._arg_minsize = args.minsize
f89605f0
JD
178
179 if self._enable_freq_arg:
180 self._arg_freq = args.freq
181 self._arg_freq_resolution = args.freq_resolution
182
183 if self._enable_log_arg:
184 self._arg_log = args.log
185
186 if self._enable_stats_arg:
187 self._arg_stats = args.stats
188
323b3fd6
PP
189 def _parse_args(self):
190 ap = argparse.ArgumentParser(description=self._DESC)
191
192 # common arguments
73b71522 193 ap.add_argument('path', metavar='<path/to/trace>', help='trace path')
bd3cd7c5 194 ap.add_argument('-r', '--refresh', type=int,
28ad5ec8 195 help='Refresh period in seconds')
bd3cd7c5
JD
196 ap.add_argument('--limit', type=int, default=10,
197 help='Limit to top X (default = 10)')
73b71522 198 ap.add_argument('--no-progress', action='store_true',
bd3cd7c5 199 help='Don\'t display the progress bar')
73b71522 200 ap.add_argument('--skip-validation', action='store_true',
d3014022 201 help='Skip the trace validation')
73b71522 202 ap.add_argument('--gmt', action='store_true',
bd3cd7c5
JD
203 help='Manipulate timestamps based on GMT instead '
204 'of local time')
205 ap.add_argument('--begin', type=str, help='start time: '
206 'hh:mm:ss[.nnnnnnnnn]')
207 ap.add_argument('--end', type=str, help='end time: '
208 'hh:mm:ss[.nnnnnnnnn]')
209 ap.add_argument('--timerange', type=str, help='time range: '
210 '[begin,end]')
211
212 if self._enable_proc_filter_args:
28ad5ec8 213 ap.add_argument('--procname', type=str,
bd3cd7c5
JD
214 help='Filter the results only for this list of '
215 'process names')
28ad5ec8 216 ap.add_argument('--pid', type=str,
bd3cd7c5
JD
217 help='Filter the results only for this list '
218 'of PIDs')
323b3fd6 219
47ba125c 220 if self._enable_max_min_arg:
28ad5ec8 221 ap.add_argument('--max', type=float,
47ba125c 222 help='Filter out, duration longer than max usec')
28ad5ec8 223 ap.add_argument('--min', type=float,
47ba125c
JD
224 help='Filter out, duration shorter than min usec')
225
f89605f0 226 if self._enable_max_min_size_arg:
28ad5ec8 227 ap.add_argument('--maxsize', type=float,
f89605f0
JD
228 help='Filter out, I/O operations working with '
229 'more that maxsize bytes')
28ad5ec8 230 ap.add_argument('--minsize', type=float,
f89605f0
JD
231 help='Filter out, I/O operations working with '
232 'less that minsize bytes')
233
234 if self._enable_freq_arg:
73b71522 235 ap.add_argument('--freq', action='store_true',
f89605f0
JD
236 help='Show the frequency distribution of '
237 'handler duration')
238 ap.add_argument('--freq-resolution', type=int, default=20,
239 help='Frequency distribution resolution '
240 '(default 20)')
241
242 if self._enable_log_arg:
73b71522 243 ap.add_argument('--log', action='store_true',
f89605f0
JD
244 help='Display the events in the order they '
245 'appeared')
246
247 if self._enable_stats_arg:
73b71522 248 ap.add_argument('--stats', action='store_true',
f89605f0
JD
249 help='Display the statistics')
250
323b3fd6
PP
251 # specific arguments
252 self._add_arguments_cb(ap)
253
254 # version of the specific command
323b3fd6
PP
255 ap.add_argument('-V', '--version', action='version',
256 version=self._VERSION)
257
258 # parse arguments
259 args = ap.parse_args()
260
bd3cd7c5 261 self._validate_transform_common_args(args)
323b3fd6 262
323b3fd6
PP
263 # save all arguments
264 self._args = args
265
266 def _create_automaton(self):
267 self._automaton = linuxautomaton.automaton.Automaton()
6e01ed18 268 self.state = self._automaton.state
This page took 0.036486 seconds and 5 git commands to generate.