예제 #1
0
    def _plot_test_boost(self, df):
        task, = self.rtapp_tasks
        ana = self.trace.ana(
            task=task,
        )

        fig = hv.Layout(
            [
                (
                    plot_signal(df['cost_margin']).options(
                        'Curve',
                        color='red'
                    ) *
                    plot_signal(df['boost_points'].astype(int)).options(
                        'Curve',
                        color='black'
                    ) *
                    plot_signal(df['expected_cost_margin']).options(
                        'Curve',
                        color='blue'
                    ) *
                    plot_signal(df['base_cost']).options(
                        'Curve',
                        color='orange'
                    ) *
                    plot_signal(df['allowed_cost']).options(
                        'Curve',
                        color='green'
                    ) *
                    ana.tasks.plot_tasks_activation(overlay=True)
                ).options(
                    title='Ramp boost for 5% => 75% util step',
                    ylabel='Cost (% of max cost)',
                ),

                ana.frequency.plot_cpu_frequencies(cpu=self.cpu, average=False),

                (
                    ana.load_tracking.plot_task_signals(
                        signals=['util', 'enqueued'],
                        colors=['orange', 'red']
                    ) *
                    ana.tasks.plot_tasks_activation(overlay=True)
                ),
            ]
        ).cols(1)

        self._save_debug_plot(fig, name=f'ramp_boost')
        return fig
예제 #2
0
 def _plot_signal(signal):
     df = self.df_task_signal(task, signal)
     df = df_refit_index(df, window=window)
     return plot_signal(
         df[signal],
         name=signal,
     ).options(dict(Curve=dict(alpha=0.5)), )
예제 #3
0
        def plot_cpu(cpu):
            name = f'CPU{cpu} util'
            series = util_df[cpu].copy(deep=False)
            series.index.name = 'Time'
            series.name = name
            fig = plot_signal(series).options(
                'Curve',
                ylabel='Utilization',
            )

            # The "y" dimension has the name of the series that we plotted
            fig = fig.redim.range(**{name: (-10, 1034)})

            times, utils = zip(*series.items())
            fig *= hv.Overlay([
                hv.VSpan(start, end).options(
                    alpha=0.1,
                    color='grey',
                ) for util, start, end in zip(
                    utils,
                    times,
                    times[1:],
                ) if not util
            ])
            return fig
예제 #4
0
 def plot_capacity(cpu):
     try:
         df = self.df_cpus_signal('capacity', cpus=[cpu])
     except MissingTraceEventError:
         return _hv_neutral()
     else:
         if df.empty:
             return _hv_neutral()
         else:
             return plot_signal(series_refit_index(df['capacity'],
                                                   window=window),
                                name='capacity')
예제 #5
0
    def plot_dev_freq_cooling_states(self, device: str):
        """
        Plot the state evolution of a devfreq cooling device

        :param device: The devfreq devices to consider
        :type device: str
        """
        df = self.df_devfreq_cooling_state([device])
        df = df_refit_index(df, window=self.trace.window)

        return plot_signal(
            df['cdev_state'],
            name=f'Device "{device}"',
        ).options(
            title='devfreq cooling devices status'
        )
예제 #6
0
    def plot_latency(self, task: TaskID):
        """
        Plot the Latency/Slack and Performance data for the specified task.

        :param task: the rt-app task to filter for
        :type task: int or str or lisa.trace.TaskID

        .. seealso:: :meth:`plot_perf` for metrics definition.
        """
        task = self.trace.get_task_id(task)

        return hv.Overlay([
            plot_signal(
                self.df_rtapp_stats(task)[col],
                name=f'{task} {col} (us)',
            ) for col in ('slack', 'wu_lat')
        ]).options(title=f'Task {task} (start) Latency and (completion) Slack')
예제 #7
0
파일: load_tracking.py 프로젝트: credp/lisa
    def _plot_pelt(self, task, signal_name, simulated, test_name):
        ana = self.trace.ana(
            backend='bokeh',
            task=task,
            tasks=[task],
        )

        fig = (
            ana.load_tracking.plot_task_signals(signals=[signal_name]) *
            plot_signal(simulated, name=f'simulated {signal_name}') *
            ana.tasks.plot_tasks_activation(
                alpha=0.2,
                overlay=True,
                which_cpu=False,
                # TODO: reeanble that when we get working twinx
                # duration=True,
            ))

        self._save_debug_plot(fig, name=f'{test_name}_{signal_name}')
        return fig
