Fix: make the regex strings raw strings
[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
3664e4b0
AB
136 def _print_date(self, begin_ns, end_ns):
137 date = 'Timerange: [%s, %s]' % (
138 common.ns_to_hour_nsec(begin_ns, gmt=self._arg_gmt,
139 multi_day=True),
140 common.ns_to_hour_nsec(end_ns, gmt=self._arg_gmt,
141 multi_day=True))
142 print(date)
143
bd3cd7c5
JD
144 def _validate_transform_common_args(self, args):
145 self._arg_path = args.path
28ad5ec8 146
bd3cd7c5
JD
147 if args.limit:
148 self._arg_limit = args.limit
28ad5ec8 149
bd3cd7c5
JD
150 self._arg_begin = None
151 if args.begin:
152 self._arg_begin = args.begin
28ad5ec8 153
bd3cd7c5
JD
154 self._arg_end = None
155 if args.end:
156 self._arg_end = args.end
28ad5ec8 157
bd3cd7c5
JD
158 self._arg_timerange = None
159 if args.timerange:
160 self._arg_timerange = args.timerange
28ad5ec8 161
bd3cd7c5
JD
162 self._arg_gmt = None
163 if args.gmt:
164 self._arg_gmt = args.gmt
28ad5ec8 165
bd3cd7c5
JD
166 self._arg_refresh = args.refresh
167 self._arg_no_progress = args.no_progress
d3014022 168 self._arg_skip_validation = args.skip_validation
bd3cd7c5 169
47ba125c
JD
170 if self._enable_proc_filter_args:
171 self._arg_proc_list = None
172 if args.procname:
73b71522 173 self._arg_proc_list = args.procname.split(',')
28ad5ec8 174
47ba125c
JD
175 self._arg_pid_list = None
176 if args.pid:
73b71522 177 self._arg_pid_list = args.pid.split(',')
47ba125c
JD
178
179 if self._enable_max_min_arg:
2b4a3c12
AB
180 self._arg_max = args.max
181 self._arg_min = args.min
47ba125c 182
f89605f0 183 if self._enable_max_min_size_arg:
2b4a3c12
AB
184 self._arg_maxsize = args.maxsize
185 self._arg_minsize = args.minsize
f89605f0
JD
186
187 if self._enable_freq_arg:
188 self._arg_freq = args.freq
189 self._arg_freq_resolution = args.freq_resolution
190
191 if self._enable_log_arg:
192 self._arg_log = args.log
193
194 if self._enable_stats_arg:
195 self._arg_stats = args.stats
196
323b3fd6
PP
197 def _parse_args(self):
198 ap = argparse.ArgumentParser(description=self._DESC)
199
200 # common arguments
73b71522 201 ap.add_argument('path', metavar='<path/to/trace>', help='trace path')
bd3cd7c5 202 ap.add_argument('-r', '--refresh', type=int,
28ad5ec8 203 help='Refresh period in seconds')
bd3cd7c5
JD
204 ap.add_argument('--limit', type=int, default=10,
205 help='Limit to top X (default = 10)')
73b71522 206 ap.add_argument('--no-progress', action='store_true',
bd3cd7c5 207 help='Don\'t display the progress bar')
73b71522 208 ap.add_argument('--skip-validation', action='store_true',
d3014022 209 help='Skip the trace validation')
73b71522 210 ap.add_argument('--gmt', action='store_true',
bd3cd7c5
JD
211 help='Manipulate timestamps based on GMT instead '
212 'of local time')
213 ap.add_argument('--begin', type=str, help='start time: '
214 'hh:mm:ss[.nnnnnnnnn]')
215 ap.add_argument('--end', type=str, help='end time: '
216 'hh:mm:ss[.nnnnnnnnn]')
217 ap.add_argument('--timerange', type=str, help='time range: '
218 '[begin,end]')
219
220 if self._enable_proc_filter_args:
28ad5ec8 221 ap.add_argument('--procname', type=str,
bd3cd7c5
JD
222 help='Filter the results only for this list of '
223 'process names')
28ad5ec8 224 ap.add_argument('--pid', type=str,
bd3cd7c5
JD
225 help='Filter the results only for this list '
226 'of PIDs')
323b3fd6 227
47ba125c 228 if self._enable_max_min_arg:
28ad5ec8 229 ap.add_argument('--max', type=float,
47ba125c 230 help='Filter out, duration longer than max usec')
28ad5ec8 231 ap.add_argument('--min', type=float,
47ba125c
JD
232 help='Filter out, duration shorter than min usec')
233
f89605f0 234 if self._enable_max_min_size_arg:
28ad5ec8 235 ap.add_argument('--maxsize', type=float,
f89605f0
JD
236 help='Filter out, I/O operations working with '
237 'more that maxsize bytes')
28ad5ec8 238 ap.add_argument('--minsize', type=float,
f89605f0
JD
239 help='Filter out, I/O operations working with '
240 'less that minsize bytes')
241
242 if self._enable_freq_arg:
73b71522 243 ap.add_argument('--freq', action='store_true',
f89605f0
JD
244 help='Show the frequency distribution of '
245 'handler duration')
246 ap.add_argument('--freq-resolution', type=int, default=20,
247 help='Frequency distribution resolution '
248 '(default 20)')
249
250 if self._enable_log_arg:
73b71522 251 ap.add_argument('--log', action='store_true',
f89605f0
JD
252 help='Display the events in the order they '
253 'appeared')
254
255 if self._enable_stats_arg:
73b71522 256 ap.add_argument('--stats', action='store_true',
f89605f0
JD
257 help='Display the statistics')
258
323b3fd6
PP
259 # specific arguments
260 self._add_arguments_cb(ap)
261
262 # version of the specific command
323b3fd6
PP
263 ap.add_argument('-V', '--version', action='version',
264 version=self._VERSION)
265
266 # parse arguments
267 args = ap.parse_args()
268
bd3cd7c5 269 self._validate_transform_common_args(args)
323b3fd6 270
323b3fd6
PP
271 # save all arguments
272 self._args = args
273
274 def _create_automaton(self):
275 self._automaton = linuxautomaton.automaton.Automaton()
6e01ed18 276 self.state = self._automaton.state
This page took 0.038086 seconds and 5 git commands to generate.