1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch# Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch# found in the LICENSE file. 4116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport telemetry.timeline.async_slice as async_slice_module 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import telemetry.timeline.event_container as event_container 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport telemetry.timeline.flow_event as flow_event_module 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import telemetry.timeline.sample as sample_module 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport telemetry.timeline.slice as slice_module 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 11a3f7b4e666c476898878fa745f637129375cd889Ben Murdochclass Thread(event_container.TimelineEventContainer): 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' A Thread stores all the trace events collected for a particular 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch thread. We organize the synchronous slices on a thread by "subrows," where 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on. 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch The asynchronous slices are stored in an AsyncSliceGroup object. 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def __init__(self, process, tid): 18a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch super(Thread, self).__init__('thread %s' % tid, parent=process) 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self.tid = tid 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._async_slices = [] 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._flow_events = [] 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._samples = [] 23a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._toplevel_slices = [] 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._all_slices = [] 25a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 26a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch # State only valid during import. 27a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._open_slices = [] 28a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._newly_added_slices = [] 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch @property 31a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch def toplevel_slices(self): 32a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return self._toplevel_slices 33a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 34a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch @property 35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch def all_slices(self): 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return self._all_slices 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch @property 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def samples(self): 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return self._samples 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch @property 43a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch def async_slices(self): 44a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return self._async_slices 45a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 46a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch @property 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def open_slice_count(self): 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return len(self._open_slices) 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch def IterChildContainers(self): 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield # pylint: disable=W0101 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def IterEventsInThisContainer(self, event_type_predicate, event_predicate): 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_type_predicate(slice_module.Slice): 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for s in self._newly_added_slices: 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(s): 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield s 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for s in self._all_slices: 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(s): 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield s 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_type_predicate(async_slice_module.AsyncSlice): 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for async_slice in self._async_slices: 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(async_slice): 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield async_slice 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for sub_slice in async_slice.IterEventsInThisContainerRecrusively(): 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(sub_slice): 69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield sub_slice 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_type_predicate(flow_event_module.FlowEvent): 72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for flow_event in self._flow_events: 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(flow_event): 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield flow_event 75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_type_predicate(sample_module.Sample): 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for sample in self._samples: 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if event_predicate(sample): 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch yield sample 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def AddSample(self, category, name, timestamp, args=None): 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if len(self._samples) and timestamp < self._samples[-1].start: 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch raise ValueError( 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'Samples must be added in increasing timestamp order') 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch sample = sample_module.Sample(self, 86a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch category, name, timestamp, args=args) 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._samples.append(sample) 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def AddAsyncSlice(self, async_slice): 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._async_slices.append(async_slice) 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def AddFlowEvent(self, flow_event): 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._flow_events.append(flow_event) 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) def BeginSlice(self, category, name, timestamp, thread_timestamp=None, 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) args=None): 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch """Opens a new slice for the thread. 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Calls to beginSlice and endSlice must be made with 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch non-monotonically-decreasing timestamps. 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * category: Category to which the slice belongs. 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * name: Name of the slice to add. 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * timestamp: The timetsamp of the slice, in milliseconds. 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * thread_timestamp: Thread specific clock (scheduled) timestamp of the 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) slice, in milliseconds. 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * args: Arguments associated with 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Returns newly opened slice 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch """ 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if len(self._open_slices) > 0 and timestamp < self._open_slices[-1].start: 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch raise ValueError( 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'Slices must be added in increasing timestamp order') 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new_slice = slice_module.Slice(self, category, name, timestamp, 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) thread_timestamp=thread_timestamp, 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) args=args) 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self._open_slices.append(new_slice) 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) new_slice.did_not_finish = True 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.PushSlice(new_slice) 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return new_slice 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) def EndSlice(self, end_timestamp, end_thread_timestamp=None): 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch """ Ends the last begun slice in this group and pushes it onto the slice 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch array. 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * end_timestamp: Timestamp when the slice ended in milliseconds 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * end_thread_timestamp: Timestamp when the scheduled time of the slice ended 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) in milliseconds 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch returns completed slice. 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch """ 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if not len(self._open_slices): 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch raise ValueError( 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'EndSlice called without an open slice') 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch curr_slice = self._open_slices.pop() 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if end_timestamp < curr_slice.start: 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch raise ValueError( 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'Slice %s end time is before its start.' % curr_slice.name) 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch curr_slice.duration = end_timestamp - curr_slice.start 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if end_thread_timestamp != None: 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if curr_slice.thread_start == None: 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) raise ValueError( 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'EndSlice with thread_timestamp called on open slice without ' + 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'thread_timestamp') 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) curr_slice.thread_duration = (end_thread_timestamp - 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) curr_slice.thread_start) 1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) curr_slice.did_not_finish = False 1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return curr_slice 1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) def PushCompleteSlice(self, category, name, timestamp, duration, 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) thread_timestamp, thread_duration, args=None): 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new_slice = slice_module.Slice(self, category, name, timestamp, 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch thread_timestamp=thread_timestamp, 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch args=args) 1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if duration == None: 1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) new_slice.did_not_finish = True 1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) else: 1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) new_slice.duration = duration 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new_slice.thread_duration = thread_duration 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.PushSlice(new_slice) 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return new_slice 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def PushSlice(self, new_slice): 163a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._newly_added_slices.append(new_slice) 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return new_slice 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) def AutoCloseOpenSlices(self, max_timestamp, max_thread_timestamp): 1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for s in self._newly_added_slices: 1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if s.did_not_finish: 1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) s.duration = max_timestamp - s.start 1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) assert s.duration >= 0 171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if s.thread_start != None: 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) s.thread_duration = max_thread_timestamp - s.thread_start 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert s.thread_duration >= 0 1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self._open_slices = [] 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def IsTimestampValidForBeginOrEnd(self, timestamp): 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if not len(self._open_slices): 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return True 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return timestamp >= self._open_slices[-1].start 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def FinalizeImport(self): 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._BuildSliceSubRows() 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def _BuildSliceSubRows(self): 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch '''This function works by walking through slices by start time. 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch The basic idea here is to insert each slice as deep into the subrow 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch list as it can go such that every subslice is fully contained by its 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch parent slice. 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Visually, if we start with this: 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 0: [ a ] 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1: [ b ] 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2: [c][d] 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch To place this slice: 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch [e] 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch We first check row 2's last item, [d]. [e] wont fit into [d] (they dont 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch even intersect). So we go to row 1. That gives us [b], and [d] wont fit 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch into that either. So, we go to row 0 and its last slice, [a]. That can 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch completely contain [e], so that means we should add [e] as a subslice 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch of [a]. That puts it on row 1, yielding: 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 0: [ a ] 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1: [ b ][e] 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2: [c][d] 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch If we then get this slice: 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch [f] 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch We do the same deepest-to-shallowest walk of the subrows trying to fit 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it. This time, it doesn't fit in any open slice. So, we simply append 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it to row 0 (a root slice): 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 0: [ a ] [f] 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1: [ b ][e] 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def CompareSlices(s1, s2): 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if s1.start == s2.start: 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # Break ties by having the slice with the greatest 218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # end timestamp come first. 219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return cmp(s2.end, s1.end) 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return cmp(s1.start, s2.start) 221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 222a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch assert len(self._toplevel_slices) == 0 223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch assert len(self._all_slices) == 0 224a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if not len(self._newly_added_slices): 225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return 226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._all_slices.extend(self._newly_added_slices) 228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 229a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch sorted_slices = sorted(self._newly_added_slices, cmp=CompareSlices) 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch root_slice = sorted_slices[0] 231a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._toplevel_slices.append(root_slice) 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for s in sorted_slices[1:]: 233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if not self._AddSliceIfBounds(root_slice, s): 234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch root_slice = s 235a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._toplevel_slices.append(root_slice) 236a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch self._newly_added_slices = [] 237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def _AddSliceIfBounds(self, root, child): 240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' Adds a child slice to a root slice its proper row. 241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Return False if the child slice is not in the bounds 242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch of the root slice. 243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Because we know that the start time of child is >= the start time 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch of all other slices seen so far, we can just check the last slice 246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch of each row for bounding. 247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # The source trace data is in microseconds but we store it as milliseconds 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # in floating-point. Since we can't represent micros as millis perfectly, 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # two end=start+duration combos that should be the same will be slightly 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # different. Round back to micros to ensure equality below. 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) child_end_micros = round(child.end * 1000) 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) root_end_micros = round(root.end * 1000) 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if child.start >= root.start and child_end_micros <= root_end_micros: 255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if len(root.sub_slices) > 0: 256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if self._AddSliceIfBounds(root.sub_slices[-1], child): 257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return True 258a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch child.parent_slice = root 259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch root.AddSubSlice(child) 260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return True 261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return False 262