1 # SPDX-License-Identifier: Apache-2.0 2 # 3 # Copyright (C) 2017, ARM Limited, Google, and contributors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 # not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 from trace import Trace 18 import pandas as pd 19 import matplotlib.pyplot as plt 20 from analysis_module import AnalysisModule 21 22 from devlib.utils.misc import memoized 23 24 class BinderTransactionAnalysis(AnalysisModule): 25 """ 26 An analysis wrapper for visualizing binder transactions. 27 28 This class is currently used to plot transaction buffer 29 sizes and queuing delays. 30 """ 31 to_micro_second = 1000000 32 33 def __init__(self, trace): 34 """ 35 Initialized by the directory that contains systrace output 36 37 :param trace: input Trace object 38 :type trace: :mod:`libs.utils.Trace` 39 """ 40 super(BinderTransactionAnalysis, self).__init__(trace) 41 42 @memoized 43 def _dfg_alloc_df(self): 44 """ 45 Get a dataframe that captures the time spent in a transaction 46 allocation and the size of the buffer allocated sorted by time. 47 48 Transaction and transaction_alloc_buf dataframes are joined 49 on transaction(debug_id) 50 51 Example of df returned: 52 transaction (debug_id) | pid | delta_t | size 53 """ 54 df_start = self._dfg_trace_event("binder_transaction") 55 df_start["start_time"] = df_start.index 56 df_end = self._dfg_trace_event("binder_transaction_alloc_buf") 57 df_end["end_time"] = df_end.index 58 df = pd.merge(df_start, df_end, on="transaction") 59 df = df[["transaction", "__comm_x", "__pid_x", 60 "start_time", "end_time", 61 "data_size", "offsets_size"]] 62 df["delta_t"] = (df["end_time"] - df["start_time"]) \ 63 * BinderTransactionAnalysis.to_micro_second 64 df["size"] = df["data_size"] - df["offsets_size"] 65 df = df.loc[df["__comm_x"] == "binderThroughpu"] \ 66 [["transaction", "__pid_x", "delta_t", "size"]].sort("delta_t") 67 return df 68 69 @memoized 70 def _dfg_queue_df(self): 71 """ 72 Get a dataframe that captures start time, end time, 73 and the delta between when a transaction is issued and 74 when it is received by the target. 75 76 Transaction and transaction_received dataframes are joined 77 on transaction(debug_id) 78 79 Example df: 80 transaction (debug_id) | name | start | end | delta 81 """ 82 df_send = self._dfg_trace_event("binder_transaction") 83 df_send["start_time"] = df_send.index 84 85 df_recv = self._dfg_trace_event("binder_transaction_received") 86 df_recv["end_time"] = df_recv.index 87 88 df = pd.merge(df_send, df_recv, on="transaction") 89 df = df[["transaction", "__comm_x", "start_time", "end_time"]] 90 df["delta_t"] = (df["end_time"] - df["start_time"]) \ 91 * BinderTransactionAnalysis.to_micro_second 92 return df 93 94 def plot_samples(self, df, y_axis, xlabel, ylabel, 95 ymin=0, ymax=None, x_axis="index"): 96 """ 97 Generate a plot that features the distribution of y_axis column 98 in the given dataframe. x_axis represents the sample points. 99 100 :param y_axis: column name of the dataframe we want to plot 101 :type y_axis: str 102 103 :param xlabel: label that appears on the plot's x-axis 104 :type xlabel: str 105 106 :param ylabel: label that appears on the plot's y-axis 107 :type ylabel: str 108 """ 109 df_sorted = df.sort_values(by=y_axis, ascending=True) 110 df_sorted[x_axis] = range(len(df_sorted.index)) 111 df_sorted.plot(kind="scatter", x=x_axis, y=y_axis) 112 ax = plt.gca() 113 ax.set_xlabel(xlabel) 114 ax.set_ylabel(ylabel) 115 ax.set_ylim(ymin=ymin) 116 if ymax: 117 ax.set_ylim(ymax=ymax) 118 plt.show() 119 120 def plot_tasks(self, df, threshold, x_axis, y_axis, xlabel, ylabel): 121 """ 122 Generate a plot that features the tasks whose y_axis column 123 in the dataframe is above a certain threshold. 124 125 :param x_axis: column name of the dataframe we want to group 126 together and use as the x-axis index in the plot 127 :type x_axis: str 128 129 :param y_axis: column name of the dataframe we want to plot 130 :type y_axis: str 131 132 :param xlabel: label that appears on the plot's x-axis 133 :type xlabel: str 134 135 :param ylabel: label that appears on the plot's y-axis 136 :type ylabel: str 137 """ 138 df_sorted = df.sort_values(by=y_axis, ascending=False) 139 df_top = df_sorted[df_sorted[y_axis] > threshold]\ 140 .groupby(x_axis).head(1) 141 df_top.plot(kind="bar", y=y_axis, x=x_axis) 142 ax = plt.gca() 143 ax.set_xlabel(xlabel) 144 ax.set_ylabel(ylabel) 145 plt.show() 146