Example #1
0
    def __init__(self, data):
        """
        Constructor for the heat map - initialises the heatmap.

        :param data:
            A generator that returns the data in the section we want to
            display as a heatmap

        """
        # Initialise the base class
        super().__init__(data)

        self.labels = AxesLabels(self.data_options.x_label,
                                 self.data_options.y_label,
                                 self.data_options.x_units,
                                 self.data_options.y_units)

        figure_size = config.get_option_from_section(
            consts.DisplayOptions.HEATMAP.value, "figure_size", typ="float")
        scale = config.get_option_from_section(
            consts.DisplayOptions.HEATMAP.value, "scale", typ="float")
        y_res = config.get_option_from_section(
            consts.DisplayOptions.HEATMAP.value, "y_res", typ="float")
        parameters = GraphParameters(figure_size, scale, y_res)
        normalise = config.get_option_from_section(
            consts.DisplayOptions.HEATMAP.value, "normalised", typ="bool")
        colorbar = "No. of occurrences"
        self.display_options = \
            self.DisplayOptions(colorbar, parameters, normalise)

        self.params = self.display_options.parameters
        self.x_data, self.y_data = self._get_data(
            data.datum_generator, self.display_options.normalise)

        # Get values calculated from data
        self.data_stats = self._get_data_stats()

        # Plot, set viewport, set axes limits
        self.axes, self.figure = self._create_axes()
        self.heatmap, self.image = self._plot_histogram()
        self.pos = self._ViewportPosition(self.data_stats.x_delta,
                                          self.data_stats.y_delta)
        self._set_axes_limits()

        # Add features - colorbar, sliders, annotations
        self._add_colorbar()
        self._create_sliders()
        self._add_annotations()
Example #2
0
    def show(self):
        """
        Calls g2 to show a track separated graph.

        The conversion for the MARPLE format happens here, a new CPEL file being
        created.

        """
        tmp_cpel = str(file.TempFileName())
        g2_path = config.get_option_from_section('g2', 'path')
        g2_path = os.path.expanduser(g2_path)
        logger.info("G2 path: %s", g2_path)

        # We create a generator that yields EventDatum from
        event_generator = self.data.datum_generator
        writer = CpelWriter(event_generator, self.display_options.track)
        writer.write(str(tmp_cpel))

        try:
            subprocess.call([g2_path, "--cpel-input", str(tmp_cpel)])
        except FileNotFoundError as fnfe:
            output.error_(
                "G2 not found at {}. Check your config file?".format(
                    fnfe.filename),
                "Could not find G2 at {}, FileNotFoundError raised. "
                "Change your config file to show the correct G2 path.".format(
                    fnfe.filename))
Example #3
0
def _get_collecter_instance(interface_name, collection_time):
    """
    A helper function that returns an instance of the appropriate interface

    :param interface_name:
        the name of the interface we want an instance of
    :param collection_time:
        the time used as an option for the collecter

    :returns:
        a collecter for the interface

    """
    interfaces = consts.InterfaceTypes
    interface = interfaces(interface_name)

    if interface is interfaces.SCHEDEVENTS:
        collecter = perf.SchedulingEvents(collection_time)
    elif interface is interfaces.DISKLATENCY:
        collecter = iosnoop.DiskLatency(collection_time)
    elif interface is interfaces.TCPTRACE:
        collecter = ebpf.TCPTracer(collection_time)
    elif interface is interfaces.MALLOCSTACKS:
        collecter = ebpf.MallocStacks(collection_time)
    elif interface is interfaces.MEMTIME:
        collecter = smem.MemoryGraph(collection_time)
    elif interface is interfaces.CALLSTACK:
        options = perf.StackTrace.Options(
            config.get_option_from_section(interfaces.CALLSTACK.value,
                                           "frequency", "int"),
            config.get_option_from_section(interfaces.CALLSTACK.value,
                                           "system_wide"))
        collecter = perf.StackTrace(collection_time, options)
    elif interface is interfaces.MEMLEAK:
        options = ebpf.Memleak.Options(
            config.get_option_from_section(interfaces.MEMLEAK.value,
                                           "top_processes", "int"))
        collecter = ebpf.Memleak(collection_time, options)
    elif interface is interfaces.MEMEVENTS:
        collecter = perf.MemoryEvents(collection_time)
    elif interface is interfaces.DISKBLOCK:
        collecter = perf.DiskBlockRequests(collection_time)
    elif interface is interfaces.PERF_MALLOC:
        collecter = perf.MemoryMalloc(collection_time)

    return collecter
Example #4
0
def _select_mode(interface, datatype, args):
    """
    Function that selects the right display mode based on the interface and the
    datatype found in the header

    We first try to see if one of the cmd line arguments matches one of the
    possible display options for :param datatype; if not we try to use the
    option associated with the interface in the config file;
    We have chosen to use the interface and not the datatype so that the user
    can choose a more specific option; it is advisable to only use the config
    file, the args being only used for 'one of' situations

    :param interface:
        the type of the interface that produced the section;
        look at the consts module to see all the possibilities
    :param datatype:
        the datatype of the data in the section;
        look at the consts module to see all the possibilities
    :param args:
        terminal arguments as a dictionary

    :return:
        a `consts.DisplayOptions` specifing the display mode

    """
    # Create the dictionaries used in the selection step
    try:
        datatype_enum = consts.Datatypes(datatype)
    except ValueError as ve:
        raise ValueError("The datatype {} is not supported.".format(datatype)) \
            from ve

    # Determine possible ways to display the datatype
    possibilities = consts.display_dictionary[datatype_enum]

    for option in possibilities:
        # If options specified in the args, then use that option
        if args[option.value]:
            return option

    default = config.get_option_from_section(
        "DisplayInterfaces", interface)

    try:
        default_enum = consts.DisplayOptions(default)
    except ValueError as ve:
        raise ValueError(
            "The default value from the config ({}) was not recognised. "
            "Make sure the config values are within the accepted parameters."
            .format(default)) from ve

    if default_enum in possibilities:
        return consts.DisplayOptions(default_enum)
    else:
        raise ValueError(
            "No valid args or config values found for {}. Either "
            "add an arg in the terminal command or modify the "
            "config file".format(interface))
