#!/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)