1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
8 from telemetry.core import exceptions
9 from telemetry.core.platform import profiler
10 from telemetry.core.platform.profiler import monsoon
13 def _CollectData(output_path, is_collecting):
14 mon = monsoon.Monsoon(wait=False)
15 mon.SetMaxCurrent(2.0)
16 # Note: Telemetry requires the device to be connected by USB, but that
17 # puts it in charging mode. This increases the power consumption.
18 mon.SetUsbPassthrough(1)
19 # Nominal Li-ion voltage is 3.7V, but it puts out 4.2V at max capacity. Use
20 # 4.0V to simulate a "~80%" charged battery. Google "li-ion voltage curve".
21 # This is true only for a single cell. (Most smartphones, some tablets.)
26 mon.StartDataCollection()
27 # Do one CollectData() to make the Monsoon set up, which takes about
28 # 0.3 seconds, and only signal that we've started after that.
31 while is_collecting.is_set():
32 samples += mon.CollectData()
34 mon.StopDataCollection()
37 plot_data = [(i / 5000., sample(0)) for i, sample in enumerate(samples)]
40 with open(output_path, 'w') as output_file:
41 output_writer = csv.writer(output_file)
42 output_writer.writerows(plot_data)
45 print 'To view the Monsoon profile, run:'
46 print (' echo "set datafile separator \',\'; plot \'%s\' with lines" | '
47 'gnuplot --persist' % output_path)
50 class MonsoonProfiler(profiler.Profiler):
51 """Profiler that tracks current using Monsoon Power Monitor.
53 http://www.msoon.com/LabEquipment/PowerMonitor/
54 The Monsoon device measures current in amps at 5000 samples/second.
56 def __init__(self, browser_backend, platform_backend, output_path, state):
57 super(MonsoonProfiler, self).__init__(
58 browser_backend, platform_backend, output_path, state)
59 # We collect the data in a separate process, so we can continuously
60 # read the samples from the USB port while running the test.
61 self._is_collecting = multiprocessing.Event()
62 self._collector = multiprocessing.Process(
63 target=_CollectData, args=(output_path, self._is_collecting))
64 self._collector.start()
65 if not self._is_collecting.wait(timeout=0.5):
66 self._collector.terminate()
67 raise exceptions.ProfilingException('Failed to start data collection.')
74 def is_supported(cls, browser_type):
76 monsoon.Monsoon(wait=False)
77 except EnvironmentError:
82 def CollectProfile(self):
83 self._is_collecting.clear()
84 self._collector.join()
85 return [self._output_path]