| Index: tools/telemetry/telemetry/core/timeline/thread.py | 
| diff --git a/tools/telemetry/telemetry/core/timeline/tracing/thread.py b/tools/telemetry/telemetry/core/timeline/thread.py | 
| similarity index 73% | 
| rename from tools/telemetry/telemetry/core/timeline/tracing/thread.py | 
| rename to tools/telemetry/telemetry/core/timeline/thread.py | 
| index 8bb184a8b4f905bed5ddca79568e9185132311a4..180532c453daf2557617b6f08db9e7d2c840b153 100644 | 
| --- a/tools/telemetry/telemetry/core/timeline/tracing/thread.py | 
| +++ b/tools/telemetry/telemetry/core/timeline/thread.py | 
| @@ -1,54 +1,82 @@ | 
| # Copyright 2013 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 itertools | 
|  | 
| -import telemetry.core.timeline.event as timeline_event | 
| -import telemetry.core.timeline.tracing.sample as tracing_sample | 
| -import telemetry.core.timeline.tracing.slice as tracing_slice | 
| +import telemetry.core.timeline.event_container as event_container | 
| +import telemetry.core.timeline.sample as tracing_sample | 
| +import telemetry.core.timeline.slice as tracing_slice | 
|  | 
| -class Thread(timeline_event.TimelineEvent): | 
| +class Thread(event_container.TimelineEventContainer): | 
| ''' A Thread stores all the trace events collected for a particular | 
| thread. We organize the synchronous slices on a thread by "subrows," where | 
| subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on. | 
| The asynchronous slices are stored in an AsyncSliceGroup object. | 
| ''' | 
| def __init__(self, process, tid): | 
| -    super(Thread, self).__init__('thread %s' % tid, 0, 0, parent=process) | 
| +    super(Thread, self).__init__('thread %s' % tid, parent=process) | 
| self.tid = tid | 
| -    self._open_slices = [] | 
| self._async_slices = [] | 
| self._samples = [] | 
| -    self._slices = [] | 
| +    self._toplevel_slices = [] | 
| + | 
| +    # State only valid during import. | 
| +    self._open_slices = [] | 
| +    self._newly_added_slices = [] | 
|  | 
| @property | 
| -  def slices(self): | 
| -    return self._slices | 
| +  def toplevel_slices(self): | 
| +    return self._toplevel_slices | 
| + | 
| +  @property | 
| +  def all_slices(self): | 
| +    return list(self.IterAllSlices()) | 
|  | 
| @property | 
| def samples(self): | 
| return self._samples | 
|  | 
| @property | 
| +  def async_slices(self): | 
| +    return self._async_slices | 
| + | 
| +  @property | 
| def open_slice_count(self): | 
| return len(self._open_slices) | 
|  | 
| -  @property | 
| -  def async_slices(self): | 
| -    return self._async_slices | 
| +  def IterChildContainers(self): | 
| +    return iter([]) | 
| + | 
| +  def IterAllSlices(self): | 
| +    for s in self._toplevel_slices: | 
| +      yield s | 
| +      for sub_slice in s.IterEventsInThisContainerRecrusively(): | 
| +        yield sub_slice | 
| +  def IterAllAsyncSlices(self): | 
| +    for async_slice in self._async_slices: | 
| +      yield async_slice | 
| +      for sub_slice in async_slice.IterEventsInThisContainerRecrusively(): | 
| +        yield sub_slice | 
| + | 
| +  def IterEventsInThisContainer(self): | 
| +    return itertools.chain( | 
| +      iter(self._open_slices), | 
| +      iter(self._newly_added_slices), | 
| +      self.IterAllAsyncSlices(), | 
| +      self.IterAllSlices(), | 
| +      iter(self._samples) | 
| +      ) | 
|  | 
| def AddSample(self, category, name, timestamp, args=None): | 
| if len(self._samples) and timestamp < self._samples[-1].start: | 
| raise ValueError( | 
| 'Samples must be added in increasing timestamp order') | 
| -    sample = tracing_sample.Sample( | 
| -        category, name, timestamp, args=args, parent=self) | 
| +    sample = tracing_sample.Sample(self, | 
| +        category, name, timestamp, args=args) | 
| self._samples.append(sample) | 
| -    self.children.append(sample) | 
|  | 
| def AddAsyncSlice(self, async_slice): | 
| self._async_slices.append(async_slice) | 
| -    async_slice.parent = self | 
| -    self.children.append(async_slice) | 
|  | 
| def BeginSlice(self, category, name, timestamp, args=None): | 
| """Opens a new slice for the thread. | 
| @@ -66,7 +94,7 @@ class Thread(timeline_event.TimelineEvent): | 
| raise ValueError( | 
| 'Slices must be added in increasing timestamp order') | 
| self._open_slices.append( | 
| -        tracing_slice.Slice(category, name, timestamp, args=args, parent=self)) | 
| +        tracing_slice.Slice(self, category, name, timestamp, args=args)) | 
|  | 
| def EndSlice(self, end_timestamp): | 
| """ Ends the last begun slice in this group and pushes it onto the slice | 
| @@ -87,14 +115,10 @@ class Thread(timeline_event.TimelineEvent): | 
| return self.PushSlice(curr_slice) | 
|  | 
| def PushSlice(self, new_slice): | 
| -    self._slices.append(new_slice) | 
| -    self.children.append(new_slice) | 
| +    self._newly_added_slices.append(new_slice) | 
| return new_slice | 
|  | 
| -  def AutoCloseOpenSlices(self, max_timestamp=None): | 
| -    if max_timestamp is None: | 
| -      self.UpdateBounds() | 
| -      max_timestamp = self.end | 
| +  def AutoCloseOpenSlices(self, max_timestamp): | 
| while len(self._open_slices) > 0: | 
| curr_slice = self.EndSlice(max_timestamp) | 
| curr_slice.did_not_finish = True | 
| @@ -104,16 +128,6 @@ class Thread(timeline_event.TimelineEvent): | 
| return True | 
| return timestamp >= self._open_slices[-1].start | 
|  | 
| -  def UpdateBounds(self): | 
| -    super(Thread, self).UpdateBounds() | 
| - | 
| -    # Take open slices into account for the start and duration of thread event | 
| -    if len(self._open_slices) > 0: | 
| -      if not len(self.slices) or self.start > self._open_slices[0].start: | 
| -        self.start = self._open_slices[0].start | 
| -      if not len(self.slices) or self.end < self._open_slices[-1].start: | 
| -        self.duration = self._open_slices[-1].start - self.start | 
| - | 
| def FinalizeImport(self): | 
| self._BuildSliceSubRows() | 
|  | 
| @@ -155,14 +169,18 @@ class Thread(timeline_event.TimelineEvent): | 
| return cmp(s2.end, s1.end) | 
| return cmp(s1.start, s2.start) | 
|  | 
| -    if not len(self._slices): | 
| +    assert len(self._toplevel_slices) == 0 | 
| +    if not len(self._newly_added_slices): | 
| return | 
|  | 
| -    sorted_slices = sorted(self._slices, cmp=CompareSlices) | 
| +    sorted_slices = sorted(self._newly_added_slices, cmp=CompareSlices) | 
| root_slice = sorted_slices[0] | 
| +    self._toplevel_slices.append(root_slice) | 
| for s in sorted_slices[1:]: | 
| if not self._AddSliceIfBounds(root_slice, s): | 
| root_slice = s | 
| +        self._toplevel_slices.append(root_slice) | 
| +    self._newly_added_slices = [] | 
|  | 
| def _AddSliceIfBounds(self, root, child): | 
| ''' Adds a child slice to a root slice its proper row. | 
| @@ -177,6 +195,7 @@ class Thread(timeline_event.TimelineEvent): | 
| if len(root.sub_slices) > 0: | 
| if self._AddSliceIfBounds(root.sub_slices[-1], child): | 
| return True | 
| +      child.parent_slice = root | 
| root.AddSubSlice(child) | 
| return True | 
| return False | 
|  |