OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Profiler using data collected from a Monsoon power meter. | 5 """Profiler using data collected from a Monsoon power meter. |
6 | 6 |
7 http://msoon.com/LabEquipment/PowerMonitor/ | 7 http://msoon.com/LabEquipment/PowerMonitor/ |
8 Data collected is a namedtuple of (amps, volts), at 5000 samples/second. | 8 Data collected is a namedtuple of (amps, volts), at 5000 samples/second. |
9 Output graph plots power in watts over time in seconds. | 9 Output graph plots power in watts over time in seconds. |
10 """ | 10 """ |
11 | 11 |
12 import csv | 12 import csv |
13 import multiprocessing | 13 import multiprocessing |
14 | 14 |
15 from telemetry.core import exceptions | 15 from telemetry.core import exceptions |
16 from telemetry.core.platform import profiler | 16 from telemetry.core.platform import profiler |
17 from telemetry.core.platform.profiler import monsoon | 17 from telemetry.core.platform.profiler import monsoon |
| 18 from telemetry.util import statistics |
18 | 19 |
19 | 20 |
20 def _CollectData(output_path, is_collecting): | 21 def _CollectData(output_path, is_collecting): |
21 mon = monsoon.Monsoon(wait=False) | 22 mon = monsoon.Monsoon(wait=False) |
22 # Note: Telemetry requires the device to be connected by USB, but that | 23 # Note: Telemetry requires the device to be connected by USB, but that |
23 # puts it in charging mode. This increases the power consumption. | 24 # puts it in charging mode. This increases the power consumption. |
24 mon.SetUsbPassthrough(1) | 25 mon.SetUsbPassthrough(1) |
25 # Nominal Li-ion voltage is 3.7V, but it puts out 4.2V at max capacity. Use | 26 # Nominal Li-ion voltage is 3.7V, but it puts out 4.2V at max capacity. Use |
26 # 4.0V to simulate a "~80%" charged battery. Google "li-ion voltage curve". | 27 # 4.0V to simulate a "~80%" charged battery. Google "li-ion voltage curve". |
27 # This is true only for a single cell. (Most smartphones, some tablets.) | 28 # This is true only for a single cell. (Most smartphones, some tablets.) |
(...skipping 14 matching lines...) Expand all Loading... |
42 # Add x-axis labels. | 43 # Add x-axis labels. |
43 plot_data = [(i / 5000., sample.amps * sample.volts) | 44 plot_data = [(i / 5000., sample.amps * sample.volts) |
44 for i, sample in enumerate(samples)] | 45 for i, sample in enumerate(samples)] |
45 | 46 |
46 # Print data in csv. | 47 # Print data in csv. |
47 with open(output_path, 'w') as output_file: | 48 with open(output_path, 'w') as output_file: |
48 output_writer = csv.writer(output_file) | 49 output_writer = csv.writer(output_file) |
49 output_writer.writerows(plot_data) | 50 output_writer.writerows(plot_data) |
50 output_file.flush() | 51 output_file.flush() |
51 | 52 |
| 53 power_samples = [s.amps * s.volts for s in samples] |
| 54 |
| 55 print 'Monsoon profile power readings in watts:' |
| 56 print (' Total = %f' % statistics.TrapezoidalRule(power_samples, 1/5000.)) |
| 57 print (' Average = %f' % statistics.ArithmeticMean(power_samples) + |
| 58 '+-%f' % statistics.StandardDeviation(power_samples)) |
| 59 print (' Peak = %f' % max(power_samples)) |
| 60 print (' Duration = %f' % (len(power_samples) / 5000.)) |
| 61 |
52 print 'To view the Monsoon profile, run:' | 62 print 'To view the Monsoon profile, run:' |
53 print (' echo "set datafile separator \',\'; plot \'%s\' with lines" | ' | 63 print (' echo "set datafile separator \',\'; plot \'%s\' with lines" | ' |
54 'gnuplot --persist' % output_path) | 64 'gnuplot --persist' % output_path) |
55 | 65 |
56 | 66 |
57 class MonsoonProfiler(profiler.Profiler): | 67 class MonsoonProfiler(profiler.Profiler): |
58 def __init__(self, browser_backend, platform_backend, output_path, state): | 68 def __init__(self, browser_backend, platform_backend, output_path, state): |
59 super(MonsoonProfiler, self).__init__( | 69 super(MonsoonProfiler, self).__init__( |
60 browser_backend, platform_backend, output_path, state) | 70 browser_backend, platform_backend, output_path, state) |
61 # We collect the data in a separate process, so we can continuously | 71 # We collect the data in a separate process, so we can continuously |
(...skipping 16 matching lines...) Expand all Loading... |
78 monsoon.Monsoon(wait=False) | 88 monsoon.Monsoon(wait=False) |
79 except EnvironmentError: | 89 except EnvironmentError: |
80 return False | 90 return False |
81 else: | 91 else: |
82 return True | 92 return True |
83 | 93 |
84 def CollectProfile(self): | 94 def CollectProfile(self): |
85 self._is_collecting.clear() | 95 self._is_collecting.clear() |
86 self._collector.join() | 96 self._collector.join() |
87 return [self._output_path] | 97 return [self._output_path] |
OLD | NEW |