Android Workloads Experiments


In [1]:
import logging
reload(logging)
log_fmt = '%(asctime)-9s %(levelname)-8s: %(message)s'
logging.basicConfig(format=log_fmt)

# Change to info once the notebook runs ok
logging.getLogger().setLevel(logging.INFO)

In [2]:
%pylab inline

import collections
import copy
import json
import os
import pexpect as pe
from time import sleep

# Support to access the remote target
import devlib
from env import TestEnv

# from devlib.utils.android import adb_command

# Import support for Android devices
from android import Screen, Workload

# Support for trace events analysis
from trace import Trace

# Suport for FTrace events parsing and visualization
import trappy

import datetime


Populating the interactive namespace from numpy and matplotlib

Test Environment set up

Devlib requires the ANDROID_HOME environment variable configured to point to your local installation of the Android SDK. If you have not this variable configured in the shell used to start the notebook server, you need to run the next cell to define where your Android SDK is installed.


In [3]:
# Setup Androd SDK
os.environ['ANDROID_HOME'] = '/home/eas/Work/Android/android-sdk-linux/'

# Setup Catapult for Systrace usage
CATAPULT_HOME = "/home/eas/Work/Android/catapult"

In [4]:
# Android device to target
DEVICE = 'GA0113TP0178'

# Ensure ADB is running as root
!adb -s {DEVICE} root


adbd is already running as root

In case more than one Android device are conencted to the host, you must specify the ID of the device you want to target in my_target_conf. Run adb devices on your host to get the ID.


In [5]:
# Setup target configuration
my_conf = {

    # Target platform and board
    "platform"    : 'android',
    "device"      : DEVICE,

#     "emeter" : {
#         "instrument" : "aep",
#         "conf" : {
#             'labels'          : ['BAT'],
#             'resistor_values' : [0.099],
#             'device_entry'    : '/dev/ttyACM1',
#         }
#     },

    # Folder where all the results will be collected
    "results_dir" : "Android_Workloads",

    # Define devlib modules to load
    "modules"     : [
        'cpufreq'       # enable CPUFreq support
    ],

    # FTrace events to collect for all the tests configuration which have
    # the "ftrace" flag enabled
    "ftrace"  : {
         "events" : [
            "sched_switch",
            "sched_overutilized",
            "sched_contrib_scale_f",
            "sched_load_avg_cpu",
            "sched_load_avg_task",
            "sched_tune_tasks_update",
            "sched_boost_cpu",
            "sched_boost_task",
            "sched_energy_diff",
            "cpu_frequency",
            "cpu_idle",
            "cpu_capacity",
         ],
         "buffsize" : 10 * 1024,
    },

    # Tools required by the experiments
    "tools"   : [ 'trace-cmd' ],
}

In [6]:
# List of configurations to test (keys of 'confs' defined in cell #9)
test_confs = ['std']

# List of workloads to run, each workload consists of a workload name
# followed by a list of workload specific parameters
test_wloads = [
    

    # YouTube workload:
# Params:
# - video URL (with optional start time)
# - duration [s] to playback
    'YouTube   https://youtu.be/XSGBVzeBUbk?t=45s   15',

# Jankbench workload:
# Params:
# - id of the benchmakr to run
    'Jankbench list_view',
#     'Jankbench image_list_view',
#     'Jankbench shadow_grid',
#     'Jankbench low_hitrate_text',
#     'Jankbench high_hitrate_text',
#     'Jankbench edit_text',

]

# Iterations for each test
iterations = 1

In [7]:
# Define what we want to collect as a list of strings.
# Supported values are
#  energy   - Use the my_conf's defined emeter to measure energy consumption across experiments
#  ftrace   - Collect an execution trace using trace-cmd
#  systrace - Collect an execution trace using Systrace/Atrace
# NOTE: energy is automatically enabled in case an "emeter" configuration is defined in my_conf
collect = ''

Support Functions

This set of support functions will help us running the benchmark using different CPUFreq governors.


In [8]:
def set_performance():
    target.cpufreq.set_all_governors('performance')

def set_powersave():
    target.cpufreq.set_all_governors('powersave')

def set_interactive():
    target.cpufreq.set_all_governors('interactive')

