# SPDX-License-Identifier: Apache-2.0 # # Copyright (C) 2017, ARM Limited, Google, 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. # from trace import Trace import pandas as pd import matplotlib.pyplot as plt from analysis_module import AnalysisModule from devlib.utils.misc import memoized class BinderTransactionAnalysis(AnalysisModule): """ An analysis wrapper for visualizing binder transactions. This class is currently used to plot transaction buffer sizes and queuing delays. """ to_micro_second = 1000000 def __init__(self, trace): """ Initialized by the directory that contains systrace output :param trace: input Trace object :type trace: :mod:`libs.utils.Trace` """ super(BinderTransactionAnalysis, self).__init__(trace) @memoized def _dfg_alloc_df(self): """ Get a dataframe that captures the time spent in a transaction allocation and the size of the buffer allocated sorted by time. Transaction and transaction_alloc_buf dataframes are joined on transaction(debug_id) Example of df returned: transaction (debug_id) | pid | delta_t | size """ df_start = self._dfg_trace_event("binder_transaction") df_start["start_time"] = df_start.index df_end = self._dfg_trace_event("binder_transaction_alloc_buf") df_end["end_time"] = df_end.index df = pd.merge(df_start, df_end, on="transaction") df = df[["transaction", "__comm_x", "__pid_x", "start_time", "end_time", "data_size", "offsets_size"]] df["delta_t"] = (df["end_time"] - df["start_time"]) \ * BinderTransactionAnalysis.to_micro_second df["size"] = df["data_size"] - df["offsets_size"] df = df.loc[df["__comm_x"] == "binderThroughpu"] \ [["transaction", "__pid_x", "delta_t", "size"]].sort("delta_t") return df @memoized def _dfg_queue_df(self): """ Get a dataframe that captures start time, end time, and the delta between when a transaction is issued and when it is received by the target. Transaction and transaction_received dataframes are joined on transaction(debug_id) Example df: transaction (debug_id) | name | start | end | delta """ df_send = self._dfg_trace_event("binder_transaction") df_send["start_time"] = df_send.index df_recv = self._dfg_trace_event("binder_transaction_received") df_recv["end_time"] = df_recv.index df = pd.merge(df_send, df_recv, on="transaction") df = df[["transaction", "__comm_x", "start_time", "end_time"]] df["delta_t"] = (df["end_time"] - df["start_time"]) \ * BinderTransactionAnalysis.to_micro_second return df def plot_samples(self, df, y_axis, xlabel, ylabel, ymin=0, ymax=None, x_axis="index"): """ Generate a plot that features the distribution of y_axis column in the given dataframe. x_axis represents the sample points. :param y_axis: column name of the dataframe we want to plot :type y_axis: str :param xlabel: label that appears on the plot's x-axis :type xlabel: str :param ylabel: label that appears on the plot's y-axis :type ylabel: str """ df_sorted = df.sort_values(by=y_axis, ascending=True) df_sorted[x_axis] = range(len(df_sorted.index)) df_sorted.plot(kind="scatter", x=x_axis, y=y_axis) ax = plt.gca() ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_ylim(ymin=ymin) if ymax: ax.set_ylim(ymax=ymax) plt.show() def plot_tasks(self, df, threshold, x_axis, y_axis, xlabel, ylabel): """ Generate a plot that features the tasks whose y_axis column in the dataframe is above a certain threshold. :param x_axis: column name of the dataframe we want to group together and use as the x-axis index in the plot :type x_axis: str :param y_axis: column name of the dataframe we want to plot :type y_axis: str :param xlabel: label that appears on the plot's x-axis :type xlabel: str :param ylabel: label that appears on the plot's y-axis :type ylabel: str """ df_sorted = df.sort_values(by=y_axis, ascending=False) df_top = df_sorted[df_sorted[y_axis] > threshold]\ .groupby(x_axis).head(1) df_top.plot(kind="bar", y=y_axis, x=x_axis) ax = plt.gca() ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) plt.show()