/tools/telemetry/telemetry/internal/platform/profiler/monsoon_profiler.py
https://gitlab.com/jonnialva90/iridium-browser · Python · 97 lines · 61 code · 16 blank · 20 comment · 10 complexity · b79afda909de7d766036070790c2b4bc MD5 · raw file
- # Copyright 2013 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Profiler using data collected from a Monsoon power meter.
- http://msoon.com/LabEquipment/PowerMonitor/
- Data collected is a namedtuple of (amps, volts), at 5000 samples/second.
- Output graph plots power in watts over time in seconds.
- """
- import csv
- import multiprocessing
- from telemetry.core import exceptions
- from telemetry.internal.platform import profiler
- from telemetry.internal.platform.profiler import monsoon
- from telemetry.util import statistics
- def _CollectData(output_path, is_collecting):
- mon = monsoon.Monsoon(wait=False)
- # Note: Telemetry requires the device to be connected by USB, but that
- # puts it in charging mode. This increases the power consumption.
- mon.SetUsbPassthrough(1)
- # Nominal Li-ion voltage is 3.7V, but it puts out 4.2V at max capacity. Use
- # 4.0V to simulate a "~80%" charged battery. Google "li-ion voltage curve".
- # This is true only for a single cell. (Most smartphones, some tablets.)
- mon.SetVoltage(4.0)
- samples = []
- try:
- mon.StartDataCollection()
- # Do one CollectData() to make the Monsoon set up, which takes about
- # 0.3 seconds, and only signal that we've started after that.
- mon.CollectData()
- is_collecting.set()
- while is_collecting.is_set():
- samples += mon.CollectData()
- finally:
- mon.StopDataCollection()
- # Add x-axis labels.
- plot_data = [(i / 5000., sample.amps * sample.volts)
- for i, sample in enumerate(samples)]
- # Print data in csv.
- with open(output_path, 'w') as output_file:
- output_writer = csv.writer(output_file)
- output_writer.writerows(plot_data)
- output_file.flush()
- power_samples = [s.amps * s.volts for s in samples]
- print 'Monsoon profile power readings in watts:'
- print ' Total = %f' % statistics.TrapezoidalRule(power_samples, 1/5000.)
- print (' Average = %f' % statistics.ArithmeticMean(power_samples) +
- '+-%f' % statistics.StandardDeviation(power_samples))
- print ' Peak = %f' % max(power_samples)
- print ' Duration = %f' % (len(power_samples) / 5000.)
- print 'To view the Monsoon profile, run:'
- print (' echo "set datafile separator \',\'; plot \'%s\' with lines" | '
- 'gnuplot --persist' % output_path)
- class MonsoonProfiler(profiler.Profiler):
- def __init__(self, browser_backend, platform_backend, output_path, state):
- super(MonsoonProfiler, self).__init__(
- browser_backend, platform_backend, output_path, state)
- # We collect the data in a separate process, so we can continuously
- # read the samples from the USB port while running the test.
- self._is_collecting = multiprocessing.Event()
- self._collector = multiprocessing.Process(
- target=_CollectData, args=(output_path, self._is_collecting))
- self._collector.start()
- if not self._is_collecting.wait(timeout=0.5):
- self._collector.terminate()
- raise exceptions.ProfilingException('Failed to start data collection.')
- @classmethod
- def name(cls):
- return 'monsoon'
- @classmethod
- def is_supported(cls, browser_type):
- try:
- monsoon.Monsoon(wait=False)
- except EnvironmentError:
- return False
- else:
- return True
- def CollectProfile(self):
- self._is_collecting.clear()
- self._collector.join()
- return [self._output_path]