예제 #8
0
    def _plot_phases(self, test, failures, signal=None):
        task, = self.rtapp_task_ids
        ana = self.trace.ana(
            task=task,
            tasks=[task],
        )
        figs = [
            (ana.tasks.plot_tasks_activation(overlay=True, which_cpu=True) *
             ana.rta.plot_phases(wlgen_profile=self.rtapp_profile) *
             hv.Overlay([
                 hv.HLine(failure).options(alpha=0.5, color='red')
                 for failure in failures
             ])),
        ]
        if signal is not None:
            figs.append(plot_signal(signal))
        fig = hv.Layout(figs).cols(1)

        self._save_debug_plot(fig, name=f'utilclamp_{test}')
        return fig
예제 #9
0
    def plot_perf(self, task: TaskID):
        r"""
        Plot the performance index.

        :param task: the rt-app task to filter for
        :type task: int or str or lisa.trace.TaskID

        The perf index is defined as:

        .. math::

            perf_index = \frac{slack}{c_period - c_run}

        where

            - ``c_period``: is the configured period for an activation
            - ``c_run``: is the configured run time for an activation, assuming to
                        run at the maximum frequency and on the maximum capacity
                        CPU.
            - ``slack``: is the measured slack for an activation

        The slack is defined as the different among the activation deadline
        and the actual completion time of the activation.

        The deadline defines also the start of the next activation, thus in
        normal conditions a task activation is always required to complete
        before its deadline.

        The slack is thus a positive value if a task complete before its
        deadline. It's zero when a task complete an activation right at its
        eadline. It's negative when the completion is over the deadline.

        Thus, a performance index in [0..1] range represents activations
        completed within their deadlines. While, the more the performance index
        is negative the more the task is late with respect to its deadline.
        """
        task = self.trace.get_task_id(task)
        return plot_signal(
            self.df_rtapp_stats(task)['perf_index'],
            name=f'{task} performance index',
        )
예제 #10
0
    def plot_event_field(self,
                         event: str,
                         field: str,
                         filter_columns=None,
                         filter_f=None):
        """
        Plot a signal represented by the filtered values of a field of an event.

        :param event: FTrace event name of interest.
        :type event: str

        :param field: Name of the field of ``event``.
        :type field: str

        :param filter_columns: Pre-filter the dataframe using
            :func:`lisa.datautils.df_filter`. Also, a signal will be inferred
            from the column names being used and will be passed to
            :meth:`lisa.trace.Trace.df_event`.
        :type filter_columns: dict or None

        :param filter_f: Function used to filter the dataframe of the event.
            The function must take a dataframe as only parameter and return
            a filtered dataframe. It is applied after ``filter_columns`` filter.
        :type filter_f: collections.abc.Callable
        """
        trace = self.trace
        if filter_columns:
            signals = [SignalDesc(event, sorted(filter_columns.keys()))]
        else:
            signals = None

        df = trace.df_event(event, signals=signals)

        if filter_columns:
            df = df_filter(df, filter_columns)

        if filter_f:
            df = filter_f(df)

        df = df_refit_index(df, window=trace.window)
        return plot_signal(df[field], name=field)
예제 #11
0
    def plot_cpu_cooling_states(self, cpu: CPU):
        """
        Plot the state evolution of a cpufreq cooling device

        :param cpu: The CPU. Whole clusters can be controlled as
          a single cooling device, they will be plotted as long this CPU
          belongs to the cluster.
        :type cpu: int
        """
        window = self.trace.window

        df = self.df_cpufreq_cooling_state([cpu])
        df = df_refit_index(df, window=window)
        series = series_refit_index(df['cdev_state'], window=window)
        cdev_name = f"CPUs {mask_to_list(df.cpus.unique()[0])}"
        return plot_signal(
            series,
            name=cdev_name,
        ).options(
            title='cpufreq cooling devices status'
        )
예제 #12
0
    def _plot_tasks_X(self, event, name, target_cpus, window, per_sec):
        df = self.trace.df_event(event)

        if target_cpus:
            df = df[df['target_cpu'].isin(target_cpus)]

        series = series_rolling_apply(
            df["target_cpu"],
            lambda x: x.count() / (window if per_sec else 1),
            window,
            window_float_index=False,
            center=True
        )

        if per_sec:
            label = f"Number of task {name} per second ({window}s windows)"
        else:
            label = f"Number of task {name} within {window}s windows"
        series = series_refit_index(series, window=self.trace.window)
        series.name = name
        return plot_signal(series, name=label)
