Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: systrace/systrace/tracing_agents/monsoon_agent.py

Issue 3018533002: Implementing a Monsoon power monitor trace agent, utilizing the UI infrastructure that the BattOr a…
Patch Set: Fixing test failures. Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2017 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.
4
5 import optparse
6 import py_utils
7 import StringIO
8 import tempfile
9 import time
10
11 from devil.android.device_utils import DeviceUtils
12 from py_trace_event import trace_time
13 from systrace import tracing_agents
14 from systrace import trace_result
15 from monsoon.monsoon_wrapper import MonsoonWrapper # pylint: disable=import-erro r
16 from monsoon.monsoon_utils import ReadSamplesFromFile # pylint: disable=import-e rror
17 from monsoon.monsoon_utils import TransformSamplesWithFrequency # pylint: disabl e=import-error
18
19
20 class MonsoonConfig(tracing_agents.TracingConfig):
21 def __init__(self, monsoon, frequency, latency_ms, device_serial_number):
22 tracing_agents.TracingConfig.__init__(self)
23 self.monsoon = monsoon
24 self.frequency = frequency
25 self.latency_ms = latency_ms
26 self.device_serial_number = device_serial_number
27
28 def add_options(parser):
29 options = optparse.OptionGroup(parser, 'Monsoon trace options')
30 options.add_option('--monsoon', dest='monsoon', default=None,
31 action='store', help='Path to monsoon controller script.')
32 options.add_option('--monsoon_freq', dest='freq', default=10,
33 action='store', help='Frequency of power monitoring in '+
34 'hertz. Default is 10.')
35 # The default latency value here has been arrived at by empirical measurement.
36 # There is latency, it just may vary from machine to machine, depend on USB
37 # hubs between device and host, USB bus contention, etc. If higher accuracy
38 # is required it should be up to the user to determine their Monsoon power
39 # latency for their local setup and use this parameter to override the
40 # default.
41 options.add_option('--monsoon_latency', dest='latency_ms', default=3.5,
42 action='store', help='Latency of monsoon power measurement'+
43 ' in milliseconds. Value varies depending upon host ' +
44 'configuration and Monsoon device. Default is 3.5ms.')
45 return options
46
47 def get_config(options):
48 return MonsoonConfig(
49 options.monsoon, int(options.freq), options.latency_ms,
50 options.device_serial_number)
51
52 def try_create_agent(config):
53 """Create a Monsoon power monitor agent.
54 Retrieves voltage from the Monsoon device with USB disabled. BattOr logs
55 include voltage which changes constantly. In comparison, Monsoon is a constant
56 voltage source whose voltage only needs to be queried once.
57
58 Args:
59 config: Command line config.
60 """
61 if type(config.monsoon) is not str:
62 return None
63
64 device = DeviceUtils(config.device_serial_number)
65 monsoon_wrapper = MonsoonWrapper(config.monsoon)
66
67 # Read the status values while USB is disconnected, reconnecting afterwards
68 # for other agents to initialize.
69 monsoon_wrapper.DisableUSB()
70 status = monsoon_wrapper.ReadStatusProperties()
71 monsoon_wrapper.EnableUSB()
72 device.adb.WaitForDevice()
73
74 if "voltage1" not in status:
75 raise Exception("Could not read voltage")
76
77 voltage = float(status["voltage1"])
78
79 return MonsoonTracingAgent(monsoon_wrapper, device, voltage,
80 config.latency_ms, config.frequency)
81
82 class MonsoonTracingAgent(tracing_agents.TracingAgent):
83 def __init__(self, monsoon_wrapper, device, voltage, latency_ms, frequency):
84 super(MonsoonTracingAgent, self).__init__()
85 self._monsoon_wrapper = monsoon_wrapper
86 self._device = device
87 self._voltage = voltage
88 self._latency_seconds = latency_ms / 1e3
89 self._frequency = frequency
90 self._sync_id = None
91 self._sync_timestamp = None
92 self._result_file = None
93 self._trace_start = None
94
95 def SupportsExplicitClockSync(self):
96 """Returns whether this supports explicit clock sync.
97
98 Although Monsoon agent implement the clock sync marker, this is performed
99 explicitly from the trace controller as the Monsoon agent has to immediately
100 reconnect USB afterwards for the other agents to issue clock sync markers
101 and to retrieve data.
102 """
103 return False
104
105 def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
106 # pylint: disable=unused-argument
107 assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
108 'recorded since explicit clock sync is not supported.')
109
110 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
111 def StopCollectionWithClockSync(self, sync_id,
112 did_record_sync_marker_callback):
113 """ Stops the collection of monsoon power data and re-enables USB.
114 Records the time at which collection was stopped so the record at this time
115 can be annotated in the resultant log.
116 """
117 self._sync_id = sync_id
118 sync_trace = trace_time.Now()
119 self._sync_timestamp = time.time()
120 did_record_sync_marker_callback(sync_trace, sync_id)
121
122 # Wait for at least two synchronization periods to allow Monsoon to gather
123 # and flush data. Min wait time is half a second.
124 flush_period = max(self._latency_seconds * 2.0, 0.5)
125 time.sleep(flush_period)
126
127 self._monsoon_wrapper.EndExecution()
128 self._monsoon_wrapper.EnableUSB()
129 self._device.adb.WaitForDevice()
130 return True
131
132 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
133 def StopAgentTracing(self, timeout=None):
134 return True
Chris Craik 2017/09/19 18:47:02 can you do the actual stop here? we'd like to avoi
Zhen Wang 2017/09/19 23:53:50 Seem that the actual stopping is done in StopColle
ddeptford 2017/09/20 23:45:58 Unfortunately this is a limitation of the monsoon
135
136 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
137 def StartAgentTracing(self, config, timeout=None):
138 # Disable USB pass-through while collecting power samples to prevent adding
139 # USB power to sample data.
140 self._monsoon_wrapper.DisableUSB()
141
142 # Begin a power reading operation.
143 self._result_file = tempfile.TemporaryFile()
144 self._monsoon_wrapper.BeginReadPower(self._frequency, out=self._result_file)
145 self._trace_start = time.time()
146 return True
147
148 @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
149 def GetResults(self, timeout=None):
150 self._result_file.flush()
151 self._result_file.seek(0)
152
153 millivolts = self._voltage * 1000
154
155 # Retrieve the samples that have second-only precision.
156 coarse_samples = ReadSamplesFromFile(
157 self._result_file)
158
159 # Use fixed period to transform samples with whole second precision to
160 # fractional precision.
161 fine_samples = TransformSamplesWithFrequency(
162 coarse_samples, self._frequency)
163
164 # Build a string result for BattOr log (whose format we use).
165 result_builder = StringIO.StringIO()
166 result_builder.write("# BattOr")
167
168 for sample in fine_samples:
169 # For timestamp comparisons, adjust using the monsoon latency.
170 adj_timestamp = sample.Timestamp - self._latency_seconds
171 if adj_timestamp >= self._trace_start:
172 result_builder.write("\n{0:f} {1:f} {2:f}".format(sample.Timestamp *
173 1000.0, sample.Amps * 1000.0, millivolts))
174 if self._sync_timestamp < adj_timestamp:
175 result_builder.write(" <{}>".format(self._sync_id))
176 return trace_result.TraceResult('powerTraceAsString',
177 result_builder.getvalue())
178
179 raise Exception("Failed to find end timestamp in monsoon log.")
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698