import sys
import subprocess
from babeltrace import TraceCollection
-from . import mi
-from .. import _version
-from . import progressbar
-from .. import __version__
-from ..common import version_utils
+from . import mi, progressbar
+from .. import _version, __version__
from ..core import analysis
-from ..linuxautomaton import common
+from ..common import (
+ format_utils, parse_utils, time_utils, trace_utils, version_utils
+)
from ..linuxautomaton import automaton
except KeyboardInterrupt:
sys.exit(0)
- def _error(self, msg, exit_code=1):
+ def _mi_error(self, msg, code=None):
+ print(json.dumps(mi.get_error(msg, code)))
+
+ def _non_mi_error(self, msg):
try:
import termcolor
pass
print(msg, file=sys.stderr)
+
+ def _error(self, msg, code, exit_code=1):
+ if self._mi_mode:
+ self._mi_error(msg)
+ else:
+ self._non_mi_error(msg)
+
sys.exit(exit_code)
def _gen_error(self, msg, exit_code=1):
self._gen_error('Failed to open ' + self._args.path, -1)
self._handles = handles
self._traces = traces
+ self._ts_begin = traces.timestamp_begin
+ self._ts_end = traces.timestamp_end
self._process_date_args()
self._read_tracer_version()
if not self._args.skip_validation:
def _read_tracer_version(self):
kernel_path = None
+ # remove the trailing /
+ while self._args.path.endswith('/'):
+ self._args.path = self._args.path[:-1]
for root, _, _ in os.walk(self._args.path):
if root.endswith('kernel'):
kernel_path = root
self._gen_error('Could not find kernel trace directory')
try:
- metadata = subprocess.getoutput(
+ ret, metadata = subprocess.getstatusoutput(
'babeltrace -o ctf-metadata "%s"' % kernel_path)
except subprocess.CalledProcessError:
self._gen_error('Cannot run babeltrace on the trace, cannot read'
' tracer version')
- major_match = re.search(r'tracer_major = (\d+)', metadata)
- minor_match = re.search(r'tracer_minor = (\d+)', metadata)
- patch_match = re.search(r'tracer_patchlevel = (\d+)', metadata)
+ # fallback to reading the text metadata if babeltrace failed to
+ # output the CTF metadata
+ if ret != 0:
+ try:
+ metadata = subprocess.getoutput(
+ 'cat "%s"' % os.path.join(kernel_path, 'metadata'))
+ except subprocess.CalledProcessError:
+ self._gen_error('Cannot read the metadata of the trace, cannot'
+ 'extract tracer version')
+
+ major_match = re.search(r'tracer_major = "*(\d+)"*', metadata)
+ minor_match = re.search(r'tracer_minor = "*(\d+)"*', metadata)
+ patch_match = re.search(r'tracer_patchlevel = "*(\d+)"*', metadata)
if not major_match or not minor_match or not patch_match:
self._gen_error('Malformed metadata, cannot read tracer version')
)
def _check_lost_events(self):
- self._print('Checking the trace for lost events...')
+ msg = 'Checking the trace for lost events...'
+ self._print(msg)
+
+ if self._mi_mode and self._args.output_progress:
+ mi.print_progress(0, msg)
+
try:
subprocess.check_output('babeltrace "%s"' % self._args.path,
shell=True)
self._mi_print()
+ def _pb_setup(self):
+ if self._args.no_progress:
+ return
+
+ ts_end = self._ts_end
+
+ if self._analysis_conf.end_ts is not None:
+ ts_end = self._analysis_conf.end_ts
+
+ if self._mi_mode:
+ cls = progressbar.MiProgress
+ else:
+ cls = progressbar.FancyProgressBar
+
+ self._progress = cls(self._ts_begin, ts_end, self._args.path,
+ self._args.progress_use_size)
+
+ def _pb_update(self, event):
+ if self._args.no_progress:
+ return
+
+ self._progress.update(event)
+
+ def _pb_finish(self):
+ if self._args.no_progress:
+ return
+
+ self._progress.finalize()
+
def _run_analysis(self):
self._pre_analysis()
- progressbar.progressbar_setup(self)
+ self._pb_setup()
for event in self._traces.events:
- progressbar.progressbar_update(self)
+ self._pb_update(event)
self._analysis.process_event(event)
if self._analysis.ended:
break
self._automaton.process_event(event)
- progressbar.progressbar_finish(self)
+ self._pb_finish()
self._analysis.end()
self._post_analysis()
def _print_date(self, begin_ns, end_ns):
- date = 'Timerange: [%s, %s]' % (
- common.ns_to_hour_nsec(begin_ns, gmt=self._args.gmt,
- multi_day=True),
- common.ns_to_hour_nsec(end_ns, gmt=self._args.gmt,
- multi_day=True))
+ time_range_str = format_utils.format_time_range(
+ begin_ns, end_ns, print_date=True, gmt=self._args.gmt
+ )
+ date = 'Timerange: {}'.format(time_range_str)
+
self._print(date)
+ def _format_timestamp(self, timestamp):
+ return format_utils.format_timestamp(
+ timestamp, print_date=self._args.multi_day, gmt=self._args.gmt
+ )
+
def _get_uniform_freq_values(self, durations):
if self._args.uniform_step is not None:
return (self._args.uniform_min, self._args.uniform_max,
refresh_period_ns = None
if args.refresh is not None:
try:
- refresh_period_ns = common.duration_str_to_ns(args.refresh)
+ refresh_period_ns = parse_utils.parse_duration(args.refresh)
except ValueError as e:
self._cmdline_error(str(e))
self._analysis_conf.period_begin_ev_name = args.period_begin
self._analysis_conf.period_end_ev_name = args.period_end
self._analysis_conf.period_begin_key_fields = \
- args.period_begin_key.split(',')
+ args.period_begin_key.split(',')
if args.period_end_key:
self._analysis_conf.period_end_key_fields = \
- args.period_end_key.split(',')
+ args.period_end_key.split(',')
else:
self._analysis_conf.period_end_key_fields = \
- self._analysis_conf.period_begin_key_fields
+ self._analysis_conf.period_begin_key_fields
if args.period_key_value:
self._analysis_conf.period_key_value = \
- tuple(args.period_key_value.split(','))
+ tuple(args.period_key_value.split(','))
if args.cpu:
self._analysis_conf.cpu_list = args.cpu.split(',')
args.freq_uniform = True
if self._mi_mode:
- # force no progress in MI mode
- args.no_progress = True
+ # print MI version if required
+ if args.mi_version:
+ print(mi.get_version_string())
+ sys.exit(0)
# print MI metadata if required
if args.metadata:
'CPU IDs')
ap.add_argument('--timerange', type=str, help='time range: '
'[begin,end]')
+ ap.add_argument('--progress-use-size', action='store_true',
+ help='use trace size to approximate progress')
ap.add_argument('-V', '--version', action='version',
version='LTTng Analyses v' + __version__)
# MI mode-dependent arguments
if self._mi_mode:
+ ap.add_argument('--mi-version', action='store_true',
+ help='Print MI version')
ap.add_argument('--metadata', action='store_true',
- help='Show analysis\'s metadata')
+ help='Print analysis\' metadata')
ap.add_argument('path', metavar='<path/to/trace>',
help='trace path', nargs='*')
+ ap.add_argument('--output-progress', action='store_true',
+ help='Print progress indication lines')
else:
ap.add_argument('--no-progress', action='store_true',
help='Don\'t display the progress bar')
self._add_arguments(ap)
args = ap.parse_args()
+
+ if self._mi_mode:
+ args.no_progress = True
+
+ if args.output_progress:
+ args.no_progress = False
+
self._validate_transform_common_args(args)
self._validate_transform_args(args)
self._args = args
pass
def _process_date_args(self):
- def date_to_epoch_nsec(date):
- ts = common.date_to_epoch_nsec(self._handles, date, self._args.gmt)
- if ts is None:
- self._cmdline_error('Invalid date format: "{}"'.format(date))
+ def parse_date(date):
+ try:
+ ts = parse_utils.parse_trace_collection_date(
+ self._traces, date, self._args.gmt
+ )
+ except ValueError as e:
+ self._cmdline_error(str(e))
return ts
- self._args.multi_day = common.is_multi_day_trace_collection(
- self._handles)
+ self._args.multi_day = trace_utils.is_multi_day_trace_collection(
+ self._traces
+ )
begin_ts = None
end_ts = None
if self._args.timerange:
- begin_ts, end_ts = common.extract_timerange(self._handles,
- self._args.timerange,
- self._args.gmt)
- if None in [begin_ts, end_ts]:
- self._cmdline_error(
- 'Invalid time format: "{}"'.format(self._args.timerange))
+ try:
+ begin_ts, end_ts = (
+ parse_utils.parse_trace_collection_time_range(
+ self._traces, self._args.timerange, self._args.gmt
+ )
+ )
+ except ValueError as e:
+ self._cmdline_error(str(e))
else:
if self._args.begin:
- begin_ts = date_to_epoch_nsec(self._args.begin)
+ begin_ts = parse_date(self._args.begin)
if self._args.end:
- end_ts = date_to_epoch_nsec(self._args.end)
+ end_ts = parse_date(self._args.end)
# We have to check if timestamp_begin is None, which
# it always is in older versions of babeltrace. In
# that case, the test is simply skipped and an invalid
# --end value will cause an empty analysis
- if self._traces.timestamp_begin is not None and \
- end_ts < self._traces.timestamp_begin:
+ if self._ts_begin is not None and \
+ end_ts < self._ts_begin:
self._cmdline_error(
'--end timestamp before beginning of trace')