def get_trace(self, **kwargs): """ :returns: a :class:`lisa.trace.TraceView` cropped to fit the ``rt-app`` tasks. :Keyword arguments: forwarded to :class:`lisa.trace.Trace`. """ trace = Trace(self.trace_path, self.plat_info, **kwargs) return trace.get_view(self.trace_window(trace))
def main(argv=None): if argv is None: argv = sys.argv[1:] plots_map = get_plots_map() analysis_nice_name_map = { get_analysis_nice_name(name): name for name in plots_map.keys() } parser = argparse.ArgumentParser( description=""" CLI for LISA analysis plots and reports from traces. Available plots: {} """.format(get_analysis_listing(plots_map)), formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( 'trace', help='trace-cmd trace.dat, or systrace file', ) parser.add_argument( '--normalize-time', action='store_true', help= 'Normalize the time in the plot, i.e. start at 0 instead of uptime timestamp', ) parser.add_argument( '--plot', nargs=2, action='append', default=[], metavar=('PLOT', 'OUTPUT_PATH'), help= 'Create the given plot. If OUTPUT_PATH is "interactive", an interactive window will be used', ) parser.add_argument( '--plot-analysis', nargs=3, action='append', default=[], metavar=('ANALYSIS', 'OUTPUT_FOLDER_PATH', 'FORMAT'), help='Create all the plots of the given analysis', ) parser.add_argument( '--plot-all', nargs=2, metavar=('OUTPUT_FOLDER_PATH', 'FORMAT'), help='Create all the plots in the given folder', ) parser.add_argument( '--best-effort', action='store_true', help= 'Try to generate as many of the requested plots as possible without early termination.', ) parser.add_argument( '--window', nargs=2, type=float, metavar=('BEGIN', 'END'), help='Only plot data between BEGIN and END times', ) parser.add_argument( '-X', '--option', nargs=2, action='append', default=[], metavar=('OPTION_NAME', 'VALUE'), help= 'Pass extra parameters to plot methods, e.g. "-X cpu 1". Mismatching names are ignored.', ) parser.add_argument( '--matplotlib-backend', default='GTK3Agg', help='matplotlib backend to use for interactive window', ) parser.add_argument( '--plat-info', help='Platform information, necessary for some plots', ) parser.add_argument( '--xkcd', action='store_true', help='Graphs will look like XKCD plots', ) args = parser.parse_args(argv) flat_plot_map = { plot_name: meth for analysis_name, plot_list in plots_map.items() for plot_name, meth in plot_list.items() } if args.plat_info: plat_info = PlatformInfo.from_yaml_map(args.plat_info) else: plat_info = None if args.plot_all: folder, fmt = args.plot_all plot_analysis_spec_list = [(get_analysis_nice_name(analysis_name), folder, fmt) for analysis_name in plots_map.keys()] else: plot_analysis_spec_list = [] plot_analysis_spec_list.extend(args.plot_analysis) plot_spec_list = [(plot_name, os.path.join(folder, '{}.{}'.format(plot_name, fmt))) for analysis_name, folder, fmt in plot_analysis_spec_list for plot_name, meth in plots_map[ analysis_nice_name_map[analysis_name]].items()] plot_spec_list.extend(args.plot) # Build minimal event list to speed up trace loading time plot_methods = set() for plot_name, file_path in plot_spec_list: try: f = flat_plot_map[plot_name] except KeyError: error('Unknown plot "{}", see --help'.format(plot_name)) plot_methods.add(f) # If best effort is used, we don't want to trigger exceptions ahead of # time. Let it fail for individual plot methods instead, so the trace can # be used for the other events if args.best_effort: events = None else: events = set() for f in plot_methods: with contextlib.suppress(AttributeError): events.update(f.used_events.get_all_events()) events = sorted(events) print('Parsing trace events: {}'.format(', '.join(events))) trace = Trace(args.trace, plat_info=plat_info, events=events, normalize_time=args.normalize_time, write_swap=True) if args.window: window = args.window def clip(l, x, r): if x < l: return l elif x > r: return r else: return x window = ( clip(trace.window[0], window[0], trace.window[1]), clip(trace.window[0], window[1], trace.window[1]), ) # There is no overlap between trace and user window, reset to trace # window if window[0] == window[1]: print( 'Window {} does not overlap with trace time range, maybe you forgot --normalize-time ?' .format(tuple(args.window))) window = trace.window trace = trace.get_view(window) for plot_name, file_path in sorted(plot_spec_list): interactive = file_path == 'interactive' f = flat_plot_map[plot_name] if interactive: matplotlib.use(args.matplotlib_backend) file_path = None else: dirname = os.path.dirname(file_path) if dirname: os.makedirs(dirname, exist_ok=True) kwargs = make_plot_kwargs(f, file_path, interactive=interactive, extra_options=args.option) xkcd_cm = plt.xkcd() if args.xkcd else nullcontext() with handle_plot_excep(exit_on_error=not args.best_effort): with xkcd_cm: TraceAnalysisBase.call_on_trace(f, trace, kwargs) if interactive: plt.show()