예제 #13
0
파일: frequency.py 프로젝트: credp/lisa
    def plot_cpu_frequencies(self, cpu: CPU, average: bool = True):
        """
        Plot frequency for the specified CPU

        :param cpu: The CPU for which to plot frequencies
        :type cpus: int

        :param average: If ``True``, add a horizontal line which is the
            frequency average.
        :type average: bool

        If ``sched_overutilized`` events are available, the plots will also
        show the intervals of time where the system was overutilized.
        """
        logger = self.logger
        df = self.df_cpu_frequency(cpu)

        if "freqs" in self.trace.plat_info:
            frequencies = self.trace.plat_info['freqs'][cpu]
        else:
            logger.info(f"Estimating CPU{cpu} frequencies from trace")
            frequencies = sorted(list(df.frequency.unique()))
            logger.debug(f"Estimated frequencies: {frequencies}")

        avg = self.get_average_cpu_frequency(cpu)
        logger.info("Average frequency for CPU{} : {:.3f} GHz".format(
            cpu, avg / 1e6))

        df = df_refit_index(df, window=self.trace.window)
        fig = plot_signal(df['frequency'], name=f'Frequency of CPU{cpu} (Hz)')

        if average and avg > 0:
            fig *= hv.HLine(avg, group='average').opts(color='red')

        plot_overutilized = self.ana.status.plot_overutilized
        if self.trace.has_events(plot_overutilized.used_events):
            fig *= plot_overutilized()

        return fig
예제 #14
0
    def plot_thermal_zone_temperature(self, thermal_zone_id: int):
        """
        Plot temperature of thermal zones (all by default)

        :param thermal_zone_id: ID of the zone
        :type thermal_zone_id: int
        """
        window = self.trace.window

        df = self.df_thermal_zones_temperature()
        df = df[df['id'] == thermal_zone_id]
        df = df_refit_index(df, window=window)

        tz_name = df.thermal_zone.unique()[0]

        return plot_signal(
            series_refit_index(df['temp'], window=window),
            name=f'Thermal zone "{tz_name}"',
        ).options(
            title='Temperature evolution',
            ylabel='Temperature (°C.10e3)'
        )
예제 #15
0
        def plot_extra(task, df):
            figs = []
            if duty_cycle:
                figs.append(
                    plot_signal(df['duty_cycle'], name=f'Duty cycle of {task}')
                )

            if duration:
                def plot_duration(active, label):
                    duration_series = df[df['active'] == active]['duration']
                    # Add blanks in the plot when the state is not the one we care about
                    duration_series = duration_series.reindex_like(df)
                    return plot_signal(duration_series, name=f'{label} duration of {task}')

                figs.extend(
                    plot_duration(active, label)
                    for active, label in (
                        (True, 'Activations'),
                        (False, 'Sleep')
                    )
                )

            return figs
예제 #16
0
    def plot_task_required_capacity(self, task: TaskID):
        """
        Plot the minimum required capacity of a task

        :param task: The name or PID of the task, or a tuple ``(pid, comm)``
        :type task: str or int or tuple
        """
        window = self.trace.window

        task_ids = self.trace.get_task_ids(task)
        df = self.df_tasks_signal('required_capacity')
        df = df_filter_task_ids(df, task_ids)
        df = df_refit_index(df, window=window)

        # Build task names (there could be multiple, during the task lifetime)
        task_name = f"Task ({', '.join(map(str, task_ids))})"

        return plot_signal(
            df['required_capacity'],
            name='required_capacity',
        ).options(
            title=f'Required CPU capacity for task {task}',
            ylabel='Utilization',
        )
예제 #17
0
파일: frequency.py 프로젝트: credp/lisa
    def plot_peripheral_frequency(self, clk_name: str, average: bool = True):
        """
        Plot frequency for the specified peripheral clock frequency

        :param clk_name: The clock name for which to plot frequency
        :type clk_name: str

        :param average: If ``True``, add a horizontal line which is the
            frequency average.
        :type average: bool

        """
        df = self.df_peripheral_clock_effective_rate(clk_name)
        freq = df['effective_rate']
        freq = series_refit_index(freq, window=self.trace.window)

        fig = plot_signal(freq, name=f'Frequency of {clk_name} (Hz)')

        if average:
            avg = series_mean(freq)
            if avg > 0:
                fig *= hv.HLine(avg, group='average').opts(color='red')

        return fig
예제 #18
0
 def _plot_signal(cpu, signal):
     df = self.df_cpus_signal(signal, cpus=[cpu])
     df = df_refit_index(df, window=window)
     return plot_signal(df[signal], name=signal).options(
         dict(Curve=dict(alpha=0.5)), )
예제 #19
0
 def plot_duration(active, label):
     duration_series = df[df['active'] == active]['duration']
     # Add blanks in the plot when the state is not the one we care about
     duration_series = duration_series.reindex_like(df)
     return plot_signal(duration_series, name=f'{label} duration of {task}')