| 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 import logging | 5 import logging |
| 6 | 6 |
| 7 from telemetry.core.backends.chrome import inspector_websocket | 7 from telemetry.core.backends.chrome import inspector_websocket |
| 8 from telemetry.core.platform import tracing_category_filter | |
| 9 from telemetry.core.platform import tracing_options | 8 from telemetry.core.platform import tracing_options |
| 10 | 9 |
| 11 | 10 |
| 12 class TracingUnsupportedException(Exception): | 11 class TracingUnsupportedException(Exception): |
| 13 pass | 12 pass |
| 14 | 13 |
| 15 | 14 |
| 16 class TracingTimeoutException(Exception): | 15 class TracingTimeoutException(Exception): |
| 17 pass | 16 pass |
| 18 | 17 |
| 18 class TracingNotRunningException(Exception): |
| 19 pass |
| 20 |
| 19 | 21 |
| 20 class TracingBackend(object): | 22 class TracingBackend(object): |
| 21 def __init__(self, devtools_port, chrome_browser_backend): | 23 def __init__(self, devtools_port, chrome_browser_backend): |
| 22 self._inspector_websocket = inspector_websocket.InspectorWebsocket( | 24 self._inspector_websocket = inspector_websocket.InspectorWebsocket( |
| 23 self._NotificationHandler, | 25 self._NotificationHandler, |
| 24 self._ErrorHandler) | 26 self._ErrorHandler) |
| 25 | 27 |
| 26 self._inspector_websocket.Connect( | 28 self._inspector_websocket.Connect( |
| 27 'ws://127.0.0.1:%i/devtools/browser' % devtools_port) | 29 'ws://127.0.0.1:%i/devtools/browser' % devtools_port) |
| 28 self._category_filter = None | |
| 29 self._nesting = 0 | |
| 30 self._tracing_data = [] | 30 self._tracing_data = [] |
| 31 self._is_tracing_running = False | 31 self._is_tracing_running = False |
| 32 self._chrome_browser_backend = chrome_browser_backend | 32 self._chrome_browser_backend = chrome_browser_backend |
| 33 | 33 |
| 34 @property | 34 @property |
| 35 def is_tracing_running(self): | 35 def is_tracing_running(self): |
| 36 return self._is_tracing_running | 36 return self._is_tracing_running |
| 37 | 37 |
| 38 def StartTracing(self, trace_options, custom_categories=None, timeout=10): | 38 def StartTracing(self, trace_options, custom_categories=None, timeout=10): |
| 39 """ Starts tracing on the first nested call and returns True. Returns False | 39 """ Starts tracing on the first call and returns True. Returns False |
| 40 and does nothing on subsequent nested calls. | 40 and does nothing on subsequent nested calls. |
| 41 """ | 41 """ |
| 42 self._nesting += 1 | |
| 43 if self.is_tracing_running: | 42 if self.is_tracing_running: |
| 44 new_category_filter = tracing_category_filter.TracingCategoryFilter( | |
| 45 filter_string=custom_categories) | |
| 46 is_subset = new_category_filter.IsSubset(self._category_filter) | |
| 47 assert(is_subset != False) | |
| 48 if is_subset == None: | |
| 49 logging.warning('Cannot determine if category filter of nested ' + | |
| 50 'StartTracing call is subset of current filter.') | |
| 51 return False | 43 return False |
| 52 self._CheckNotificationSupported() | 44 self._CheckNotificationSupported() |
| 53 #TODO(nednguyen): remove this when the stable branch pass 2118. | 45 #TODO(nednguyen): remove this when the stable branch pass 2118. |
| 54 if (trace_options.record_mode == tracing_options.RECORD_AS_MUCH_AS_POSSIBLE | 46 if (trace_options.record_mode == tracing_options.RECORD_AS_MUCH_AS_POSSIBLE |
| 55 and self._chrome_browser_backend.chrome_branch_number | 47 and self._chrome_browser_backend.chrome_branch_number |
| 56 and self._chrome_browser_backend.chrome_branch_number < 2118): | 48 and self._chrome_browser_backend.chrome_branch_number < 2118): |
| 57 logging.warning( | 49 logging.warning( |
| 58 'Cannot use %s tracing mode on chrome browser with branch version %i,' | 50 'Cannot use %s tracing mode on chrome browser with branch version %i,' |
| 59 ' (<2118) fallback to use %s tracing mode' % ( | 51 ' (<2118) fallback to use %s tracing mode' % ( |
| 60 trace_options.record_mode, | 52 trace_options.record_mode, |
| 61 self._chrome_browser_backend.chrome_branch_number, | 53 self._chrome_browser_backend.chrome_branch_number, |
| 62 tracing_options.RECORD_UNTIL_FULL)) | 54 tracing_options.RECORD_UNTIL_FULL)) |
| 63 trace_options.record_mode = tracing_options.RECORD_UNTIL_FULL | 55 trace_options.record_mode = tracing_options.RECORD_UNTIL_FULL |
| 64 req = {'method': 'Tracing.start'} | 56 req = {'method': 'Tracing.start'} |
| 65 req['params'] = {} | 57 req['params'] = {} |
| 66 m = {tracing_options.RECORD_UNTIL_FULL: 'record-until-full', | 58 m = {tracing_options.RECORD_UNTIL_FULL: 'record-until-full', |
| 67 tracing_options.RECORD_AS_MUCH_AS_POSSIBLE: | 59 tracing_options.RECORD_AS_MUCH_AS_POSSIBLE: |
| 68 'record-as-much-as-possible'} | 60 'record-as-much-as-possible'} |
| 69 req['params']['options'] = m[trace_options.record_mode] | 61 req['params']['options'] = m[trace_options.record_mode] |
| 70 self._category_filter = tracing_category_filter.TracingCategoryFilter( | |
| 71 filter_string=custom_categories) | |
| 72 if custom_categories: | 62 if custom_categories: |
| 73 req['params']['categories'] = custom_categories | 63 req['params']['categories'] = custom_categories |
| 74 self._inspector_websocket.SyncRequest(req, timeout) | 64 self._inspector_websocket.SyncRequest(req, timeout) |
| 75 self._is_tracing_running = True | 65 self._is_tracing_running = True |
| 76 return True | 66 return True |
| 77 | 67 |
| 78 def StopTracing(self, timeout=30): | 68 def StopTracing(self, timeout=30): |
| 79 """ Stops tracing on the innermost (!) nested call, because we cannot get | 69 """ Stops tracing and returns the raw json trace result. It this is called |
| 80 results otherwise. Resets _tracing_data on the outermost nested call. | 70 after tracing has been stopped, empty trace data is returned. |
| 81 Returns the result of the trace, as TracingTimelineData object. | |
| 82 """ | 71 """ |
| 83 self._nesting -= 1 | 72 if not self.is_tracing_running: |
| 84 assert self._nesting >= 0 | 73 raise TracingNotRunningException() |
| 85 if self.is_tracing_running: | 74 req = {'method': 'Tracing.end'} |
| 86 req = {'method': 'Tracing.end'} | 75 self._inspector_websocket.SendAndIgnoreResponse(req) |
| 87 self._inspector_websocket.SendAndIgnoreResponse(req) | 76 # After Tracing.end, chrome browser will send asynchronous notifications |
| 88 # After Tracing.end, chrome browser will send asynchronous notifications | 77 # containing trace data. This is until Tracing.tracingComplete is sent, |
| 89 # containing trace data. This is until Tracing.tracingComplete is sent, | 78 # which means there is no trace buffers pending flush. |
| 90 # which means there is no trace buffers pending flush. | 79 try: |
| 91 try: | 80 self._inspector_websocket.DispatchNotificationsUntilDone(timeout) |
| 92 self._inspector_websocket.DispatchNotificationsUntilDone(timeout) | 81 except \ |
| 93 except \ | 82 inspector_websocket.DispatchNotificationsUntilDoneTimeoutException \ |
| 94 inspector_websocket.DispatchNotificationsUntilDoneTimeoutException \ | 83 as err: |
| 95 as err: | 84 raise TracingTimeoutException( |
| 96 raise TracingTimeoutException( | 85 'Trace data was not fully received due to timeout after %s ' |
| 97 'Trace data was not fully received due to timeout after %s ' | 86 'seconds. If the trace data is big, you may want to increase the ' |
| 98 'seconds. If the trace data is big, you may want to increase the ' | 87 'time out amount.' % err.elapsed_time) |
| 99 'time out amount.' % err.elapsed_time) | 88 self._is_tracing_running = False |
| 100 self._is_tracing_running = False | 89 return self._GetTraceResultAndReset() |
| 101 if self._nesting == 0: | |
| 102 self._category_filter = None | |
| 103 return self._GetTraceResultAndReset() | |
| 104 else: | |
| 105 return self._GetTraceResult() | |
| 106 | |
| 107 def _GetTraceResult(self): | |
| 108 assert not self.is_tracing_running | |
| 109 return self._tracing_data | |
| 110 | 90 |
| 111 def _GetTraceResultAndReset(self): | 91 def _GetTraceResultAndReset(self): |
| 112 result = self._GetTraceResult() | 92 result = self._tracing_data |
| 113 | |
| 114 self._tracing_data = [] | 93 self._tracing_data = [] |
| 115 return result | 94 return result |
| 116 | 95 |
| 117 def _ErrorHandler(self, elapsed): | 96 def _ErrorHandler(self, elapsed): |
| 118 logging.error('Unrecoverable error after %ds reading tracing response.', | 97 logging.error('Unrecoverable error after %ds reading tracing response.', |
| 119 elapsed) | 98 elapsed) |
| 120 raise | 99 raise |
| 121 | 100 |
| 122 def _NotificationHandler(self, res): | 101 def _NotificationHandler(self, res): |
| 123 if 'Tracing.dataCollected' == res.get('method'): | 102 if 'Tracing.dataCollected' == res.get('method'): |
| (...skipping 12 matching lines...) Expand all Loading... |
| 136 | 115 |
| 137 def _CheckNotificationSupported(self): | 116 def _CheckNotificationSupported(self): |
| 138 """Ensures we're running against a compatible version of chrome.""" | 117 """Ensures we're running against a compatible version of chrome.""" |
| 139 req = {'method': 'Tracing.hasCompleted'} | 118 req = {'method': 'Tracing.hasCompleted'} |
| 140 res = self._inspector_websocket.SyncRequest(req) | 119 res = self._inspector_websocket.SyncRequest(req) |
| 141 if res.get('response'): | 120 if res.get('response'): |
| 142 raise TracingUnsupportedException( | 121 raise TracingUnsupportedException( |
| 143 'Tracing not supported for this browser') | 122 'Tracing not supported for this browser') |
| 144 elif 'error' in res: | 123 elif 'error' in res: |
| 145 return | 124 return |
| OLD | NEW |