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 |