#!/usr/bin/env python # 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 time import sleep import os import re import argparse import pandas as pd import matplotlib.pyplot as plt from android import System from env import TestEnv # Setup target configuration conf = { # Target platform and board "platform" : 'android', # Useful for reading names of little/big cluster # and energy model info, its device specific and use # only if needed for analysis # "board" : 'pixel', # Device # By default the device connected is detected, but if more than 1 # device, override the following to get a specific device. # "device" : "HT66N0300080", # Folder where all the results will be collected "results_dir" : "BinderTransactionTracing", # Define devlib modules to load "modules" : [ 'cpufreq', # enable CPUFreq support 'cpuidle', # enable cpuidle support # 'cgroups' # Enable for cgroup support ], "emeter" : { 'instrument': 'monsoon', 'conf': { } }, "systrace": { 'extra_categories': ['binder_driver'], "extra_events": ["binder_transaction_alloc_buf"], }, # Tools required by the experiments "tools" : [ 'taskset'], "skip_nrg_model" : True, } te = TestEnv(conf, wipe=False) target = te.target def run_page_stats(duration, frequency): procs = {} for i in range(int(duration/frequency)): ss = target.execute("cat /d/binder/stats") proc_dump = re.split("\nproc ", ss)[1:] for proc in proc_dump[1:]: lines = proc.split("\n ") proc_id = lines[0] page = re.search("pages: (\d+:\d+:\d+)", proc) active, lru, free = map(int, page.group(1).split(":")) if proc_id not in procs: procs[proc_id] = {"alloc": [], "lru": []} procs[proc_id]["alloc"].append(active + lru) procs[proc_id]["lru"].append(lru) sleep(frequency) for proc in procs: df = pd.DataFrame(data={"alloc": procs[proc]["alloc"], "lru": procs[proc]["lru"]}) df.plot(title="proc " + proc) plt.show() def experiment(duration_s, cmd, frequency): """ Starts systrace and run a command on target if specified. If no command is given, collect the trace for duration_s seconds. :param duration_s: duration to collect systrace :type duration_s: int :param cmd: command to execute on the target :type cmd: string :param frequency: sampling frequency for page stats :type frequency: float """ systrace_output = System.systrace_start( te, os.path.join(te.res_dir, 'trace.html'), conf=conf) systrace_output.expect("Starting tracing") if frequency: run_page_stats(duration_s, frequency) elif cmd: target.execute(cmd) else: sleep(duration_s) systrace_output.sendline("") System.systrace_wait(te, systrace_output) te.platform_dump(te.res_dir) parser = argparse.ArgumentParser( description="Collect systrace for binder events while executing" "a command on the target or wait for duration_s seconds") parser.add_argument("--duration", "-d", type=int, default=0, help="How long to collect the trace in seconds.") parser.add_argument("--command", "-c", type=str, default="", help="Command to execute on the target.") parser.add_argument("--pagestats", "-p", nargs="?", type=float, default=None, const=0.1, help="Run binder page stats analysis." "Optional argument for sample interval in seconds.") if __name__ == "__main__": args = parser.parse_args() experiment(args.duration, args.command, args.pagestats)