| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 """Monitor tracing events on chrome via chrome remote debugging.""" | 5 """Monitor tracing events on chrome via chrome remote debugging.""" |
| 6 | 6 |
| 7 import bisect | |
| 8 import itertools | 7 import itertools |
| 9 import logging | 8 import logging |
| 10 import operator | 9 import operator |
| 11 | 10 |
| 11 import clovis_constants |
| 12 import devtools_monitor | 12 import devtools_monitor |
| 13 | 13 |
| 14 | 14 |
| 15 QUEUING_CATEGORY = 'disabled-by-default-loading.resource' | |
| 16 _ENABLED_CATEGORIES = ( | |
| 17 ('toplevel', 'blink', 'v8', 'java', 'devtools.timeline', | |
| 18 'blink.user_timing', 'blink.net', 'disabled-by-default-blink.debug.layout') | |
| 19 + (QUEUING_CATEGORY,)) | |
| 20 _DISABLED_CATEGORIES = ('cc',) # Contains a lot of events, none of which we use. | |
| 21 INITIAL_CATEGORIES = ( | |
| 22 _ENABLED_CATEGORIES | |
| 23 + tuple('-' + cat for cat in _DISABLED_CATEGORIES)) | |
| 24 | |
| 25 | |
| 26 class TracingTrack(devtools_monitor.Track): | 15 class TracingTrack(devtools_monitor.Track): |
| 27 """Grabs and processes trace event messages. | 16 """Grabs and processes trace event messages. |
| 28 | 17 |
| 29 See https://goo.gl/Qabkqk for details on the protocol. | 18 See https://goo.gl/Qabkqk for details on the protocol. |
| 30 """ | 19 """ |
| 31 def __init__(self, connection, additional_categories=None, | 20 def __init__(self, connection, categories, fetch_stream=False): |
| 32 disabled_categories=None, | |
| 33 fetch_stream=False): | |
| 34 """Initialize this TracingTrack. | 21 """Initialize this TracingTrack. |
| 35 | 22 |
| 36 Args: | 23 Args: |
| 37 connection: a DevToolsConnection. | 24 connection: a DevToolsConnection. |
| 38 additional_categories: ([str] or None) If set, a list of additional | 25 categories: ([str] or None) If set, a list of categories to enable or |
| 39 categories to add. This cannot be used to re-enable | 26 disable in Chrome tracing. Categories prefixed with '-' are |
| 40 a category which is disabled by default (see | 27 disabled. |
| 41 _DISABLED_CATEGORIES), nor to disable a category. | |
| 42 disabled_categories: If set, a set of categories from _ENABLED_CATEGORIES | |
| 43 to disable. | |
| 44 fetch_stream: if true, use a websocket stream to fetch tracing data rather | 28 fetch_stream: if true, use a websocket stream to fetch tracing data rather |
| 45 than dataCollected events. It appears based on very limited testing that | 29 than dataCollected events. It appears based on very limited testing that |
| 46 a stream is slower than the default reporting as dataCollected events. | 30 a stream is slower than the default reporting as dataCollected events. |
| 47 """ | 31 """ |
| 48 super(TracingTrack, self).__init__(connection) | 32 super(TracingTrack, self).__init__(connection) |
| 49 if connection: | 33 if connection: |
| 50 connection.RegisterListener('Tracing.dataCollected', self) | 34 connection.RegisterListener('Tracing.dataCollected', self) |
| 51 | 35 |
| 52 categories_to_enable = _ENABLED_CATEGORIES | 36 self._categories = set(categories) |
| 53 categories_to_disable = _DISABLED_CATEGORIES | |
| 54 | |
| 55 if disabled_categories: | |
| 56 assert not any(cat.startswith('-') for cat in disabled_categories), ( | |
| 57 'Specify categories to disable without an initial -') | |
| 58 assert set(disabled_categories).issubset(set(_ENABLED_CATEGORIES)), ( | |
| 59 'Can only disable categories that are enabled by default') | |
| 60 categories_to_enable = ( | |
| 61 set(categories_to_enable).difference(set(disabled_categories))) | |
| 62 categories_to_disable += disabled_categories | |
| 63 | |
| 64 if additional_categories: | |
| 65 assert not any(cat.startswith('-') for cat in additional_categories), ( | |
| 66 'Use disabled_categories to disable a category') | |
| 67 assert not (set(additional_categories) & set(_DISABLED_CATEGORIES)), ( | |
| 68 'Cannot enable a disabled category') | |
| 69 categories_to_enable += tuple(additional_categories) | |
| 70 | |
| 71 self._categories = set( | |
| 72 itertools.chain(categories_to_enable, | |
| 73 tuple('-' + cat for cat in categories_to_disable))) | |
| 74 params = {} | 37 params = {} |
| 75 params['categories'] = ','.join(self._categories) | 38 params['categories'] = ','.join(self._categories) |
| 76 if fetch_stream: | 39 if fetch_stream: |
| 77 params['transferMode'] = 'ReturnAsStream' | 40 params['transferMode'] = 'ReturnAsStream' |
| 78 | 41 |
| 79 if connection: | 42 if connection: |
| 80 connection.SyncRequestNoResponse('Tracing.start', params) | 43 connection.SyncRequestNoResponse('Tracing.start', params) |
| 81 | 44 |
| 82 self._events = [] | 45 self._events = [] |
| 83 self._base_msec = None | 46 self._base_msec = None |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 """ | 127 """ |
| 165 events = self._events | 128 events = self._events |
| 166 if pid is not None: | 129 if pid is not None: |
| 167 events = filter(lambda e : e.tracing_event['pid'] == pid, events) | 130 events = filter(lambda e : e.tracing_event['pid'] == pid, events) |
| 168 if tid is not None: | 131 if tid is not None: |
| 169 events = filter(lambda e : e.tracing_event['tid'] == tid, events) | 132 events = filter(lambda e : e.tracing_event['tid'] == tid, events) |
| 170 if categories is not None: | 133 if categories is not None: |
| 171 events = filter( | 134 events = filter( |
| 172 lambda e : set(e.category.split(',')).intersection(categories), | 135 lambda e : set(e.category.split(',')).intersection(categories), |
| 173 events) | 136 events) |
| 174 tracing_track = TracingTrack(None) | 137 tracing_track = TracingTrack(None, clovis_constants.DEFAULT_CATEGORIES) |
| 175 tracing_track._events = events | 138 tracing_track._events = events |
| 176 tracing_track._categories = self._categories | 139 tracing_track._categories = self._categories |
| 177 if categories is not None: | 140 if categories is not None: |
| 178 tracing_track._categories = self._categories.intersection(categories) | 141 tracing_track._categories = self._categories.intersection(categories) |
| 179 return tracing_track | 142 return tracing_track |
| 180 | 143 |
| 181 def ToJsonDict(self): | 144 def ToJsonDict(self): |
| 182 return {'categories': list(self._categories), | 145 return {'categories': list(self._categories), |
| 183 'events': [e.ToJsonDict() for e in self._events]} | 146 'events': [e.ToJsonDict() for e in self._events]} |
| 184 | 147 |
| 185 @classmethod | 148 @classmethod |
| 186 def FromJsonDict(cls, json_dict): | 149 def FromJsonDict(cls, json_dict): |
| 187 if not json_dict: | 150 if not json_dict: |
| 188 return None | 151 return None |
| 189 assert 'events' in json_dict | 152 assert 'events' in json_dict |
| 190 events = [Event(e) for e in json_dict['events']] | 153 events = [Event(e) for e in json_dict['events']] |
| 191 tracing_track = TracingTrack(None) | 154 tracing_track = TracingTrack(None, clovis_constants.DEFAULT_CATEGORIES) |
| 192 tracing_track._categories = set(json_dict.get('categories', [])) | 155 tracing_track._categories = set(json_dict.get('categories', [])) |
| 193 tracing_track._events = events | 156 tracing_track._events = events |
| 194 tracing_track._base_msec = events[0].start_msec if events else 0 | 157 tracing_track._base_msec = events[0].start_msec if events else 0 |
| 195 for e in events[1:]: | 158 for e in events[1:]: |
| 196 if e.type == 'M': | 159 if e.type == 'M': |
| 197 continue # No timestamp for metadata events. | 160 continue # No timestamp for metadata events. |
| 198 assert e.start_msec > 0 | 161 assert e.start_msec > 0 |
| 199 if e.start_msec < tracing_track._base_msec: | 162 if e.start_msec < tracing_track._base_msec: |
| 200 tracing_track._base_msec = e.start_msec | 163 tracing_track._base_msec = e.start_msec |
| 201 return tracing_track | 164 return tracing_track |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 579 self._left = _IntervalTree(self.start, left_end, left_events) | 542 self._left = _IntervalTree(self.start, left_end, left_events) |
| 580 self._right = _IntervalTree(right_start, self.end, right_events) | 543 self._right = _IntervalTree(right_start, self.end, right_events) |
| 581 | 544 |
| 582 def _IsLeaf(self): | 545 def _IsLeaf(self): |
| 583 return self._left is None | 546 return self._left is None |
| 584 | 547 |
| 585 @classmethod | 548 @classmethod |
| 586 def _Overlaps(cls, event, start, end): | 549 def _Overlaps(cls, event, start, end): |
| 587 return (min(end, event.end_msec) - max(start, event.start_msec) > 0 | 550 return (min(end, event.end_msec) - max(start, event.start_msec) > 0 |
| 588 or start <= event.start_msec < end) # For instant events. | 551 or start <= event.start_msec < end) # For instant events. |
| OLD | NEW |