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

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: Updating static methods and fixing test fakes. Created 3 years, 2 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 # pylint: disable=no-self-use
96 def IsConnectionOwner(self):
97 """ Returns whether this agent is a connection owner.
98 """
99 return True
100
101 def SupportsExplicitClockSync(self):
102 """Returns whether this supports explicit clock sync.
103
104 Although Monsoon agent implement the clock sync marker, this is performed
105 explicitly from the trace controller as the Monsoon agent has to immediately
106 reconnect USB afterwards for the other agents to issue clock sync markers
107 and to retrieve data.
108 """
109 return False
110
111 def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
112 # pylint: disable=unused-argument
113 assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
114 'recorded since explicit clock sync is not supported.')
115
116 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
117 def StopCollectionWithClockSync(self, sync_id,
118 did_record_sync_marker_callback):
119 """ Stops the collection of monsoon power data and re-enables USB.
120 Records the time at which collection was stopped so the record at this time
121 can be annotated in the resultant log.
122 """
123 self._sync_id = sync_id
124 sync_trace = trace_time.Now()
125 self._sync_timestamp = time.time()
126 did_record_sync_marker_callback(sync_trace, sync_id)
127
128 # Wait for at least two synchronization periods to allow Monsoon to gather
129 # and flush data. Min wait time is half a second.
130 flush_period = max(self._latency_seconds * 2.0, 0.5)
131 time.sleep(flush_period)
132
133 self._monsoon_wrapper.EndExecution()
134 self._monsoon_wrapper.EnableUSB()
135 self._device.adb.WaitForDevice()
136 return True
137
138 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
139 def StopAgentTracing(self, timeout=None):
140 return True
141
142 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
143 def StartAgentTracing(self, config, timeout=None):
144 # Disable USB pass-through while collecting power samples to prevent adding
145 # USB power to sample data.
146 self._monsoon_wrapper.DisableUSB()
147
148 # Begin a power reading operation.
149 self._result_file = tempfile.TemporaryFile()
150 self._monsoon_wrapper.BeginReadPower(self._frequency, out=self._result_file)
151 self._trace_start = time.time()
152 return True
153
154 @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
155 def GetResults(self, timeout=None):
156 self._result_file.flush()
157 self._result_file.seek(0)
158
159 millivolts = self._voltage * 1000
160
161 # Retrieve the samples that have second-only precision.
162 coarse_samples = ReadSamplesFromFile(
163 self._result_file)
164
165 # Use fixed period to transform samples with whole second precision to
166 # fractional precision.
167 fine_samples = TransformSamplesWithFrequency(
168 coarse_samples, self._frequency)
169
170 # Build a string result for BattOr log (whose format we use).
171 result_builder = StringIO.StringIO()
172 result_builder.write("# BattOr")
173
174 for sample in fine_samples:
175 # For timestamp comparisons, adjust using the monsoon latency.
176 adj_timestamp = sample.Timestamp - self._latency_seconds
177 if adj_timestamp >= self._trace_start:
178 result_builder.write("\n{0:f} {1:f} {2:f}".format(sample.Timestamp *
179 1000.0, sample.Amps * 1000.0, millivolts))
180 if self._sync_timestamp < adj_timestamp:
181 result_builder.write(" <{}>".format(self._sync_id))
182 return trace_result.TraceResult('powerTraceAsString',
183 result_builder.getvalue())
184
185 raise Exception("Failed to find end timestamp in monsoon log.")
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698