16e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# SPDX-License-Identifier: Apache-2.0
26e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien#
36e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# Copyright (C) 2017, ARM Limited, Google, and contributors.
46e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien#
56e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# Licensed under the Apache License, Version 2.0 (the "License"); you may
66e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# not use this file except in compliance with the License.
76e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# You may obtain a copy of the License at
86e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien#
96e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# http://www.apache.org/licenses/LICENSE-2.0
106e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien#
116e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# Unless required by applicable law or agreed to in writing, software
126e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
136e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
146e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# See the License for the specific language governing permissions and
156e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien# limitations under the License.
166e3604a24925c2ca67f6cf4b3415c0d6c8b80e75Connor O'Brien#
17382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangfrom trace import Trace
18382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangimport pandas as pd
19382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangimport matplotlib.pyplot as plt
20382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangfrom analysis_module import AnalysisModule
21382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
22382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangfrom devlib.utils.misc import memoized
23382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
24382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yangclass BinderTransactionAnalysis(AnalysisModule):
25382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    """
26382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    An analysis wrapper for visualizing binder transactions.
27382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
28382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    This class is currently used to plot transaction buffer
29382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    sizes and queuing delays.
30382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    """
31382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    to_micro_second = 1000000
32382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
33382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    def __init__(self, trace):
34382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
35382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Initialized by the directory that contains systrace output
36382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
37382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param trace: input Trace object
38382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type trace: :mod:`libs.utils.Trace`
39382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
40382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        super(BinderTransactionAnalysis, self).__init__(trace)
41382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
42382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    @memoized
43382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    def _dfg_alloc_df(self):
44382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
45382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Get a dataframe that captures the time spent in a transaction
46382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        allocation and the size of the buffer allocated sorted by time.
47382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
48382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Transaction and transaction_alloc_buf dataframes are joined
49382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        on transaction(debug_id)
50382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
51382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Example of df returned:
52382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        transaction (debug_id) | pid | delta_t | size
53382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
54382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_start = self._dfg_trace_event("binder_transaction")
55382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_start["start_time"] = df_start.index
56382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_end = self._dfg_trace_event("binder_transaction_alloc_buf")
57382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_end["end_time"] = df_end.index
58382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df = pd.merge(df_start, df_end, on="transaction")
59382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df = df[["transaction", "__comm_x", "__pid_x",
60382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                 "start_time", "end_time",
61382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                 "data_size", "offsets_size"]]
62382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df["delta_t"] = (df["end_time"] - df["start_time"]) \
63382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                        * BinderTransactionAnalysis.to_micro_second
64382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df["size"] = df["data_size"] - df["offsets_size"]
65382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df = df.loc[df["__comm_x"] == "binderThroughpu"] \
66382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang             [["transaction", "__pid_x", "delta_t", "size"]].sort("delta_t")
67382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        return df
68382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
69382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    @memoized
70382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    def _dfg_queue_df(self):
71382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
72382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Get a dataframe that captures start time, end time,
73382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        and the delta between when a transaction is issued and
74382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        when it is received by the target.
75382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
76382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Transaction and transaction_received dataframes are joined
77382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        on transaction(debug_id)
78382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
79382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Example df:
80382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        transaction (debug_id) | name | start | end | delta
81382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
82382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_send = self._dfg_trace_event("binder_transaction")
83382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_send["start_time"] = df_send.index
84382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
85382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_recv = self._dfg_trace_event("binder_transaction_received")
86382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_recv["end_time"] = df_recv.index
87382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
88382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df = pd.merge(df_send, df_recv, on="transaction")
89382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df = df[["transaction", "__comm_x", "start_time", "end_time"]]
90382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df["delta_t"] = (df["end_time"] - df["start_time"]) \
91382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                        * BinderTransactionAnalysis.to_micro_second
92382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        return df
93382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
94382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    def plot_samples(self, df, y_axis, xlabel, ylabel,
95382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                     ymin=0, ymax=None, x_axis="index"):
96382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
97382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Generate a plot that features the distribution of y_axis column
98382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        in the given dataframe. x_axis represents the sample points.
99382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
100382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param y_axis: column name of the dataframe we want to plot
101382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type y_axis: str
102382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
103382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param xlabel: label that appears on the plot's x-axis
104382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type xlabel: str
105382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
106382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param ylabel: label that appears on the plot's y-axis
107382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type ylabel: str
108382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
109382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_sorted = df.sort_values(by=y_axis, ascending=True)
110382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_sorted[x_axis] = range(len(df_sorted.index))
111382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_sorted.plot(kind="scatter", x=x_axis, y=y_axis)
112382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax = plt.gca()
113382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax.set_xlabel(xlabel)
114382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax.set_ylabel(ylabel)
115382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax.set_ylim(ymin=ymin)
116382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        if ymax:
117382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang            ax.set_ylim(ymax=ymax)
118382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        plt.show()
119382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
120382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang    def plot_tasks(self, df, threshold, x_axis, y_axis, xlabel, ylabel):
121382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
122382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        Generate a plot that features the tasks whose y_axis column
123382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        in the dataframe is above a certain threshold.
124382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
125382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param x_axis: column name of the dataframe we want to group
126382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        together and use as the x-axis index in the plot
127382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type x_axis: str
128382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
129382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param y_axis: column name of the dataframe we want to plot
130382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type y_axis: str
131382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
132382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param xlabel: label that appears on the plot's x-axis
133382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type xlabel: str
134382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang
135382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :param ylabel: label that appears on the plot's y-axis
136382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        :type ylabel: str
137382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        """
138382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_sorted = df.sort_values(by=y_axis, ascending=False)
139382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_top = df_sorted[df_sorted[y_axis] > threshold]\
140382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang                 .groupby(x_axis).head(1)
141382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        df_top.plot(kind="bar", y=y_axis, x=x_axis)
142382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax = plt.gca()
143382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax.set_xlabel(xlabel)
144382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        ax.set_ylabel(ylabel)
145382239bcd68ea03d3c07ce99062282c28b39a142Sherry Yang        plt.show()
146