Source code for lisa.analysis.pixel6

# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2023, ARM Limited and contributors.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import pandas as pd
import holoviews as hv
from holoviews import opts

from lisa.datautils import df_add_delta
from lisa.analysis.base import TraceAnalysisBase
from lisa.trace import requires_events
from lisa.notebook import plot_signal


[docs] class Pixel6Analysis(TraceAnalysisBase): """ Support for Pixel 6-specific data analysis :param trace: input Trace object :type trace: lisa.trace.Trace """ name = 'pixel6' EMETER_CHAN_NAMES = { 'S4M_VDD_CPUCL0': 'CPU-Little', 'S3M_VDD_CPUCL1': 'CPU-Mid', 'S2M_VDD_CPUCL2': 'CPU-Big', 'S2S_VDD_G3D': 'GPU', } ############################################################################### # DataFrame Getter Methods ###############################################################################
[docs] @TraceAnalysisBase.df_method @requires_events('pixel6_emeter') def df_power_meter(self): """ Get the power meter readings across the trace. :retuns: A :class:`pandas.DataFrame` with: * A ``channel`` column (name of the power meter channel) * A ``power`` column (average power usage in mW since the last measurement) """ df = self.trace.df_event('pixel6_emeter') df = df[df['chan_name'].isin(Pixel6Analysis.EMETER_CHAN_NAMES)] grouped = df.groupby('chan_name', observed=True, group_keys=False) def make_chan_df(df): energy_diff = df_add_delta(df, col='energy_diff', src_col='value', window=self.trace.window)['energy_diff'] ts_diff = df_add_delta(df, col='ts_diff', src_col='ts', window=self.trace.window)['ts_diff'] power = energy_diff / ts_diff df = pd.DataFrame(dict(power=power, channel=df['chan_name'])) return df.dropna() df = grouped[df.columns].apply(make_chan_df) df['channel'] = df['channel'].astype('category').cat.rename_categories(Pixel6Analysis.EMETER_CHAN_NAMES) return df
############################################################################### # Plotting methods ###############################################################################
[docs] @TraceAnalysisBase.plot_method @df_power_meter.used_events def plot_power_meter(self, channels=None): """ Plot the power meter readings from various channels. :param channels: List of channels to plot :type channels: list(str) The channels needs to correspond to values in the ``channel`` column of df_power_meter(). """ df = self.df_power_meter() channels = list(channels or df['channel'].unique()) if any(channel not in df['channel'].cat.categories for channel in channels): raise ValueError('Specified channel not found') channel_data = dict(iter(df[df['channel'].isin(channels)].groupby('channel', group_keys=False, observed=True))) return hv.Overlay([ plot_signal(channel_data[channel]['power'], name=channel, vdim=hv.Dimension('power', label='Power', unit='mW')) for channel in channels ]).opts(title='Power usage per channel over time')