Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import json | |
| 6 import numbers | |
| 7 | |
| 8 def _ValidateRawData(raw): | |
| 9 if isinstance(raw, basestring): | |
| 10 return | |
| 11 if isinstance(raw, numbers.Number): | |
| 12 return | |
| 13 | |
|
nednguyen
2014/08/05 14:34:34
Can None be raw data?
For example: {1:None, 2:'foo
| |
| 14 if isinstance(raw, list): | |
| 15 for r in raw: | |
| 16 _ValidateRawData(r) | |
| 17 return | |
| 18 | |
| 19 if isinstance(raw, dict): | |
| 20 for k,v in raw.iteritems(): | |
| 21 _ValidateRawData(k) | |
| 22 _ValidateRawData(v) | |
| 23 return | |
| 24 | |
| 25 raise Exception('%s is not allowed in TraceValue', raw) | |
|
nednguyen
2014/08/05 14:34:34
Throwing exception at the leaf level may make it h
| |
| 26 | |
| 27 | |
| 28 # TraceValues have a variety of events in them. These are called "parts" and | |
| 29 # aare accessed by name, using the following fixed field names. | |
|
nednguyen
2014/08/05 14:34:34
nit: are
| |
| 30 class TraceValuePart(object): | |
|
chrishenry
2014/08/05 23:44:15
Just TracePart? TraceValuePart is a bit ambiguous.
| |
| 31 def __init__(self, rawFieldName): | |
| 32 self.rawFieldName = rawFieldName | |
|
chrishenry
2014/08/05 23:44:15
nit: raw_field_name
| |
| 33 | |
| 34 def __repr__(self): | |
| 35 return 'TraceValuePart("%s")' % self.rawFieldName | |
| 36 | |
| 37 CHROME_TRACE_PART = TraceValuePart('traceEvents') | |
| 38 INSPECTOR_TRACE_PART = TraceValuePart('inspectorTimelineEvents') | |
| 39 TAB_ID_PART = TraceValuePart('tabIds') | |
| 40 | |
| 41 ALL_TRACE_VALUE_PARTS = set([CHROME_TRACE_PART, | |
| 42 INSPECTOR_TRACE_PART, | |
| 43 TAB_ID_PART]) | |
| 44 | |
| 45 class RawTraceValueHelpersMixin(object): | |
|
nednguyen
2014/08/05 14:34:34
Don't you need __init__(self) to define self._raw_
chrishenry
2014/08/05 23:44:16
Does TraceValue and Builder really need to mixin t
| |
| 46 @property | |
| 47 def active_parts(self): | |
| 48 return set([p for p in ALL_TRACE_VALUE_PARTS | |
| 49 if p.rawFieldName in self._raw_data]) | |
| 50 | |
| 51 def HasEventsFor(self, part): | |
| 52 assert isinstance(part, TraceValuePart) | |
| 53 if part.rawFieldName not in self._raw_data: | |
| 54 return False | |
| 55 return len(self._raw_data[part.rawFieldName]) > 0 | |
| 56 | |
| 57 def GetEventsFor(self, part): | |
| 58 assert isinstance(part, TraceValuePart) | |
| 59 return self._raw_data[part.rawFieldName] | |
| 60 | |
| 61 @property | |
| 62 def metadata_records(self): | |
| 63 part_field_names = set([p.rawFieldName for p in ALL_TRACE_VALUE_PARTS]) | |
|
slamm
2014/08/12 23:11:59
You can build the set with a generator expression
| |
| 64 for k,v in self._raw_data.iteritems(): | |
|
chrishenry
2014/08/05 23:44:15
nit: k, v (space after ,)
| |
| 65 if k in part_field_names: | |
| 66 continue | |
| 67 yield { | |
| 68 'name' : k, | |
|
chrishenry
2014/08/05 23:44:15
nit: no space before :
| |
| 69 'value' : self._raw_data[v] | |
|
nednguyen
2014/08/05 14:34:34
'value': v ?
| |
| 70 } | |
| 71 | |
| 72 | |
| 73 # TODO(nduca): Make this subclass value. Moving it was a huge enough patch | |
| 74 # that the true subclassing will be done in a followup. | |
| 75 class TraceValue(RawTraceValueHelpersMixin): | |
| 76 def __init__(self, raw_data=None): | |
| 77 """Creates a TraceValue from the given data. | |
| 78 | |
| 79 NOTE: raw data must NOT include any non-primitive objects! | |
| 80 By design, TraceValue must contain only data that is BOTH serializable | |
| 81 to a file, AND restorable once again from that file into a TraceValue | |
| 82 without assistance from other classes. | |
| 83 | |
| 84 raw_data can be any of the three standard trace_event formats: | |
|
nednguyen
2014/08/05 14:34:34
So we will need something else for video and image
| |
| 85 1. Trace container format: a json-parseable dict. | |
| 86 2. A json-parseable array: assumed to be chrome trace data. | |
| 87 3. A json-parseable array missing the final ]: assumed to be | |
| 88 chrome trace data. | |
| 89 """ | |
| 90 self._raw_data = {} | |
| 91 self._events_are_safely_mutable = False | |
| 92 if raw_data == None: | |
| 93 return | |
| 94 | |
| 95 _ValidateRawData(raw_data) | |
| 96 | |
| 97 if self._TryInitFromRaw(raw_data): | |
| 98 return | |
| 99 | |
| 100 if not isinstance(raw_data, basestring): | |
|
chrishenry
2014/08/05 23:44:16
I think it's clearer to refactor TryInitFromRaw an
| |
| 101 raise ValueError('Unrecognized data format') | |
| 102 | |
| 103 if len(raw_data) == 0: | |
| 104 self._raw_data == {} | |
|
slamm
2014/08/12 23:11:59
self._raw_data = {} ?
Same in _TryInitFromRaw.
| |
| 105 return | |
| 106 | |
| 107 if raw_data[0] == '[' and raw_data[-1] != ']': | |
|
slamm
2014/08/12 23:11:59
Better?
if raw_data.startswith('[') and not raw_d
| |
| 108 if raw_data[-1] == ',': | |
| 109 raw_data = raw_data[:-1] + ']' | |
| 110 else: | |
| 111 raw_data = raw_data + ']' | |
| 112 | |
| 113 raw_data = json.loads(raw_data) | |
| 114 if self._TryInitFromRaw(raw_data): | |
| 115 self._events_are_safely_mutable = True | |
| 116 return | |
| 117 | |
| 118 raise Exception('Unrecognized data format') | |
| 119 | |
| 120 def _TryInitFromRaw(self, raw_data): | |
| 121 if isinstance(raw_data, dict): | |
| 122 self._raw_data = raw_data | |
| 123 return True | |
| 124 | |
| 125 if isinstance(raw_data, list): | |
| 126 if len(raw_data) == 0: | |
| 127 self._raw_data == {} | |
| 128 return True | |
| 129 | |
| 130 self._raw_data = {'traceEvents': raw_data} | |
|
nednguyen
2014/08/05 14:34:34
How about self._raw_data = { CHROME_TRACE_PART.raw
| |
| 131 return True | |
| 132 | |
| 133 return False | |
| 134 | |
| 135 def _SetFromBuilder(self, d): | |
| 136 self._raw_data = d | |
| 137 self._event_data_is_mutable = True | |
|
chrishenry
2014/08/05 23:44:16
Unused? Or do you mean _events_are_safely_mutable?
| |
| 138 | |
| 139 @property | |
| 140 def events_are_safely_mutable(self): | |
| 141 """Returns true if the events in this value are completely sealed. | |
| 142 | |
| 143 Some importers want to take complex fields out of the TraceValue and add | |
| 144 them to the model, changing them subtly as they do so. If the TraceValue was | |
|
chrishenry
2014/08/05 23:44:16
Do these importers modify the raw data in this Tra
| |
| 145 constructed with data that is shared with something outside the trace value, | |
| 146 for instance a test harness, then this mutation is unexpected. But, if the | |
| 147 values are sealed, then mutating the events is a lot faster. | |
| 148 | |
| 149 We know if events are sealed if the value came from a string, or if the | |
| 150 value came from | |
|
chrishenry
2014/08/05 23:44:16
incomplete sentence?
| |
| 151 """ | |
| 152 return self._events_are_safely_mutable | |
| 153 | |
| 154 def Serialize(self, f, gzip_result=False): | |
| 155 """Serializes the trace result to a file-like object. | |
| 156 | |
| 157 Always writes in the trace container format.""" | |
| 158 assert not gzip_result, 'Not implemented' | |
| 159 json.dump(self._raw_data, f) | |
| 160 | |
| 161 | |
| 162 class TraceValueBuilder(RawTraceValueHelpersMixin): | |
| 163 def __init__(self): | |
| 164 """TraceValueBuilder helps build up of a trace from multiple trace agents. | |
| 165 | |
| 166 TraceValue is supposed to be immutable, but it is useful during recording | |
| 167 to have a mutable version. That is TraceValueBuilder. | |
| 168 """ | |
| 169 self._raw_data = {} | |
| 170 | |
| 171 def AsValue(self): | |
| 172 if self._raw_data == None: | |
| 173 raise Exception('Can only AsValue() once') | |
| 174 | |
| 175 res = TraceValue() | |
|
chrishenry
2014/08/05 23:44:16
nit: s/res/value/
| |
| 176 res._SetFromBuilder(self._raw_data) | |
| 177 self._raw_data = None | |
| 178 return res | |
| 179 | |
| 180 def AddEventsTo(self, part, events): | |
| 181 # Note: this wont work when you call this from multiple browsers. | |
| 182 # Each browser's trace_event_impl zeros its timestamps when it writes them | |
| 183 # out and doesn't write a timebase that can be used to re-sync them. | |
|
chrishenry
2014/08/05 23:44:16
Turn this into pydoc?
| |
| 184 assert isinstance(part, TraceValuePart) | |
| 185 assert isinstance(events, list) | |
| 186 if self._raw_data == None: | |
| 187 raise Exception('Already called AsValue() on this builder.') | |
| 188 existing_events = None | |
| 189 existing_events = self._raw_data.get(part.rawFieldName, None) | |
| 190 if existing_events == None: | |
| 191 existing_events = [] | |
| 192 self._raw_data[part.rawFieldName] = existing_events | |
| 193 existing_events.extend(events) | |
| 194 | |
| OLD | NEW |