def set_sched():
    target.cpufreq.set_all_governors('sched')

def set_ondemand():
    target.cpufreq.set_all_governors('ondemand')
    
    for cpu in target.list_online_cpus():
        tunables = target.cpufreq.get_governor_tunables(cpu)
        target.cpufreq.set_governor_tunables(
            cpu,
            'ondemand',
            **{'sampling_rate' : tunables['sampling_rate_min']}
        )

In [9]:
# Available test configurations
confs = {
     'std' : {
         'label' : 'int',
         'set'   : set_interactive,
     },
     'eas' : {
        'label' : 'sch',
        'set'   :  set_sched,
     }
}

Experiments Execution Function


In [10]:
SYSTRACE_CMD  = CATAPULT_HOME + "/systrace/systrace/systrace.py -e {} -o {} gfx view sched freq idle -t {}"

def experiment(wl, res_dir, conf_name, wload_name, iterations, collect=''):
    
    # Load workload params
    wload_kind = wload_name.split()[0]
    wload_tag = wload_name.split()[1]\
                .replace('https://youtu.be/', '')\
                .replace('?t=', '_')
            
    # Check for workload being available
    wload = Workload.get(te, wload_kind)
    if not wload:
        return {}
    
    # Setup test results folder
    exp_dir = os.path.join(res_dir, conf_name, "{}_{}".format(wload_kind, wload_tag))
    os.system('mkdir -p {}'.format(exp_dir));

    # Configure governor
    confs[conf_name]['set']()
    
    # Configure screen to max brightness and no dimming
    Screen.set_brightness(target, percent=100)
    Screen.set_dim(target, auto=False)
    Screen.set_timeout(target, 60*60*10) # 10 hours should be enought for an experiment
    
    # Start the required tracing command
    if 'ftrace' in collect:
        # Start FTrace and Energy monitoring
        te.ftrace.start()
    elif 'systrace' in collect:
        # Start systrace
        trace_file = os.path.join(exp_dir, 'trace.html')
        trace_cmd = SYSTRACE_CMD.format(DEVICE, trace_file, wload['duration'] * iterations)
        logging.info('SysTrace: %s', trace_cmd)
        systrace_output = pe.spawn(trace_cmd)
    
    ###########################
    # Run the required workload
    
    # Jankbench
    if 'Jankbench' in wload_name:
        db_file, nrg_data, nrg_file = wload.run(exp_dir, wload_tag, iterations, collect)
        
    # YouTube
    elif 'YouTube' in wload_name:
        video_url = wload_name.split()[1]
        video_duration_s = wload_name.split()[2]
        db_file, nrg_data, nrg_file = wload.run(exp_dir, video_url, int(video_duration_s), collect)

    ###########################
    
    # Stop the required trace command
    if 'ftrace' in collect:
        te.ftrace.stop()
        # Collect and keep track of the trace
        trace_file = os.path.join(exp_dir, 'trace.dat')
        te.ftrace.get_trace(trace_file)
    elif 'systrace' in collect:
        logging.info('Waiting systrace report [%s]...', trace_file)
        systrace_output.wait()

    # Reset screen brightness and auto dimming
    Screen.set_defaults(target, )
        
    # Dump platform descriptor
    te.platform_dump(exp_dir)

    # return all the experiment data
    if 'trace' in collect:
        return {
            'dir'             : exp_dir,
            'db_file'         : db_file,
            'nrg_data'        : copy.deepcopy(nrg_data),
            'nrg_file'        : nrg_file,
            'trace_file'      : trace_file,
        }
    else:
        return {
            'dir'             : exp_dir,
            'db_file'         : db_file,
            'nrg_data'        : copy.deepcopy(nrg_data),
            'nrg_file'        : nrg_file,
        }

Main

Target Connection


In [11]:
# # Cleanup Caiman energy meter temporary folders
# !rm -rf /tmp/eprobe-caiman-*
# # Ensure there are not other "caiman" instanced running for the specified device
# # my_conf['emeter']['conf']['device_entry']
# !killall caiman

In [12]:
# Initialize a test environment using:
te = TestEnv(my_conf, wipe=False)
target = te.target


