blob: dccfed88bc37ebc5a0e9c83f78f54770446beeb1 [file] [log] [blame]
# 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 six
from telemetry.timeline import async_slice as async_slice_module
from telemetry.timeline import flow_event as flow_event_module
from telemetry.timeline import slice as slice_module
class TimelineEventContainer(object):
"""Represents a container for events.
"""
def __init__(self, name, parent):
self.parent = parent
self.name = name
@staticmethod
def IsAsyncSlice(t):
return t == async_slice_module.AsyncSlice
@staticmethod
def IsSliceOrAsyncSlice(t):
return t in (slice_module.Slice, async_slice_module.AsyncSlice)
# Basic functions that subclasses of TimelineEventContainer should implement
# in order to expose their events. New methods should be added to this part of
# the code only when absolutely certain they're needed.
def IterChildContainers(self):
raise NotImplementedError()
def IterEventsInThisContainer(self, event_type_predicate, event_predicate):
"""Iterates all the TimelineEvents in this container.
Only events with a type matching event_type_predicate AND matching event
event_predicate will be yielded.
event_type_predicate is given an actual type object, e.g.:
event_type_predicate(slice_module.Slice)
event_predicate is given actual events:
event_predicate(thread.slices[7])
DO NOT ASSUME that the event_type_predicate will be called for every event
found. The relative calling order of the two is left up to the implementer
of the method.
"""
del event_type_predicate, event_predicate # unused
return
yield # pylint: disable=unreachable
def IterAllEvents(self,
recursive=True,
event_type_predicate=lambda t: True,
event_predicate=lambda e: True):
"""Iterates all events in this container, pre-filtered by two predicates.
Only events with a type matching event_type_predicate AND matching event
event_predicate will be yielded.
event_type_predicate is given an actual type object, e.g.:
event_type_predicate(slice_module.Slice)
event_predicate is given actual events:
event_predicate(thread.slices[7])
"""
if not recursive:
for e in self.IterEventsInThisContainer(
event_type_predicate, event_predicate):
yield e
return
# TODO(nduca): Write this as a proper iterator instead of one that creates a
# list and then iterates it.
containers = []
def GetContainersRecursive(container):
containers.append(container)
for container in container.IterChildContainers():
GetContainersRecursive(container)
GetContainersRecursive(self)
# Actually create the iterator.
for c in containers:
for e in c.IterEventsInThisContainer(event_type_predicate,
event_predicate):
yield e
# Helper functions for finding common kinds of events. Must always take an
# optinal recurisve parameter and be implemented in terms fo IterAllEvents.
def IterTimelineMarkers(self, names, recursive=True):
if isinstance(names, six.string_types):
names = {names}
else:
names = set(names)
def IsEventNeeded(event):
return event.parent_slice is None and event.name in names
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=self.IsSliceOrAsyncSlice,
event_predicate=IsEventNeeded)
def IterAllEventsOfName(self, name, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: True,
event_predicate=lambda e: e.name == name)
def IterAllSlices(self, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: t == slice_module.Slice)
def IterAllSlicesInRange(self, start, end, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: t == slice_module.Slice,
event_predicate=lambda s: s.start >= start and s.end <= end)
def IterAllSlicesOfName(self, name, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: t == slice_module.Slice,
event_predicate=lambda e: e.name == name)
def IterAllToplevelSlicesOfName(self, name, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: t == slice_module.Slice,
event_predicate=lambda e: e.name == name and e.parent_slice is None)
def IterAllAsyncSlicesOfName(self, name, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=self.IsAsyncSlice,
event_predicate=lambda e: e.name == name)
def IterAllAsyncSlicesStartsWithName(self, name, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=self.IsAsyncSlice,
event_predicate=lambda e: e.name.startswith(name))
def IterAllFlowEvents(self, recursive=True):
return self.IterAllEvents(
recursive=recursive,
event_type_predicate=lambda t: t == flow_event_module.FlowEvent)
# List versions. These should always be simple expressions that list() on
# an underlying iter method.
def GetAllEvents(self, recursive=True):
return list(self.IterAllEvents(recursive=recursive))
def GetAllEventsOfName(self, name, recursive=True):
return list(self.IterAllEventsOfName(name, recursive))
def GetAllToplevelSlicesOfName(self, name, recursive=True):
return list(self.IterAllToplevelSlicesOfName(name, recursive))