diff options
Diffstat (limited to 'libs/utils/analysis/binder_transaction_analysis.py')
-rw-r--r-- | libs/utils/analysis/binder_transaction_analysis.py | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/libs/utils/analysis/binder_transaction_analysis.py b/libs/utils/analysis/binder_transaction_analysis.py new file mode 100644 index 0000000..82a0f5f --- /dev/null +++ b/libs/utils/analysis/binder_transaction_analysis.py @@ -0,0 +1,145 @@ +# 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() |