2016-05-10 18:11:10,176 INFO    :         Target - Using base path: /home/derkling/Code/lisa
2016-05-10 18:11:10,177 INFO    :         Target - Loading custom (inline) target configuration
2016-05-10 18:11:10,178 INFO    :         Target - Devlib modules to load: ['cpufreq']
2016-05-10 18:11:10,179 INFO    :         Target - Connecting Android target [GA0113TP0178]
2016-05-10 18:11:11,481 INFO    :         Target - Initializing target workdir:
2016-05-10 18:11:11,482 INFO    :         Target -    /data/local/tmp/devlib-target
2016-05-10 18:11:14,396 INFO    :         Target - Topology:
2016-05-10 18:11:14,397 INFO    :         Target -    [[0, 1], [2, 3]]
2016-05-10 18:11:15,643 WARNING : Event [sched_overutilized] not available for tracing
2016-05-10 18:11:15,645 WARNING : Event [sched_contrib_scale_f] not available for tracing
2016-05-10 18:11:15,647 WARNING : Event [sched_load_avg_cpu] not available for tracing
2016-05-10 18:11:15,648 WARNING : Event [sched_load_avg_task] not available for tracing
2016-05-10 18:11:15,649 WARNING : Event [sched_tune_tasks_update] not available for tracing
2016-05-10 18:11:15,651 WARNING : Event [sched_boost_cpu] not available for tracing
2016-05-10 18:11:15,652 WARNING : Event [sched_boost_task] not available for tracing
2016-05-10 18:11:15,654 WARNING : Event [sched_energy_diff] not available for tracing
2016-05-10 18:11:15,657 WARNING : Event [cpu_capacity] not available for tracing
2016-05-10 18:11:15,657 INFO    :         FTrace - Enabled tracepoints:
2016-05-10 18:11:15,658 INFO    :         FTrace -   sched_switch
2016-05-10 18:11:15,658 INFO    :         FTrace -   sched_overutilized
2016-05-10 18:11:15,659 INFO    :         FTrace -   sched_contrib_scale_f
2016-05-10 18:11:15,660 INFO    :         FTrace -   sched_load_avg_cpu
2016-05-10 18:11:15,660 INFO    :         FTrace -   sched_load_avg_task
2016-05-10 18:11:15,661 INFO    :         FTrace -   sched_tune_tasks_update
2016-05-10 18:11:15,661 INFO    :         FTrace -   sched_boost_cpu
2016-05-10 18:11:15,662 INFO    :         FTrace -   sched_boost_task
2016-05-10 18:11:15,662 INFO    :         FTrace -   sched_energy_diff
2016-05-10 18:11:15,663 INFO    :         FTrace -   cpu_frequency
2016-05-10 18:11:15,664 INFO    :         FTrace -   cpu_idle
2016-05-10 18:11:15,664 INFO    :         FTrace -   cpu_capacity
2016-05-10 18:11:15,665 INFO    :        TestEnv - Set results folder to:
2016-05-10 18:11:15,665 INFO    :        TestEnv -    /home/derkling/Code/lisa/results/Android_Workloads
2016-05-10 18:11:15,666 INFO    :        TestEnv - Experiment results available also in:
2016-05-10 18:11:15,666 INFO    :        TestEnv -    /home/derkling/Code/lisa/results_latest

Workloads Execution and Data Collection


In [13]:
# Unlock device screen (assume no password required)
target.execute('input keyevent 82')

# Intialize Workloads for this test environment
wl = Workload(te)

# The set of results for each comparison test
results = collections.defaultdict(dict)

# Enable energy collection if an emeter has been configured
if 'emeter' in my_conf and te.emeter:
    logging.info('Enabling ENERGY collection')
    collect += ' energy'

# Run the benchmark in all the configured governors
for conf_name in test_confs:

    for idx,wload_name in enumerate(test_wloads):
        
        wload_kind = wload_name.split()[0]
        logging.info('------------------------')
        logging.info('Test %d/%d: %s in %s configuration',
                     idx+1, len(test_wloads), wload_kind.upper(), conf_name.upper())
        res = experiment(wl, te.res_dir, conf_name, wload_name, iterations, collect)
        results[conf_name][wload_name] = res

    # Save collected results
    res_file = os.path.join(te.res_dir, conf_name, 'results.json')
    with open(res_file, 'w') as fh:
        json.dump(results[conf_name], fh, indent=4)


