In [1]:
import logging
from conf import LisaLogging
LisaLogging.setup()
# Generate plots inline
%matplotlib inline
import os
Boards specific settings can be collected into a JSON platform description file:
In [2]:
!ls -la $LISA_HOME/libs/utils/platforms/
In [3]:
!cat $LISA_HOME/libs/utils/platforms/hikey.json
In [2]:
# Check which Android devices are available
!adb devices
In [3]:
ADB_DEVICE = '00b43d0b08a8a4b8'
In [6]:
# Unified configuration dictionary
my_conf = {
# Target platform
"platform" : 'android',
# Location of external tools (adb, fastboot, systrace, etc)
# These properties can be used to override the environment variables:
# ANDROID_HOME and CATAPULT_HOME
"ANDROID_HOME" : "/opt/android-sdk-linux",
"CATAPULT_HOME" : "/home/derkling/Code/catapult",
# Boards specific settings can be collected into a JSON
# platform description file, to be placed under:
# LISA_HOME/libs/utils/platforms
"board" : 'hikey',
# If you have multiple Android device connected, here
# we can specify which one to target
"device" : ADB_DEVICE,
# Folder where all the results will be collected
"results_dir" : "ReleaseNotes_v16.09",
}
In [7]:
from env import TestEnv
te = TestEnv(my_conf, force_new=True)
target = te.target
In [8]:
from time import sleep
def sample_energy(energy_meter, time_s):
# Reset the configured energy counters
energy_meter.reset()
# Run the workload you want to measure
#
# In this simple example we just wait some time while the
# energy counters accumulate power samples
sleep(time_s)
# Read and report the measured energy (since last reset)
return energy_meter.report(te.res_dir)
Requirements:
In [15]:
!ls -la /dev/ttyACM*
In [16]:
ACM_DEVICE = '/dev/ttyACM1'
In [17]:
# Energy Meters Configuration for ARM Energy Probe
aep_conf = {
'conf' : {
# Value of the shunt resistor [Ohm] for each channel
'resistor_values' : [0.010],
# Device entry assigned to the probe on the host
'device_entry' : ACM_DEVICE,
},
'channel_map' : {
'BAT' : 'CH0'
}
}
from energy import AEP
ape_em = AEP(target, aep_conf, '/tmp')
In [18]:
nrg_report = sample_energy(ape_em, 2)
print nrg_report
In [19]:
!cat $nrg_report.report_file
In [43]:
my_conf = {
# Configure the energy meter to use
"emeter" : {
# Require usage of an AEP meter
"instrument" : "aep",
# Configuration parameters require by the AEP device
"conf" : {
# Value of the shunt resistor in Ohm
'resistor_values' : [0.099],
# Device entry assigned to the probe on the host
'device_entry' : ACM_DEVICE,
},
# Map AEP's channels to logical names (used to generate reports)
'channel_map' : {
'BAT' : 'CH0'
}
},
# Other target configurations
"platform" : 'android',
"board" : 'hikey',
"device" : ADB_DEVICE,
"results_dir" : "ReleaseNotes_v16.09",
"ANDROID_HOME" : "/opt/android-sdk-linux",
"CATAPULT_HOME" : "/home/derkling/Code/catapult",
}
In [46]:
from env import TestEnv
te = TestEnv(my_conf, force_new=True)
In [ ]:
for i in xrange(1,11):
nrg_report = sample_energy(te.emeter, 1)
nrg_bat = float(nrg_report.channels['BAT'])
print "Sample {:2d}: {:.3f}".format(i, nrg_bat)
Requirements:
In [22]:
!ping -c1 baylibre-acme.local | grep '64 bytes'
In [23]:
# Energy Meters Configuration for BayLibre's ACME
acme_conf = {
"conf" : {
#'iio-capture' : '/usr/bin/iio-capture',
#'ip_address' : 'baylibre-acme.local',
},
"channel_map" : {
"Device0" : 0,
"Device1" : 1,
},
}
from energy import ACME
acme_em = ACME(target, acme_conf, '/tmp')
In [24]:
nrg_report = sample_energy(acme_em, 2)
print nrg_report
In [25]:
!cat $nrg_report.report_file
In [4]:
my_conf = {
# Configure the energy meter to use
"emeter" : {
# Require usage of an AEP meter
"instrument" : "acme",
"conf" : {
#'iio-capture' : '/usr/bin/iio-capture',
#'ip_address' : 'baylibre-acme.local',
},
'channel_map' : {
'Device0' : 0,
'Device1' : 1,
},
},
# Other target configurations
"platform" : 'android',
"board" : 'hikey',
"device" : ADB_DEVICE,
"results_dir" : "ReleaseNotes_v16.09",
"ANDROID_HOME" : "/opt/android-sdk-linux",
"CATAPULT_HOME" : "/home/derkling/Code/catapult",
}
In [5]:
from env import TestEnv
te = TestEnv(my_conf, force_new=True)
target = te.target
In [28]:
for i in xrange(1,11):
nrg_report = sample_energy(te.emeter, 1)
nrg_bat = float(nrg_report.channels['Device1'])
print "Sample {:2d}: {:.3f}".format(i, nrg_bat)
A new Android library has been added which provides APIs to:
- simplify the interaction with a device
- execute interesting workloads and benchmarks
- make it easy the integration of new workloads and benchmarks
Not intended to replace WA, but instead to provide a Python based
programming interface to automate reproducible experiments on
and Android device.
In [6]:
from android import System
print "Supported functions:"
for f in dir(System):
if "__" in f:
continue
print " ", f
Capturing main useful actions, for example:
- ensure we set AIRPLAIN_MODE before measuring scheduler energy
- provide simple support for input actions (relative swipes)
In [34]:
# logging.getLogger().setLevel(logging.DEBUG)
In [ ]:
# Example (use tab to complete)
System.
In [7]:
System.menu(target)
System.back(target)
In [8]:
youtube_apk = System.list_packages(target, 'YouTube')
if youtube_apk:
System.start_app(target, youtube_apk[0])
In [45]:
logging.getLogger().setLevel(logging.INFO)
In [9]:
from android import Screen
print "Supported functions:"
for f in dir(Screen):
if "__" in f:
continue
print " ", f
In [ ]:
# logging.getLogger().setLevel(logging.DEBUG)
In [ ]:
# Example (use TAB to complete)
Screen.
In [10]:
Screen.set_brightness(target, auto=False, percent=100)
In [11]:
Screen.set_orientation(target, auto=False, portrait=False)
In [ ]:
# logging.getLogger().setLevel(logging.INFO)
A simple workload class allows to easily add a wrapper for the exection of a specific Android application.
NOTE: To keep things simple, LISA does not provide APKs installation support.
All the exposes APIs assume that the required packages are already installed
in the target. Whenever a package is missing, LISA reports that and it's up
to the user to install it before using it.
A wrapper class usually requires to specify:
A reproducible experiment should take care of:
Here is an example wrapper which allows to play a YouTube
video for a specified number of seconds:
https://github.com/ARM-software/lisa/blob/master/libs/utils/android/workloads/youtube.py
In [40]:
# logging.getLogger().setLevel(logging.DEBUG)
In [12]:
from android import Workload
# Get the list of available workloads
wloads = Workload(te)
wloads.availables(target)
Out[12]:
In [16]:
yt = Workload.get(te, name='YouTube')
# Playback big bug bunny for 15s starting from 1:20s
video_id = 'XSGBVzeBUbk'
video_url = "https://youtu.be/{}?t={}s".format(video_id, 80)
# Play video and measure energy consumption
results = yt.run(te.res_dir,
video_url, video_duration_s=16,
collect='energy')
In [17]:
results
Out[17]:
In [18]:
framestats = results[0]
!cat $framestats
Android benchmarks can be integrated as standalone Notebook, like for example what we provide for PCMark: https://github.com/ARM-software/lisa/blob/master/ipynb/android/benchmarks/Android_PCMark.ipynb
Alternatively we are adding other benchmarks as predefined Android workloads.
Here is an example of UiBench workload which can run a specified number of tests:
In [19]:
from android import Workload
ui = Workload.get(te, name='UiBench')
# Play video and measure energy consumption
results = ui.run(te.res_dir,
ui.test_GlTextureView,
duration_s=5,
collect='energy')
In [20]:
results
Out[20]:
In [21]:
framestats = results[0]
!cat $framestats
The Trace module is a wrapper around the TRAPpy library which has been updated to:
NOTE: the cells in this sections are required just to create a trace file to be used by the following sections
In [22]:
# The following exanples uses an HiKey board
ADB_DEVICE = '607A87C400055E6E'
In [ ]:
# logging.getLogger().setLevel(logging.DEBUG)
In [23]:
# Unified configuration dictionary
my_conf = {
# Tools required
"tools" : ['rt-app', 'trace-cmd'],
# RTApp calibration
#"modules" : ['cpufreq'],
"rtapp-calib" : {
"0": 254, "1": 252, "2": 252, "3": 251,
"4": 251, "5": 252, "6": 251, "7": 251
},
# FTrace configuration
"ftrace" : {
# Events to trace
"events" : [
"sched_switch",
"sched_wakeup",
"sched_wakeup_new",
"sched_wakeup_tracking",
"sched_stat_wait",
"sched_overutilized",
"sched_contrib_scale_f",
"sched_load_avg_cpu",
"sched_load_avg_task",
"sched_tune_config",
"sched_tune_filter",
"sched_tune_tasks_update",
"sched_tune_boostgroup_update",
"sched_boost_cpu",
"sched_boost_task",
"sched_energy_diff",
"cpu_capacity",
"cpu_frequency",
"cpu_idle",
"walt_update_task_ravg",
"walt_update_history",
"walt_migration_update_sum",
],
# # Kernel functions to profile
# "functions" : [
# "pick_next_task_fair",
# "select_task_rq_fair",
# "enqueue_task_fair",
# "update_curr_fair",
# "dequeue_task_fair",
# ],
# Per-CPU buffer configuration
"buffsize" : 10 * 1024,
},
# Target platform
"platform" : 'android',
"board" : 'hikey',
"device" : ADB_DEVICE,
"results_dir" : "ReleaseNotes_v16.09",
"ANDROID_HOME" : "/opt/android-sdk-linux",
"CATAPULT_HOME" : "/home/derkling/Code/catapult",
}
In [24]:
from env import TestEnv
te = TestEnv(my_conf, force_new=True)
target = te.target
In [25]:
from wlgen import RTA,Ramp
# Let's run a simple RAMP task
rta = RTA(target, 'ramp')
rta.conf(
kind='profile',
params = {
'ramp' : Ramp().get()
}
);
In [26]:
te.ftrace.start()
target.execute("echo 'my_marker: label=START' > /sys/kernel/debug/tracing/trace_marker",
as_root=True)
rta.run(out_dir=te.res_dir)
target.execute("echo 'my_marker: label=STOP' > /sys/kernel/debug/tracing/trace_marker",
as_root=True)
te.ftrace.stop()
trace_file = os.path.join(te.res_dir, 'trace.dat')
te.ftrace.get_trace(trace_file)
In [27]:
from trace import Trace
events_to_parse = my_conf['ftrace']['events']
events_to_parse += ['my_marker']
trace = Trace(trace_file, events_to_parse, te.platform)
In [28]:
trace.available_events
Out[28]:
In [ ]:
# Use TAB to complete
trace.data_frame.
In [30]:
rt_tasks = trace.data_frame.rt_tasks()
rt_tasks.head()
Out[30]:
In [31]:
lat_df = trace.data_frame.latency_df('ramp')
lat_df.head()
Out[31]:
In [32]:
custom_df = trace.data_frame.trace_event('my_marker')
custom_df
Out[32]:
In [33]:
ctxsw_df = trace.data_frame.trace_event('sched_switch')
ctxsw_df.head()
Out[33]:
In [ ]:
# Use TAB to complete
trace.analysis.
In [34]:
trace.analysis.tasks.plotTasks(tasks='ramp',
signals=['util_avg', 'boosted_util',
'sched_overutilized', 'residencies'])
In [35]:
lat_data = trace.analysis.latency.plotLatency('ramp')
In [36]:
lat_data.T
Out[36]:
In [37]:
trace.analysis.frequency.plotClusterFrequencies()
Out[37]:
In [38]:
trace.analysis.frequency.plotClusterFrequencyResidency(pct=True, active=True)
In [39]:
trace.analysis.frequency.plotClusterFrequencyResidency(pct=True, active=False)
Each new API introduced in LISA has an associated notebook which shows a
complete example of its usage.
Examples are usually defined to:
- setup the connection to a target (usually a JUNO board)
- configure a workload (usually using RTApp)
- run workload and collect required measures
- show the most common functions exposed by the new API