Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 # Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 '''Tracing controller class. This class manages | |
| 8 multiple tracing agents and collects data from all of them. It also | |
| 9 manages the clock sync process. | |
| 10 ''' | |
| 11 | |
| 12 import ast | |
| 13 import tempfile | |
| 14 import uuid | |
| 15 import sys | |
| 16 | |
| 17 import trace_event | |
| 18 from devil.utils import reraiser_thread | |
| 19 from devil.utils import timeout_retry | |
| 20 from systrace.tracing_agents import TracingAgent | |
| 21 from systrace.tracing_agents import TraceResults | |
| 22 | |
| 23 # TODO(alexandermont): Current version of trace viewer does not support | |
| 24 # the controller tracing agent output. Thus we use this variable to | |
| 25 # suppress this tracing agent's output. This should be removed once | |
| 26 # trace viewer is working again. | |
| 27 output_controller_tracing_agent = False | |
|
Zhen Wang
2016/03/30 18:11:16
s/output_controller_tracing_agent/OUTPUT_CONTROLLE
| |
| 28 | |
| 29 class TracingController(TracingAgent): | |
| 30 def __init__(self, options, categories, agents): | |
| 31 """Create tracing controller. | |
| 32 | |
| 33 Create a tracing controller object. Note that the tracing | |
| 34 controller is also a tracing agent. | |
| 35 | |
| 36 Args: | |
| 37 options: Tracing options. | |
| 38 categories: Categories of trace events to record. | |
| 39 agents: List of tracing agents for this controller. | |
| 40 """ | |
| 41 super(TracingController, self).__init__() | |
| 42 self._agents = agents | |
| 43 self._options = options | |
| 44 self._categories = categories | |
| 45 self._trace_in_progress = False | |
| 46 self._clock_sync_markers = [] | |
| 47 self._log_path = None | |
| 48 self._all_results = None | |
| 49 | |
| 50 def _StartAgentTracing_func(self): | |
|
Zhen Wang
2016/03/30 16:14:08
nit: is this name following the style? Why not jus
alexandermont
2016/03/30 19:33:25
Done. Changed to _StartAgentTracingImpl. (Don't wa
| |
| 51 """Start tracing for the controller tracing agent. | |
| 52 | |
| 53 Start tracing for the controller tracing agent. Note that | |
| 54 the tracing controller records the "controller side" | |
| 55 of the clock sync records, and nothing else. | |
| 56 """ | |
| 57 if not trace_event.trace_can_enable(): | |
| 58 raise RuntimeError, ('Cannot enable trace_event;' | |
| 59 ' ensure catapult_base is in PYTHONPATH') | |
| 60 | |
| 61 controller_log_file = tempfile.NamedTemporaryFile(delete=False) | |
| 62 self._log_path = controller_log_file.name | |
| 63 controller_log_file.close() | |
| 64 trace_event.trace_enable(self._log_path) | |
| 65 return True | |
| 66 | |
| 67 def StartAgentTracing(self, options, categories, timeout=10): | |
| 68 # pylint: disable=unused-argument | |
| 69 # don't need the options and categories arguments in this | |
| 70 # case, but including them for consistency with the | |
| 71 # function prototypes for other TracingAgents | |
| 72 return timeout_retry.Run(self._StartAgentTracing_func, | |
| 73 timeout, 1) | |
| 74 | |
| 75 @property | |
| 76 def trace_in_progress(self): | |
| 77 return self._trace_in_progress | |
| 78 | |
| 79 def _StopAgentTracing_func(self): | |
| 80 """Stops tracing for the controller tracing agent. | |
| 81 """ | |
| 82 # pylint: disable=no-self-use | |
| 83 # This function doesn't use self, but making it a member function | |
| 84 # for consistency with the other TracingAgents | |
| 85 trace_event.trace_disable() | |
| 86 return True | |
| 87 | |
| 88 def StopAgentTracing(self, timeout=10): | |
| 89 return timeout_retry.Run(self._StopAgentTracing_func, | |
| 90 timeout, 1) | |
| 91 | |
| 92 def _GetResults_func(self): | |
| 93 """Gets the log output from the controller tracing agent. | |
| 94 | |
| 95 This output only contains the "controller side" of the clock sync records. | |
| 96 """ | |
| 97 if self._trace_in_progress: | |
| 98 raise RuntimeError, 'Cannot get results while trace is in progress' | |
| 99 with open(self._log_path, 'r') as outfile: | |
| 100 result = outfile.read() + ']' | |
| 101 return TraceResults('traceEvents', ast.literal_eval(result)) | |
| 102 | |
| 103 def GetResults(self, timeout=30): | |
| 104 return timeout_retry.Run(self._GetResults_func, | |
| 105 timeout, 1) | |
| 106 | |
| 107 def StartTracing(self): | |
| 108 """Start tracing for all tracing agents. | |
| 109 | |
| 110 This function starts tracing for both the controller tracing agent | |
| 111 and the child tracing agents. | |
| 112 | |
| 113 Returns: | |
| 114 Boolean indicating whether or not the start tracing succeeded | |
| 115 for all agents. | |
| 116 """ | |
| 117 assert not self._trace_in_progress, 'Trace already in progress.' | |
| 118 self._trace_in_progress = True | |
| 119 if not self.StartAgentTracing(self._options, | |
| 120 self._categories, | |
| 121 timeout=self._options.timeout): | |
| 122 print 'Unable to start controller tracing agent.' | |
| 123 return False | |
| 124 succ_agents = [] | |
| 125 for agent in self._agents: | |
| 126 if agent.StartAgentTracing(self._options, | |
| 127 self._categories, | |
| 128 timeout=self._options.timeout): | |
| 129 succ_agents.append(agent) | |
| 130 else: | |
| 131 print 'Agent %s not started.' % str(agent) | |
| 132 na = len(self._agents) | |
| 133 ns = len(succ_agents) | |
| 134 if ns < na: | |
| 135 print 'Warning: Only %d of %d tracing agents started.' % (na, ns) | |
| 136 self._agents = succ_agents | |
| 137 | |
| 138 def StopTracing(self): | |
| 139 """Issue clock sync marker and stop tracing for all tracing agents. | |
| 140 | |
| 141 This function stops both the controller tracing agent | |
| 142 and the child tracing agents. It issues a clock sync marker prior | |
| 143 to stopping tracing. | |
| 144 | |
| 145 Returns: | |
| 146 Boolean indicating whether or not the stop tracing succeeded | |
| 147 for all agents. | |
| 148 """ | |
| 149 assert self._trace_in_progress, 'No trace in progress.' | |
| 150 self._trace_in_progress = False | |
| 151 self._IssueClockSyncMarker() | |
| 152 succ_agents = [] | |
| 153 for agent in self._agents: | |
| 154 if agent.StopAgentTracing(timeout=self._options.timeout): | |
| 155 succ_agents.append(agent) | |
| 156 else: | |
| 157 print 'Agent %s not stopped.' % str(agent) | |
| 158 if not self.StopAgentTracing(timeout=self._options.timeout): | |
| 159 print 'Unable to stop controller tracing agent.' | |
| 160 return False | |
| 161 na = len(self._agents) | |
| 162 ns = len(succ_agents) | |
| 163 if ns < na: | |
| 164 print 'Warning: Only %d of %d tracing agents stopped.' % (na, ns) | |
| 165 self._agents = succ_agents | |
| 166 self._all_results = {} | |
| 167 for agent in self._agents + [self]: | |
| 168 try: | |
| 169 (key, value) = agent.GetResults( | |
| 170 timeout=self._options.collection_timeout) | |
| 171 if key in self._all_results: | |
| 172 print 'Warning: Duplicate tracing agents' | |
| 173 if (agent is not self) or output_controller_tracing_agent: | |
| 174 self._all_results[key] = value | |
| 175 except reraiser_thread.TimeoutError: | |
| 176 print 'Warning: Timeout when getting results.' | |
| 177 except: | |
| 178 print 'Warning: Other exception when getting results:' | |
| 179 print sys.exc_info()[0] | |
| 180 raise | |
| 181 return True | |
| 182 | |
| 183 def SupportsExplicitClockSync(self): | |
| 184 '''Returns whether this supports explicit clock sync. | |
| 185 | |
| 186 Although the tracing controller conceptually supports explicit clock | |
| 187 sync, it is not an agent controlled by other controllers so it does not | |
| 188 define RecordClockSyncMarker (rather, the recording of the "controller | |
| 189 side" of the clock sync marker is done in _IssueClockSyncMarker). Thus, | |
| 190 SupportsExplicitClockSync must return false. | |
| 191 ''' | |
| 192 return False | |
| 193 | |
| 194 def RecordClockSyncMarker(self, sync_id, callback): | |
| 195 raise NotImplementedError | |
| 196 | |
| 197 def _IssueClockSyncMarker(self): | |
| 198 """Issue clock sync markers to all the child tracing agents.""" | |
| 199 for agent in self._agents: | |
| 200 if agent.SupportsExplicitClockSync(): | |
| 201 sync_id = GetUniqueSyncID() | |
| 202 callback = lambda t, s: trace_event.clock_sync(s, issue_ts=t) | |
| 203 agent.RecordClockSyncMarker(sync_id, callback) | |
| 204 | |
| 205 def GetUniqueSyncID(): | |
| 206 """Get a unique sync ID. | |
| 207 | |
| 208 Gets a unique sync ID by generating a UUID and converting it to a string | |
| 209 (since UUIDs are not JSON serializable) | |
| 210 """ | |
| 211 return str(uuid.uuid4()) | |
| OLD | NEW |