2016-05-10 18:11:17,190 INFO    :       Workload - Workloads available on target:
2016-05-10 18:11:17,192 INFO    :       Workload -   ['YouTube', 'Jankbench']
2016-05-10 18:11:17,193 INFO    : ------------------------
2016-05-10 18:11:17,194 INFO    : Test 1/2: YOUTUBE in STD configuration
2016-05-10 18:11:17,195 INFO    :       Workload - Workloads available on target:
2016-05-10 18:11:17,195 INFO    :       Workload -   ['YouTube', 'Jankbench']
2016-05-10 18:11:18,282 INFO    : Set brightness: 100%
2016-05-10 18:11:18,829 INFO    : Dim screen mode: OFF
2016-05-10 18:11:19,440 INFO    : Screen timeout: 36000 [s]
2016-05-10 18:11:20,631 INFO    : Force manual orientation
2016-05-10 18:11:20,632 INFO    : Set orientation: LANDSCAPE
2016-05-10 18:11:21,776 INFO    : am start -a android.intent.action.VIEW "https://youtu.be/XSGBVzeBUbk?t=45s"
2016-05-10 18:11:25,586 INFO    : Play video for 15 [s]
2016-05-10 18:11:42,883 INFO    : Set orientation: AUTO
2016-05-10 18:11:43,971 INFO    : Set orientation: AUTO
2016-05-10 18:11:45,581 INFO    : Set brightness: AUTO
2016-05-10 18:11:46,153 INFO    : Dim screen mode: ON
2016-05-10 18:11:46,705 INFO    : Screen timeout: 30 [s]
2016-05-10 18:11:46,707 INFO    : ------------------------
2016-05-10 18:11:46,708 INFO    : Test 2/2: JANKBENCH in STD configuration
2016-05-10 18:11:46,708 INFO    :       Workload - Workloads available on target:
2016-05-10 18:11:46,709 INFO    :       Workload -   ['YouTube', 'Jankbench']
2016-05-10 18:11:47,841 INFO    : Set brightness: 100%
2016-05-10 18:11:48,361 INFO    : Dim screen mode: OFF
2016-05-10 18:11:48,971 INFO    : Screen timeout: 36000 [s]
2016-05-10 18:11:51,289 INFO    : Force manual orientation
2016-05-10 18:11:51,290 INFO    : Set orientation: PORTRAIT
2016-05-10 18:11:52,543 INFO    : am start -n "com.android.benchmark/.app.RunLocalBenchmarksActivity" --eia "com.android.benchmark.EXTRA_ENABLED_BENCHMARK_IDS" 0 --ei "com.android.benchmark.EXTRA_RUN_COUNT" 1
2016-05-10 18:11:53,186 INFO    : adb -s GA0113TP0178 logcat ActivityManager:* System.out:I *:S BENCH:*
2016-05-10 18:12:28,308 INFO    :    Mean:  24.202 JankP:   0.061 StdDev:  21.430 Count Bad:    4 Count Jank:    1
2016-05-10 18:12:31,396 INFO    : Set orientation: AUTO
2016-05-10 18:12:32,452 INFO    : Set orientation: AUTO
2016-05-10 18:12:34,180 INFO    : Set brightness: AUTO
2016-05-10 18:12:34,750 INFO    : Dim screen mode: ON
2016-05-10 18:12:35,320 INFO    : Screen timeout: 30 [s]

Energy Measurements Report


In [16]:
for conf_name in test_confs:
    for idx,wload_name in enumerate(test_wloads):
        nrg = 'NaN'
        if results[conf_name][wload_name]['nrg_data']:
            nrg = '{:6.1f}'.format(float(results[conf_name][wload_name]['nrg_data']['BAT']))
        print "Energy consumption {}, {:52}: {}".format(conf_name.upper(), wload_name.upper(), nrg)


Energy consumption STD, YOUTUBE   HTTPS://YOUTU.BE/XSGBVZEBUBK?T=45S   15   : NaN
Energy consumption STD, JANKBENCH LIST_VIEW                                 : NaN