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

Side by Side Diff: tools/telemetry/telemetry/core/timeline/thread.py

Issue 19772005: [telemetry] Timeline model cleanups (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: silly reitveld Created 7 years, 5 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import telemetry.core.timeline.event as timeline_event 5 import telemetry.core.timeline.event_container as event_container
6 import telemetry.core.timeline.tracing.sample as tracing_sample 6 import telemetry.core.timeline.sample as tracing_sample
7 import telemetry.core.timeline.tracing.slice as tracing_slice 7 import telemetry.core.timeline.slice as tracing_slice
8 8
9 class Thread(timeline_event.TimelineEvent): 9 class Thread(event_container.TimelineEventContainer):
10 ''' A Thread stores all the trace events collected for a particular 10 ''' A Thread stores all the trace events collected for a particular
11 thread. We organize the synchronous slices on a thread by "subrows," where 11 thread. We organize the synchronous slices on a thread by "subrows," where
12 subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on. 12 subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on.
13 The asynchronous slices are stored in an AsyncSliceGroup object. 13 The asynchronous slices are stored in an AsyncSliceGroup object.
14 ''' 14 '''
15 def __init__(self, process, tid): 15 def __init__(self, process, tid):
16 super(Thread, self).__init__('thread %s' % tid, 0, 0, parent=process) 16 super(Thread, self).__init__('thread %s' % tid, parent=process)
17 self.tid = tid 17 self.tid = tid
18 self._open_slices = []
19 self._async_slices = [] 18 self._async_slices = []
20 self._samples = [] 19 self._samples = []
21 self._slices = [] 20 self._toplevel_slices = []
21
22 # State only valid during import.
23 self._open_slices = []
24 self._newly_added_slices = []
22 25
23 @property 26 @property
24 def slices(self): 27 def toplevel_slices(self):
25 return self._slices 28 return self._toplevel_slices
29
30 @property
31 def all_slices(self):
32 return list(self.IterAllSlices())
26 33
27 @property 34 @property
28 def samples(self): 35 def samples(self):
29 return self._samples 36 return self._samples
30 37
31 @property 38 @property
39 def async_slices(self):
40 return self._async_slices
41
42 @property
32 def open_slice_count(self): 43 def open_slice_count(self):
33 return len(self._open_slices) 44 return len(self._open_slices)
34 45
35 @property 46 def IterChildContainers(self):
36 def async_slices(self): 47 return iter([])
37 return self._async_slices 48
49 def IterAllSlices(self):
50 for s in self._toplevel_slices:
51 yield s
52 for sub_slice in s.IterEventsInThisContainerRecrusively():
53 yield sub_slice
54 def IterAllAsyncSlices(self):
55 for async_slice in self._async_slices:
56 yield async_slice
57 for sub_slice in async_slice.IterEventsInThisContainerRecrusively():
58 yield sub_slice
59
60 def IterEventsInThisContainer(self):
61 for s in self._open_slices:
Tim Song 2013/07/18 23:13:55 There is a convenience function itertools.chain th
62 yield s
63 for s in self._newly_added_slices:
64 yield s
65 for s in self.IterAllAsyncSlices():
66 yield s
67 for s in self.IterAllSlices():
68 yield s
69 for sample in self._samples:
70 yield sample
38 71
39 def AddSample(self, category, name, timestamp, args=None): 72 def AddSample(self, category, name, timestamp, args=None):
40 if len(self._samples) and timestamp < self._samples[-1].start: 73 if len(self._samples) and timestamp < self._samples[-1].start:
41 raise ValueError( 74 raise ValueError(
42 'Samples must be added in increasing timestamp order') 75 'Samples must be added in increasing timestamp order')
43 sample = tracing_sample.Sample( 76 sample = tracing_sample.Sample(self,
44 category, name, timestamp, args=args, parent=self) 77 category, name, timestamp, args=args)
45 self._samples.append(sample) 78 self._samples.append(sample)
46 self.children.append(sample)
47 79
48 def AddAsyncSlice(self, async_slice): 80 def AddAsyncSlice(self, async_slice):
49 self._async_slices.append(async_slice) 81 self._async_slices.append(async_slice)
50 async_slice.parent = self
51 self.children.append(async_slice)
52 82
53 def BeginSlice(self, category, name, timestamp, args=None): 83 def BeginSlice(self, category, name, timestamp, args=None):
54 """Opens a new slice for the thread. 84 """Opens a new slice for the thread.
55 Calls to beginSlice and endSlice must be made with 85 Calls to beginSlice and endSlice must be made with
56 non-monotonically-decreasing timestamps. 86 non-monotonically-decreasing timestamps.
57 87
58 * category: Category to which the slice belongs. 88 * category: Category to which the slice belongs.
59 * name: Name of the slice to add. 89 * name: Name of the slice to add.
60 * timestamp: The timetsamp of the slice, in milliseconds. 90 * timestamp: The timetsamp of the slice, in milliseconds.
61 * args: Arguments associated with 91 * args: Arguments associated with
62 92
63 Returns newly opened slice 93 Returns newly opened slice
64 """ 94 """
65 if len(self._open_slices) > 0 and timestamp < self._open_slices[-1].start: 95 if len(self._open_slices) > 0 and timestamp < self._open_slices[-1].start:
66 raise ValueError( 96 raise ValueError(
67 'Slices must be added in increasing timestamp order') 97 'Slices must be added in increasing timestamp order')
68 self._open_slices.append( 98 self._open_slices.append(
69 tracing_slice.Slice(category, name, timestamp, args=args, parent=self)) 99 tracing_slice.Slice(self, category, name, timestamp, args=args))
70 100
71 def EndSlice(self, end_timestamp): 101 def EndSlice(self, end_timestamp):
72 """ Ends the last begun slice in this group and pushes it onto the slice 102 """ Ends the last begun slice in this group and pushes it onto the slice
73 array. 103 array.
74 104
75 * end_timestamp: Timestamp when the slice ended in milliseconds 105 * end_timestamp: Timestamp when the slice ended in milliseconds
76 106
77 returns completed slice. 107 returns completed slice.
78 """ 108 """
79 if not len(self._open_slices): 109 if not len(self._open_slices):
80 raise ValueError( 110 raise ValueError(
81 'EndSlice called without an open slice') 111 'EndSlice called without an open slice')
82 curr_slice = self._open_slices.pop() 112 curr_slice = self._open_slices.pop()
83 if end_timestamp < curr_slice.start: 113 if end_timestamp < curr_slice.start:
84 raise ValueError( 114 raise ValueError(
85 'Slice %s end time is before its start.' % curr_slice.name) 115 'Slice %s end time is before its start.' % curr_slice.name)
86 curr_slice.duration = end_timestamp - curr_slice.start 116 curr_slice.duration = end_timestamp - curr_slice.start
87 return self.PushSlice(curr_slice) 117 return self.PushSlice(curr_slice)
88 118
89 def PushSlice(self, new_slice): 119 def PushSlice(self, new_slice):
90 self._slices.append(new_slice) 120 self._newly_added_slices.append(new_slice)
91 self.children.append(new_slice)
92 return new_slice 121 return new_slice
93 122
94 def AutoCloseOpenSlices(self, max_timestamp=None): 123 def AutoCloseOpenSlices(self, max_timestamp):
95 if max_timestamp is None:
96 self.UpdateBounds()
97 max_timestamp = self.end
98 while len(self._open_slices) > 0: 124 while len(self._open_slices) > 0:
99 curr_slice = self.EndSlice(max_timestamp) 125 curr_slice = self.EndSlice(max_timestamp)
100 curr_slice.did_not_finish = True 126 curr_slice.did_not_finish = True
101 127
102 def IsTimestampValidForBeginOrEnd(self, timestamp): 128 def IsTimestampValidForBeginOrEnd(self, timestamp):
103 if not len(self._open_slices): 129 if not len(self._open_slices):
104 return True 130 return True
105 return timestamp >= self._open_slices[-1].start 131 return timestamp >= self._open_slices[-1].start
106 132
107 def UpdateBounds(self):
108 super(Thread, self).UpdateBounds()
109
110 # Take open slices into account for the start and duration of thread event
111 if len(self._open_slices) > 0:
112 if not len(self.slices) or self.start > self._open_slices[0].start:
113 self.start = self._open_slices[0].start
114 if not len(self.slices) or self.end < self._open_slices[-1].start:
115 self.duration = self._open_slices[-1].start - self.start
116
117 def FinalizeImport(self): 133 def FinalizeImport(self):
118 self._BuildSliceSubRows() 134 self._BuildSliceSubRows()
119 135
120 def _BuildSliceSubRows(self): 136 def _BuildSliceSubRows(self):
121 '''This function works by walking through slices by start time. 137 '''This function works by walking through slices by start time.
122 138
123 The basic idea here is to insert each slice as deep into the subrow 139 The basic idea here is to insert each slice as deep into the subrow
124 list as it can go such that every subslice is fully contained by its 140 list as it can go such that every subslice is fully contained by its
125 parent slice. 141 parent slice.
126 142
(...skipping 21 matching lines...) Expand all
148 0: [ a ] [f] 164 0: [ a ] [f]
149 1: [ b ][e] 165 1: [ b ][e]
150 ''' 166 '''
151 def CompareSlices(s1, s2): 167 def CompareSlices(s1, s2):
152 if s1.start == s2.start: 168 if s1.start == s2.start:
153 # Break ties by having the slice with the greatest 169 # Break ties by having the slice with the greatest
154 # end timestamp come first. 170 # end timestamp come first.
155 return cmp(s2.end, s1.end) 171 return cmp(s2.end, s1.end)
156 return cmp(s1.start, s2.start) 172 return cmp(s1.start, s2.start)
157 173
158 if not len(self._slices): 174 assert len(self._toplevel_slices) == 0
175 if not len(self._newly_added_slices):
159 return 176 return
160 177
161 sorted_slices = sorted(self._slices, cmp=CompareSlices) 178 sorted_slices = sorted(self._newly_added_slices, cmp=CompareSlices)
162 root_slice = sorted_slices[0] 179 root_slice = sorted_slices[0]
180 self._toplevel_slices.append(root_slice)
163 for s in sorted_slices[1:]: 181 for s in sorted_slices[1:]:
164 if not self._AddSliceIfBounds(root_slice, s): 182 if not self._AddSliceIfBounds(root_slice, s):
165 root_slice = s 183 root_slice = s
184 self._toplevel_slices.append(root_slice)
185 self._newly_added_slices = []
166 186
167 def _AddSliceIfBounds(self, root, child): 187 def _AddSliceIfBounds(self, root, child):
168 ''' Adds a child slice to a root slice its proper row. 188 ''' Adds a child slice to a root slice its proper row.
169 Return False if the child slice is not in the bounds 189 Return False if the child slice is not in the bounds
170 of the root slice. 190 of the root slice.
171 191
172 Because we know that the start time of child is >= the start time 192 Because we know that the start time of child is >= the start time
173 of all other slices seen so far, we can just check the last slice 193 of all other slices seen so far, we can just check the last slice
174 of each row for bounding. 194 of each row for bounding.
175 ''' 195 '''
176 if child.start >= root.start and child.end <= root.end: 196 if child.start >= root.start and child.end <= root.end:
177 if len(root.sub_slices) > 0: 197 if len(root.sub_slices) > 0:
178 if self._AddSliceIfBounds(root.sub_slices[-1], child): 198 if self._AddSliceIfBounds(root.sub_slices[-1], child):
179 return True 199 return True
200 child.parent_slice = root
180 root.AddSubSlice(child) 201 root.AddSubSlice(child)
181 return True 202 return True
182 return False 203 return False
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698