NOTE: the monsoon.py tool is required to collect data from the power monitor.
Instructions on how to install it can be found here:
https://github.com/ARM-software/lisa/wiki/Energy-Meters-Requirements#monsoon-power-monitor.
In [1]:
import logging
from conf import LisaLogging
LisaLogging.setup()
In [2]:
# Generate plots inline
%matplotlib inline
import os
# Support to access the remote target
import devlib
from env import TestEnv
# RTApp configurator for generation of PERIODIC tasks
from wlgen import RTA, Ramp
In [3]:
# Let's assume the monsoon binary is installed in the following path
MONSOON_BIN = os.path.join(os.getenv('LISA_HOME'), 'tools', 'scripts', 'monsoon.py')
In [4]:
# Setup target configuration
my_conf = {
# Target platform and board
"platform" : 'android',
"board" : 'wahoo',
# Android tools
"ANDROID_HOME" : "/home/derkling/Code/lisa/tools/android-sdk-linux",
# Folder where all the results will be collected
"results_dir" : "EnergyMeter_Monsoon",
# Define devlib modules to load
"modules" : ["cpufreq"], # Required by rt-app calibration
"exclude_modules" : [ 'hwmon' ],
# Energy Meters Configuration for ARM Energy Probe
"emeter" : {
"instrument" : "monsoon",
"conf" : {
'monsoon_bin' : MONSOON_BIN,
},
},
# Tools required by the experiments
"tools" : [ 'trace-cmd', 'rt-app' ],
# Comment this line to calibrate RTApp in your own platform
# "rtapp-calib" : {"0": 360, "1": 142, "2": 138, "3": 352, "4": 352, "5": 353},
}
In [5]:
# Once powered the Monsoon Power Monitor does not enable the output voltage.
# Since the devlib's API expects that the device is powered and available for
# an ADB connection, let's manually power on the device before initializing the TestEnv
# Power on the device
!$MONSOON_BIN --device /dev/ttyACM1 --voltage 4.2
# Enable USB passthrough to be able to connect the device
!$MONSOON_BIN --usbpassthrough on
In [6]:
# Initialize a test environment using:
te = TestEnv(my_conf, wipe=False, force_new=True)
target = te.target
In [8]:
# If your device support charge via USB, let's disable it in order
# to read the overall power consumption from the main output channel
# For example, this is the API for a Pixel phone:
te.target.write_value('/sys/class/power_supply/battery/charging_enabled', 0)
Detailed information on RTApp can be found in examples/wlgen/rtapp_example.ipynb.
Each EnergyMeter derived class has two main methods: reset and report.
In [9]:
# Create and RTApp RAMP task
rtapp = RTA(te.target, 'ramp', calibration=te.calibration())
rtapp.conf(kind='profile',
params={
'ramp' : Ramp(
start_pct = 60,
end_pct = 20,
delta_pct = 5,
time_s = 0.5).get()
})
# EnergyMeter Start
te.emeter.reset()
rtapp.run(out_dir=te.res_dir)
# EnergyMeter Stop and samples collection
nrg_report = te.emeter.report(te.res_dir)
In [10]:
logging.info("Collected data:")
!tree $te.res_dir
In [11]:
logging.info("Measured channels energy:")
logging.info("%s", nrg_report.channels)
In [12]:
logging.info("Generated energy file:")
logging.info(" %s", nrg_report.report_file)
!cat $nrg_report.report_file
In [13]:
logging.info("Samples collected for the Output and Battery channels (only first 10)")
samples_file = os.path.join(te.res_dir, 'samples.csv')
!head $samples_file
In [14]:
logging.info("DataFrame of collected samples (only first 5)")
nrg_report.data_frame.head()
Out[14]:
In [16]:
logging.info("Plot of collected power samples")
axes = nrg_report.data_frame[('output', 'power')].plot(
figsize=(16,8), drawstyle='steps-post');
axes.set_title('Power samples');
axes.set_xlabel('Time [s]');
axes.set_ylabel('Output power [W]');
In [17]:
logging.info("Plot of collected power samples")
nrg_report.data_frame.describe(percentiles=[0.90, 0.95, 0.99]).T
Out[17]:
In [18]:
logging.info("Power distribution")
axes = nrg_report.data_frame[('output', 'power')].plot(
kind='hist', bins=32,
figsize=(16,8));
axes.set_title('Power Histogram');
axes.set_xlabel('Output power [W] buckets');
axes.set_ylabel('Samples per bucket');