Example #5
0
    def __init__(self, data):
        """
        Initialise the object.

        :param data:
            A `data_io.EventData` object that encapsulated the collected data
            we want to display using g2.

        """
        # Initialise the base class
        super().__init__(data)

        track = config.get_option_from_section(consts.DisplayOptions.G2.value,
                                               "track")
        self.display_options = self.DisplayOptions(track)
Example #6
0
    def __init__(self, data):
        """
        Constructor for the Treemap.

        :param data:
            A `data_io.StackData` object that encapsulated the collected data
            we want to display using the treemap.

        """
        # Initialise the base class
        super().__init__(data)

        depth = config.get_option_from_section(
            consts.DisplayOptions.TREEMAP.value, "depth", typ="int")
        self.display_options = self.DisplayOptions(depth)
Example #7
0
    def __init__(self, data):
        """
        Initialise the flamegraph.

        :param data:
            A `data_io.StackData` object that encapsulated the collected data
            we want to display as a flamegraph

        """
        # Initialise the base class
        super().__init__(data)

        coloring = config.get_option_from_section(
            consts.DisplayOptions.FLAMEGRAPH.value, "coloring")
        self.display_options = self.DisplayOptions(coloring)
        self.svg_temp_file = str(file.TempFileName())
Example #8
0
def _get_collecters(subcommands, collection_time):
    """
    Calls the relevant functions that user chose and stores output in file.

    :param subcommands:
        The subcommands that tell which collecters to get
    :param collection_time:
        The time for collection


    """
    # Determine all arguments specifying collecter interfaces
    args_seen = set()
    for subcommand in subcommands:
        if subcommand in consts.interfaces_argnames:
            args_seen.add(subcommand)
        else:
            # Check for aliases
            if not config.config.has_option("Aliases", subcommand):
                raise ValueError(
                    'Subcommand or alias {} not valid!'.format(subcommand))
            # Look for aliases
            alias_args = set(
                config.get_option_from_section("Aliases",
                                               subcommand).split(','))
            args_seen = args_seen.union(alias_args)

    collecter_instances = []
    for arg in args_seen:
        try:
            instance = _get_collecter_instance(arg, collection_time)
        except exceptions.NotSupportedException as nse:
            output.error_(
                "Requirement not satisfied", " Subcommand or alias "
                "{} needs kernel version "
                "{} or above!".format(arg, nse.required_kernel))
        else:
            collecter_instances.append(instance)

    return collecter_instances
Example #9
0
    def __init__(self, data):
        """
        Constructor for the StackPlot.

        :param data:
            A `data_io.PointData` object that encapsulated the collected data
            we want to display using the stackplot.

        """
        # Initialise the base class
        super().__init__(data)

        top_processes = config.get_option_from_section(
            consts.DisplayOptions.STACKPLOT.value, "top", typ="int")
        self.display_options = self.DisplayOptions(top_processes)

        # Read the data into a dict
        datapoints = {}
        for point in data.datum_generator:
            if point.x not in datapoints:
                datapoints[point.x] = []
            datapoints[point.x].append((point.y, point.info))

        # Collapse same labels at same x
        self._collapse_labels(datapoints)

        # Set of unique labels that will be displayed
        seen_labels = set()

        # Dict of x-coord to other points not in the top n at that x
        other = {}

        for x in datapoints:
            # Sort tuples at each time step by memory and take top elements
            data_descending = sorted(datapoints[x],
                                     key=lambda z: z[0],
                                     reverse=True)

            # Only keep first n at each time step
            datapoints[x] = data_descending[0:self.display_options.
                                            top_processes]

            # Sum the rest of the values separately, as "other"
            if x not in other:
                try:
                    other[x] = np.sum(
                        z[0] for z in
                        data_descending[self.display_options.top_processes:])
                except IndexError as ie:
                    raise IndexError(
                        "Not enough data to display stackplot "
                        "with {} rows, use smaller number. {}".format(
                            self.display_options.top_processes, ie.args))

            # Keep track of the labels that are in use in top n
            seen_labels = seen_labels.union(set(z[1] for z in datapoints[x]))

        # Insert the missing datapoints
        self._add_missing_datapoints(datapoints, seen_labels)

        # Sort again
        for x in datapoints:
            datapoints[x] = sorted(datapoints[x],
                                   key=lambda z: z[1],
                                   reverse=True)

        y_values_list = []
        # @@@ separate other and tuple_list into different for loops
        for index in range(len(seen_labels) + 1):
            values = []
            for x, tuple_list in datapoints.items():
                if index == 0:
                    values.append(other[x])
                else:
                    values.append(tuple_list[index - 1][0])
            y_values_list.append(values)

        labels_list = ["other"]
        for _, tuple_list in datapoints.items():
            for (_, label) in tuple_list:
                labels_list.append(label)
            break

        # Create the data to be plotted
        self.x_values = sorted(time for time in datapoints)
        self.y_values = np.stack(y_values_list)
        self.labels = labels_list