Example #1
0
File: base.py Project: rousya/lisa
    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))
Example #2
0
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()