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

Unified Diff: tools/telemetry/telemetry/timeline/trace_data.py

Issue 805463002: Implement ubertracing. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merg Created 6 years 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 side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/telemetry/timeline/trace_data.py
diff --git a/tools/telemetry/telemetry/timeline/trace_data.py b/tools/telemetry/telemetry/timeline/trace_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b52fce2fe9248bb8882c775710fbfc3f22f3a93
--- /dev/null
+++ b/tools/telemetry/telemetry/timeline/trace_data.py
@@ -0,0 +1,175 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import numbers
+
slamm 2014/12/22 17:12:32 It is good practice for modules to raise their own
+def _ValidateRawData(raw):
+ try:
+ json.dumps(raw)
+ except TypeError as e:
+ raise Exception('TraceData cannot be serialized: %s' % e)
+ except ValueError as e:
+ raise Exception('TraceData cannot be serialized: %s' % e)
slamm 2014/12/22 17:12:31 except (TypeError, ValueError) as e: raise NonSe
sullivan 2014/12/22 19:28:37 TraceData should only contain json-serializable da
+
+
+class TraceDataPart(object):
+ """TraceData can have a variety of events.
+
+ These are called "parts" and are accessed by the following fixed field names.
+ """
+ def __init__(self, raw_field_name):
+ self._raw_field_name = raw_field_name
+
+ def __repr__(self):
+ return 'TraceDataPart("%s")' % self._raw_field_name
+
+ @property
+ def raw_field_name(self):
+ return self._raw_field_name
slamm 2014/12/22 17:12:32 indent 2.
sullivan 2014/12/22 19:28:38 Done.
+
+
+CHROME_TRACE_PART = TraceDataPart('traceEvents')
+INSPECTOR_TRACE_PART = TraceDataPart('inspectorTimelineEvents')
+SURFACE_FLINGER_PART = TraceDataPart('surfaceFlinger')
+TAB_ID_PART = TraceDataPart('tabIds')
+
+ALL_TRACE_PARTS = set([CHROME_TRACE_PART, INSPECTOR_TRACE_PART, TAB_ID_PART])
slamm 2014/12/22 17:12:32 Use set literal? ALL_TRACE_PARTS = {CHROME_TRACE_
sullivan 2014/12/22 19:28:38 Done.
+
+
+def _HasEventsFor(part, raw):
+ assert isinstance(part, TraceDataPart)
+ if part.raw_field_name not in raw:
+ return False
+ return len(raw[part.raw_field_name]) > 0
+
+
+class TraceData(object):
+ """Validates, parses, and serializes raw data.
+
+ NOTE: raw data must NOT include any non-primitive objects!
slamm 2014/12/22 17:12:32 NOTE: raw data must only include primitive objects
sullivan 2014/12/22 19:28:38 Done.
+ By design, TraceData must contain only data that is BOTH json-serializable
+ to a file, AND restorable once again from that file into TraceData without
+ assistance from other classes.
+
+ Raw data can be any of the three standard trace_event formats:
slamm 2014/12/22 17:12:32 Raw data can be one of three standard trace_event
sullivan 2014/12/22 19:28:38 Done.
+ 1. Trace container format: a json-parseable dict.
+ 2. A json-parseable array: assumed to be chrome trace data.
+ 3. A json-parseable array missing the final ']': assumed to be chrome trace
+ data.
+ """
+ def __init__(self, raw_data=None):
+ """Creates TraceData from the given data."""
+ self._raw_data = {}
+ self._events_are_safely_mutable = False
+ if not raw_data:
+ return
+ _ValidateRawData(raw_data)
+
+ if isinstance(raw_data, basestring):
+ if raw_data.startswith('[') and not raw_data.endswith(']'):
+ if raw_data.endswith(','):
+ raw_data = raw_data[:-1]
+ raw_data += ']'
+ json_data = json.loads(raw_data)
+ # The parsed data isn't shared with anyone else, so we mark this value
+ # as safely mutable.
+ self._events_are_safely_mutable = True
+ else:
+ json_data = raw_data
+
+ if isinstance(json_data, dict):
+ self._raw_data = json_data
+ elif isinstance(json_data, list):
+ if len(json_data) == 0:
+ self._raw_data = {}
+ self._raw_data = {CHROME_TRACE_PART.raw_field_name: json_data}
+ else:
+ raise Exception('Unrecognized data format.')
+
+ def _SetFromBuilder(self, d):
+ self._raw_data = d
+ self._events_are_safely_mutable = True
+
+ @property
+ def events_are_safely_mutable(self):
+ """Returns true if the events in this value are completely sealed.
+
+ Some importers want to take complex fields out of the TraceData and add
+ them to the model, changing them subtly as they do so. If the TraceData
+ was constructed with data that is shared with something outside the trace
+ data, for instance a test harness, then this mutation is unexpected. But,
+ if the values are sealed, then mutating the events is a lot faster.
+
+ We know if events are sealed if the value came from a string, or if the
+ value came from a TraceDataBuilder.
+ """
+ return self._events_are_safely_mutable
+
+ @property
+ def active_parts(self):
+ return set([p for p in ALL_TRACE_PARTS
+ if p.raw_field_name in self._raw_data])
slamm 2014/12/22 17:12:31 Use a set comprehension? return {p for p in ALL
sullivan 2014/12/22 19:28:38 Done.
+
+ @property
+ def metadata_records(self):
+ part_field_names = set([p.raw_field_name for p in ALL_TRACE_PARTS])
slamm 2014/12/22 17:12:32 part_field_names = {p.raw_field_name for p in ALL_
sullivan 2014/12/22 19:28:37 Done.
+ for k,v in self._raw_data.iteritems():
slamm 2014/12/22 17:12:32 A space after the comma. for k, v in self._raw_da
sullivan 2014/12/22 19:28:37 Done.
+ if k in part_field_names:
+ continue
+ yield {
+ 'name' : k,
+ 'value' : self._raw_data[v]
slamm 2014/12/22 17:12:32 No spaces before the colons. 'name': k, 'value':
sullivan 2014/12/22 19:28:38 Done.
+ }
+
+ def HasEventsFor(self, part):
+ return _HasEventsFor(part, self._raw_data)
+
+ def GetEventsFor(self, part):
+ if not self.HasEventsFor(part):
+ return []
+ assert isinstance(part, TraceDataPart)
+ return self._raw_data[part.raw_field_name]
+
+ def Serialize(self, f, gzip_result=False):
+ """Serializes the trace result to a file-like object.
+
+ Always writes in the trace container format."""
slamm 2014/12/22 17:12:32 Closing quotes on a new line. """Serializes the t
sullivan 2014/12/22 19:28:38 Done.
+ assert not gzip_result, 'Not implemented'
+ json.dump(self._raw_data, f)
+
+
+class TraceDataBuilder(object):
+ """TraceDataBuilder helps build up a trace from multiple trace agents.
+
+ TraceData is supposed to be immutable, but it is useful during recording to
+ have a mutable version. That is TraceDataBuilder.
+ """
+ def __init__(self):
+ self._raw_data = {}
+
+ def AsData(self):
+ if self._raw_data == None:
+ raise Exception('Can only AsData once')
+
+ data = TraceData()
+ data._SetFromBuilder(self._raw_data)
+ self._raw_data = None
+ return data
+
+ def AddEventsTo(self, part, events):
+ """Note: this won't work when called from multiple browsers.
+
+ Each browser's trace_event_impl zeros its timestamps when it writes them
+ out and doesn't write a timebase that can be used to re-sync them.
+ """
+ assert isinstance(part, TraceDataPart)
+ assert isinstance(events, list)
+ if self._raw_data == None:
+ raise Exception('Already called AsData() on this builder.')
+
+ self._raw_data.setdefault(part.raw_field_name, []).extend(events)
+
+ def HasEventsFor(self, part):
+ return _HasEventsFor(part, self._raw_data)

Powered by Google App Engine
This is Rietveld 408576698