def __init__(self, tracing_event, synthetic=False): """Creates Event. Intended to be created only by TracingTrack. Args: tracing_event: JSON tracing event, as defined in https://goo.gl/Qabkqk. synthetic: True if the event is synthetic. This is only used for indexing internal to TracingTrack. """ if not synthetic and tracing_event['ph'] in ['s', 't', 'f']: raise devtools_monitor.DevToolsConnectionException( 'Unsupported event: %s' % tracing_event) if not synthetic and tracing_event['ph'] in ['p']: raise devtools_monitor.DevToolsConnectionException( 'Deprecated event: %s' % tracing_event) self._tracing_event = tracing_event # Note tracing event times are in microseconds. self.start_msec = tracing_event['ts'] / 1000.0 self.end_msec = None self._synthetic = synthetic if self.type == 'X': # Some events don't have a duration. duration = (tracing_event['dur'] if 'dur' in tracing_event else tracing_event['tdur']) self.end_msec = self.start_msec + duration / 1000.0
def _DurationEnd(self, event, _): if not self._duration_stack: raise devtools_monitor.DevToolsConnectionException( 'Unmatched duration end: %s' % event) start = self._duration_stack.pop() start.SetClose(event) return start
def _ObjectDestroyed(self, event, _): if event.id not in self._objects: raise devtools_monitor.DevToolsConnectionException( 'Missing object creation for %s' % event) start = self._objects[event.id] del self._objects[event.id] start.SetClose(event) return start
def _ObjectCreated(self, event, _): # The tracing event format has object deletion timestamps being exclusive, # that is the timestamp for a deletion my equal that of the next create at # the same address. This asserts that does not happen in practice as it is # inconvenient to handle that correctly here. if event.id in self._objects: raise devtools_monitor.DevToolsConnectionException( 'Multiple objects at same address: %s, %s' % (event, self._objects[event.id])) self._objects[event.id] = event return None
def SetClose(self, closing): """Close a spanning event. Args: closing: The closing event. Raises: devtools_monitor.DevToolsConnectionException if closing can't property close this event. """ if self.type != self.CLOSING_EVENTS.get(closing.type): raise devtools_monitor.DevToolsConnectionException( 'Bad closing: %s --> %s' % (self, closing)) if self.type in ['b', 'S'] and ( self.tracing_event['cat'] != closing.tracing_event['cat'] or self.id != closing.id): raise devtools_monitor.DevToolsConnectionException( 'Bad async closing: %s --> %s' % (self, closing)) self.end_msec = closing.start_msec if 'args' in closing.tracing_event: self.tracing_event.setdefault( 'args', {}).update(closing.tracing_event['args'])
def _AsyncEnd(self, event, strict): key = self._AsyncKey(event, strict) if key not in self._async_stacks: message = 'Unmatched async end %s: %s' % (key, event) if strict: raise devtools_monitor.DevToolsConnectionException(message) else: logging.warning(message) return None stack = self._async_stacks[key] start = stack.pop() if not stack: del self._async_stacks[key] start.SetClose(event) return start
def _IndexEvents(self, strict=False): if self._interval_tree: return complete_events = [] spanning_events = self._SpanningEvents() for event in self._events: if not event.IsIndexable(): continue if event.IsComplete(): complete_events.append(event) continue matched_event = spanning_events.Match(event, strict) if matched_event is not None: complete_events.append(matched_event) self._interval_tree = _IntervalTree.FromEvents(complete_events) if strict and spanning_events.HasPending(): raise devtools_monitor.DevToolsConnectionException( 'Pending spanning events: %s' % '\n'.join([str(e) for e in spanning_events.PendingEvents()]))
def _Unsupported(self, event, _): raise devtools_monitor.DevToolsConnectionException( 'Unsupported spanning event type: %s' % event)