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

Side by Side Diff: telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend.py

Issue 2160793003: Support traces containing all parts/agents returned via DevTools streams (Closed) Base URL: https://chromium.googlesource.com/external/github.com/catapult-project/catapult.git@master
Patch Set: moved _had_data_collected initialization Created 4 years, 4 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
« no previous file with comments | « no previous file | telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import json 5 import json
6 import logging 6 import logging
7 import socket 7 import socket
8 import time 8 import time
9 import traceback 9 import traceback
10 10
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 84
85 class TracingBackend(object): 85 class TracingBackend(object):
86 86
87 _TRACING_DOMAIN = 'Tracing' 87 _TRACING_DOMAIN = 'Tracing'
88 88
89 def __init__(self, inspector_socket, is_tracing_running=False, 89 def __init__(self, inspector_socket, is_tracing_running=False,
90 support_modern_devtools_tracing_start_api=False): 90 support_modern_devtools_tracing_start_api=False):
91 self._inspector_websocket = inspector_socket 91 self._inspector_websocket = inspector_socket
92 self._inspector_websocket.RegisterDomain( 92 self._inspector_websocket.RegisterDomain(
93 self._TRACING_DOMAIN, self._NotificationHandler) 93 self._TRACING_DOMAIN, self._NotificationHandler)
94 self._trace_events = []
95 self._is_tracing_running = is_tracing_running 94 self._is_tracing_running = is_tracing_running
96 self._can_collect_data = False 95 self._can_collect_data = False
97 self._has_received_all_tracing_data = False 96 self._has_received_all_tracing_data = False
97 self._had_data_collected = False
98 self._support_modern_devtools_tracing_start_api = ( 98 self._support_modern_devtools_tracing_start_api = (
99 support_modern_devtools_tracing_start_api) 99 support_modern_devtools_tracing_start_api)
100 self._trace_data_builder = None
100 101
101 @property 102 @property
102 def is_tracing_running(self): 103 def is_tracing_running(self):
103 return self._is_tracing_running 104 return self._is_tracing_running
104 105
105 def StartTracing(self, chrome_trace_config, timeout=10): 106 def StartTracing(self, chrome_trace_config, timeout=10):
106 """When first called, starts tracing, and returns True. 107 """When first called, starts tracing, and returns True.
107 108
108 If called during tracing, tracing is unchanged, and it returns False. 109 If called during tracing, tracing is unchanged, and it returns False.
109 """ 110 """
110 if self.is_tracing_running: 111 if self.is_tracing_running:
111 return False 112 return False
112 assert not self._can_collect_data, 'Data not collected from last trace.' 113 assert not self._can_collect_data, 'Data not collected from last trace.'
113 # Reset collected tracing data from previous tracing calls. 114 # Reset collected tracing data from previous tracing calls.
114 self._trace_events = [] 115 self._had_data_collected = False
115 116
116 if not self.IsTracingSupported(): 117 if not self.IsTracingSupported():
117 raise TracingUnsupportedException( 118 raise TracingUnsupportedException(
118 'Chrome tracing not supported for this app.') 119 'Chrome tracing not supported for this app.')
119 120
120 params = {'transferMode': 'ReturnAsStream'} 121 params = {'transferMode': 'ReturnAsStream'}
121 if self._support_modern_devtools_tracing_start_api: 122 if self._support_modern_devtools_tracing_start_api:
122 params['traceConfig'] = ( 123 params['traceConfig'] = (
123 chrome_trace_config.GetChromeTraceConfigForDevTools()) 124 chrome_trace_config.GetChromeTraceConfigForDevTools())
124 else: 125 else:
(...skipping 28 matching lines...) Expand all
153 if 'error' in rc: 154 if 'error' in rc:
154 raise ClockSyncResponseException(rc['error']['message']) 155 raise ClockSyncResponseException(rc['error']['message'])
155 156
156 def StopTracing(self): 157 def StopTracing(self):
157 """Stops tracing and pushes results to the supplied TraceDataBuilder. 158 """Stops tracing and pushes results to the supplied TraceDataBuilder.
158 159
159 If this is called after tracing has been stopped, trace data from the last 160 If this is called after tracing has been stopped, trace data from the last
160 tracing run is pushed. 161 tracing run is pushed.
161 """ 162 """
162 if not self.is_tracing_running: 163 if not self.is_tracing_running:
163 if not self._trace_events: 164 raise TracingHasNotRunException()
164 raise TracingHasNotRunException()
165 else:
166 req = {'method': 'Tracing.end'}
167 self._inspector_websocket.SendAndIgnoreResponse(req)
168 165
166 req = {'method': 'Tracing.end'}
167 self._inspector_websocket.SendAndIgnoreResponse(req)
169 self._is_tracing_running = False 168 self._is_tracing_running = False
170 self._can_collect_data = True 169 self._can_collect_data = True
171 170
172 def DumpMemory(self, timeout=30): 171 def DumpMemory(self, timeout=30):
173 """Dumps memory. 172 """Dumps memory.
174 173
175 Returns: 174 Returns:
176 GUID of the generated dump if successful, None otherwise. 175 GUID of the generated dump if successful, None otherwise.
177 176
178 Raises: 177 Raises:
(...skipping 26 matching lines...) Expand all
205 raise TracingUnexpectedResponseException( 204 raise TracingUnexpectedResponseException(
206 'Inspector returned unexpected response for ' 205 'Inspector returned unexpected response for '
207 'Tracing.requestMemoryDump:\n' + json.dumps(response, indent=2)) 206 'Tracing.requestMemoryDump:\n' + json.dumps(response, indent=2))
208 207
209 result = response['result'] 208 result = response['result']
210 return result['dumpGuid'] if result['success'] else None 209 return result['dumpGuid'] if result['success'] else None
211 210
212 def CollectTraceData(self, trace_data_builder, timeout=30): 211 def CollectTraceData(self, trace_data_builder, timeout=30):
213 if not self._can_collect_data: 212 if not self._can_collect_data:
214 raise Exception('Cannot collect before tracing is finished.') 213 raise Exception('Cannot collect before tracing is finished.')
215 self._CollectTracingData(timeout) 214 self._CollectTracingData(trace_data_builder, timeout)
216 self._can_collect_data = False 215 self._can_collect_data = False
217 trace_data_builder.AddEventsTo(
218 trace_data_module.CHROME_TRACE_PART, self._trace_events)
219 216
220 def _CollectTracingData(self, timeout): 217 def _CollectTracingData(self, trace_data_builder, timeout):
221 """Collects tracing data. Assumes that Tracing.end has already been sent. 218 """Collects tracing data. Assumes that Tracing.end has already been sent.
222 219
223 Args: 220 Args:
221 trace_data_builder: An instance of TraceDataBuilder to put results into.
224 timeout: The timeout in seconds. 222 timeout: The timeout in seconds.
225 223
226 Raises: 224 Raises:
227 TracingTimeoutException: If more than |timeout| seconds has passed 225 TracingTimeoutException: If more than |timeout| seconds has passed
228 since the last time any data is received. 226 since the last time any data is received.
229 TracingUnrecoverableException: If there is a websocket error. 227 TracingUnrecoverableException: If there is a websocket error.
230 """ 228 """
231 self._has_received_all_tracing_data = False 229 self._has_received_all_tracing_data = False
232 start_time = time.time() 230 start_time = time.time()
233 while True: 231 self._trace_data_builder = trace_data_builder
234 try: 232 try:
235 self._inspector_websocket.DispatchNotifications(timeout) 233 while True:
236 start_time = time.time() 234 try:
237 except websocket.WebSocketTimeoutException: 235 self._inspector_websocket.DispatchNotifications(timeout)
238 pass 236 start_time = time.time()
239 except (socket.error, websocket.WebSocketException): 237 except websocket.WebSocketTimeoutException:
240 raise TracingUnrecoverableException( 238 pass
241 'Exception raised while collecting tracing data:\n' + 239 except (socket.error, websocket.WebSocketException):
242 traceback.format_exc()) 240 raise TracingUnrecoverableException(
241 'Exception raised while collecting tracing data:\n' +
242 traceback.format_exc())
243 243
244 if self._has_received_all_tracing_data: 244 if self._has_received_all_tracing_data:
245 break 245 break
246 246
247 elapsed_time = time.time() - start_time 247 elapsed_time = time.time() - start_time
248 if elapsed_time > timeout: 248 if elapsed_time > timeout:
249 raise TracingTimeoutException( 249 raise TracingTimeoutException(
250 'Only received partial trace data due to timeout after %s seconds. ' 250 'Only received partial trace data due to timeout after %s '
251 'If the trace data is big, you may want to increase the timeout ' 251 'seconds. If the trace data is big, you may want to increase '
252 'amount.' % elapsed_time) 252 'the timeout amount.' % elapsed_time)
253 finally:
254 self._trace_data_builder = None
253 255
254 def _NotificationHandler(self, res): 256 def _NotificationHandler(self, res):
255 if 'Tracing.dataCollected' == res.get('method'): 257 if 'Tracing.dataCollected' == res.get('method'):
256 value = res.get('params', {}).get('value') 258 value = res.get('params', {}).get('value')
257 self._trace_events.extend(value) 259 self._trace_data_builder.AddEventsTo(
260 trace_data_module.CHROME_TRACE_PART, value)
261 self._had_data_collected = True
258 elif 'Tracing.tracingComplete' == res.get('method'): 262 elif 'Tracing.tracingComplete' == res.get('method'):
259 stream_handle = res.get('params', {}).get('stream') 263 stream_handle = res.get('params', {}).get('stream')
260 if not stream_handle: 264 if not stream_handle:
261 self._has_received_all_tracing_data = True 265 self._has_received_all_tracing_data = True
262 return 266 return
263 267 if self._had_data_collected:
Zhen Wang 2016/07/29 14:45:42 So this will never happen? If so, I would suggest
264 if self._trace_events:
265 raise TracingUnexpectedResponseException( 268 raise TracingUnexpectedResponseException(
266 'Got both dataCollected events and a stream from server') 269 'Got both dataCollected events and a stream from server')
267 reader = _DevToolsStreamReader(self._inspector_websocket, stream_handle) 270 reader = _DevToolsStreamReader(self._inspector_websocket, stream_handle)
268 reader.Read(self._ReceivedAllTraceDataFromStream) 271 reader.Read(self._ReceivedAllTraceDataFromStream)
269 272
270 def _ReceivedAllTraceDataFromStream(self, data): 273 def _ReceivedAllTraceDataFromStream(self, data):
271 self._trace_events = json.loads(data) 274 trace = json.loads(data)
275 if type(trace) == dict:
276 for part in trace_data_module.ALL_TRACE_PARTS:
277 field_name = part.raw_field_name
278 if field_name in trace:
279 self._trace_data_builder.AddEventsTo(part, trace[field_name])
280
281 if 'metadata' in trace:
282 self._trace_data_builder.SetMetadataFor(
283 trace_data_module.CHROME_TRACE_PART, trace['metadata'])
284
285 elif type(trace) == list:
286 self._trace_data_builder.AddEventsTo(
287 trace_data_module.CHROME_TRACE_PART, trace)
288 else:
289 raise TracingUnexpectedResponseException('Unexpected trace type')
272 self._has_received_all_tracing_data = True 290 self._has_received_all_tracing_data = True
273 291
274 def Close(self): 292 def Close(self):
275 self._inspector_websocket.UnregisterDomain(self._TRACING_DOMAIN) 293 self._inspector_websocket.UnregisterDomain(self._TRACING_DOMAIN)
276 self._inspector_websocket = None 294 self._inspector_websocket = None
277 295
278 @decorators.Cache 296 @decorators.Cache
279 def IsTracingSupported(self): 297 def IsTracingSupported(self):
280 req = {'method': 'Tracing.hasCompleted'} 298 req = {'method': 'Tracing.hasCompleted'}
281 res = self._inspector_websocket.SyncRequest(req, timeout=10) 299 res = self._inspector_websocket.SyncRequest(req, timeout=10)
282 return not res.get('response') 300 return not res.get('response')
OLDNEW
« no previous file with comments | « no previous file | telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698