mirror of
https://github.com/ARM-software/devlib.git
synced 2025-02-07 13:40:48 +00:00
Merge pull request #119 from bjackman/monsoon
instrument: Add support for Monsoon Power Monitor
This commit is contained in:
commit
d72049d35b
@ -14,6 +14,7 @@ from devlib.instrument import MEASUREMENT_TYPES, INSTANTANEOUS, CONTINUOUS
|
|||||||
from devlib.instrument.daq import DaqInstrument
|
from devlib.instrument.daq import DaqInstrument
|
||||||
from devlib.instrument.energy_probe import EnergyProbeInstrument
|
from devlib.instrument.energy_probe import EnergyProbeInstrument
|
||||||
from devlib.instrument.hwmon import HwmonInstrument
|
from devlib.instrument.hwmon import HwmonInstrument
|
||||||
|
from devlib.instrument.monsoon import MonsoonInstrument
|
||||||
from devlib.instrument.netstats import NetstatsInstrument
|
from devlib.instrument.netstats import NetstatsInstrument
|
||||||
|
|
||||||
from devlib.trace.ftrace import FtraceCollector
|
from devlib.trace.ftrace import FtraceCollector
|
||||||
|
132
devlib/instrument/monsoon.py
Normal file
132
devlib/instrument/monsoon.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
from devlib.instrument import Instrument, CONTINUOUS, MeasurementsCsv
|
||||||
|
from devlib.exception import HostError
|
||||||
|
from devlib.host import PACKAGE_BIN_DIRECTORY
|
||||||
|
from devlib.utils.misc import which
|
||||||
|
|
||||||
|
INSTALL_INSTRUCTIONS="""
|
||||||
|
MonsoonInstrument requires the monsoon.py tool, available from AOSP:
|
||||||
|
|
||||||
|
https://android.googlesource.com/platform/cts/+/master/tools/utils/monsoon.py
|
||||||
|
|
||||||
|
Download this script and put it in your $PATH (or pass it as the monsoon_bin
|
||||||
|
parameter to MonsoonInstrument). `pip install gflags pyserial` to install the
|
||||||
|
dependencies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class MonsoonInstrument(Instrument):
|
||||||
|
"""Instrument for Monsoon Solutions power monitor
|
||||||
|
|
||||||
|
To use this instrument, you need to install the monsoon.py script available
|
||||||
|
from the Android Open Source Project. As of May 2017 this is under the CTS
|
||||||
|
repository:
|
||||||
|
|
||||||
|
https://android.googlesource.com/platform/cts/+/master/tools/utils/monsoon.py
|
||||||
|
|
||||||
|
Collects power measurements only, from a selection of two channels, the USB
|
||||||
|
passthrough channel and the main output channel.
|
||||||
|
|
||||||
|
:param target: Ignored
|
||||||
|
:param monsoon_bin: Path to monsoon.py executable. If not provided,
|
||||||
|
``$PATH`` is searched.
|
||||||
|
:param tty_device: TTY device to use to communicate with the Power
|
||||||
|
Monitor. If not provided, a sane default is used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
mode = CONTINUOUS
|
||||||
|
|
||||||
|
def __init__(self, target, monsoon_bin=None, tty_device=None):
|
||||||
|
super(MonsoonInstrument, self).__init__(target)
|
||||||
|
self.monsoon_bin = monsoon_bin or which('monsoon.py')
|
||||||
|
if not self.monsoon_bin:
|
||||||
|
raise HostError(INSTALL_INSTRUCTIONS)
|
||||||
|
|
||||||
|
self.tty_device = tty_device
|
||||||
|
|
||||||
|
self.process = None
|
||||||
|
self.output = None
|
||||||
|
|
||||||
|
self.sample_rate_hz = 500
|
||||||
|
self.add_channel('output', 'power')
|
||||||
|
self.add_channel('USB', 'power')
|
||||||
|
|
||||||
|
def reset(self, sites=None, kinds=None, channels=None):
|
||||||
|
super(MonsoonInstrument, self).reset(sites, kinds)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if self.process:
|
||||||
|
self.process.kill()
|
||||||
|
|
||||||
|
cmd = [self.monsoon_bin,
|
||||||
|
'--hz', str(self.sample_rate_hz),
|
||||||
|
'--samples', '-1', # -1 means sample indefinitely
|
||||||
|
'--includeusb']
|
||||||
|
if self.tty_device:
|
||||||
|
cmd += ['--device', self.tty_device]
|
||||||
|
|
||||||
|
self.logger.debug(' '.join(cmd))
|
||||||
|
self.buffer_file = NamedTemporaryFile(prefix='monsoon', delete=False)
|
||||||
|
self.process = Popen(cmd, stdout=self.buffer_file, stderr=PIPE)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
process = self.process
|
||||||
|
self.process = None
|
||||||
|
if not process:
|
||||||
|
raise RuntimeError('Monsoon script not started')
|
||||||
|
|
||||||
|
process.poll()
|
||||||
|
if process.returncode is not None:
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
raise HostError(
|
||||||
|
'Monsoon script exited unexpectedly with exit code {}.\n'
|
||||||
|
'stdout:\n{}\nstderr:\n{}'.format(process.returncode,
|
||||||
|
stdout, stderr))
|
||||||
|
|
||||||
|
process.send_signal(signal.SIGINT)
|
||||||
|
|
||||||
|
stderr = process.stderr.read()
|
||||||
|
|
||||||
|
self.buffer_file.close()
|
||||||
|
with open(self.buffer_file.name) as f:
|
||||||
|
stdout = f.read()
|
||||||
|
os.remove(self.buffer_file.name)
|
||||||
|
self.buffer_file = None
|
||||||
|
|
||||||
|
self.output = (stdout, stderr)
|
||||||
|
|
||||||
|
def get_data(self, outfile):
|
||||||
|
if self.process:
|
||||||
|
raise RuntimeError('`get_data` called before `stop`')
|
||||||
|
|
||||||
|
stdout, stderr = self.output
|
||||||
|
|
||||||
|
with open(outfile, 'wb') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
active_sites = [c.site for c in self.active_channels]
|
||||||
|
|
||||||
|
# Write column headers
|
||||||
|
row = []
|
||||||
|
if 'output' in active_sites:
|
||||||
|
row.append('output_power')
|
||||||
|
if 'USB' in active_sites:
|
||||||
|
row.append('USB_power')
|
||||||
|
writer.writerow(row)
|
||||||
|
|
||||||
|
# Write data
|
||||||
|
for line in stdout.splitlines():
|
||||||
|
# Each output line is a main_output, usb_output measurement pair.
|
||||||
|
# (If our user only requested one channel we still collect both,
|
||||||
|
# and just ignore one of them)
|
||||||
|
output, usb = line.split()
|
||||||
|
row = []
|
||||||
|
if 'output' in active_sites:
|
||||||
|
row.append(output)
|
||||||
|
if 'USB' in active_sites:
|
||||||
|
row.append(usb)
|
||||||
|
writer.writerow(row)
|
||||||
|
|
||||||
|
return MeasurementsCsv(outfile, self.active_channels)
|
Loading…
x
Reference in New Issue
Block a user