def event_intervals(self, name=None, task=None, interval=None, match_exact=True): """Returns event intervals for specified `name` and `task` Name here implies `section` or `counter` name. """ if name is None: intervals = \ IntervalList(sorted_items(self._tmw_intervals_by_name.values())) elif isinstance(name, string_types): if match_exact: intervals = self._tmw_intervals_by_name[name] else: intervals = IntervalList( sorted_items(value for key, value in self._tmw_intervals_by_name.iteritems() if name in key)) else: # assume iterable (must match exact) intervals = IntervalList( sorted_items( value for key, value in self._tmw_intervals_by_name.iteritems() if key in name)) intervals = intervals.slice(interval=interval) if task: intervals = IntervalList( filter(lambda it: it.event.task == task, intervals)) return intervals
def pwrstate_intervals(self, device=None, state=None, interval=None): """ Returns pwr state intervals for specified state (if any) on device (if any) over the specified interval (if any). """ try: self._pwrstate_intervals_by_device.keys() except AttributeError: self._pwrstate_events_handler() try: if device is not None: intervals = self._pwrstate_intervals_by_device[device] else: intervals = IntervalList( sorted_items( self._pwrstate_intervals_by_device.values())) if is_list_like(state): filter_func = (lambda ti: ti.state in state) if state else None else: filter_func = (lambda ti: ti.state == state) if state else None return IntervalList(filter(filter_func, intervals.slice(interval=interval))) except: return IntervalList()
def lpm_intervals(self, cluster=None, interval=None): """Return Idle interval for specified cpu & interval when cluster is IDLE (in LPM) state """ try: return IntervalList( filter( lambda cii: cii.state == BusyState.IDLE, self.cluster_intervals(cluster=cluster, interval=interval))) except: return IntervalList()
def busy_intervals(self, cluster=None, interval=None): """Return Busy interval for specified cluster & interval when cluster is not IDLE (in LPM) state """ try: return IntervalList( filter( lambda cii: cii.state != BusyState.IDLE, self.cluster_intervals(cluster=cluster, interval=interval))) except: return IntervalList()
def bimc_aggregate_requests(self, interval=None): """ Returns alll votes between BIMC clock changes. """ rv = IntervalList() votes = {} max_voter, max_vote = '', 0 for bimc_interval in \ self._trace.clock.frequency_intervals(clock='bimc_clk', interval=interval): for bus_requests in self.bus_request_intervals( interval=bimc_interval.interval): ib_vote = bus_requests.instantaneous_bw_GBps device = bus_requests.device + ' ' + repr( bus_requests.master_slave) votes[device] = ib_vote if ib_vote > max_vote: max_voter = device max_vote = ib_vote rv.append( AggBusRequestInterval(votes=votes, max_voter=max_voter, interval=bimc_interval.interval)) return rv
def io_request_intervals(self, op=None, interval=None, by='issue'): """Returns event intervals for specified `op` If by ='issue' (default): returns intervals from block issue ==> complete Elif by = 'insert': returns intervals from insert to queue ==> complete For list of io_types (aka ops) see `trace.disk.ops` # TODO: Filter by # of sectors & devices. See `DiskIOType` in `ftrace.io` for op. """ if by == 'insert': interval_dict = self._io_insert_intervals_by_op else: interval_dict = self._io_issue_intervals_by_op if op is None: intervals = \ IntervalList(sorted_items(interval_dict.values())) else: intervals = interval_dict[op] intervals = intervals.slice(interval=interval) return intervals
def open_camera_intervals(self, interval=None): """ Returns list of intervals to open camera device. Camera open should return in 200ms, and must return in 500ms. References: [1] http://source.android.com/devices/camera/camera3_requests_hal.html [2] https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/camera3.h """ rv = IntervalList() # Several device vendors have different names cam_open_events = self._trace.android.event_intervals( name='openCameraDevice', interval=interval) # Typical of SS if not cam_open_events: cam_open_events = self._trace.android.event_intervals( name='AndroidCamera.open', interval=interval) # Huawei for cam_open_event in cam_open_events: interval = cam_open_event.interval if interval.duration > 0.5: log.warn("Camera open exceeded 500ms recommended time") rv.append( CameraLatency(op="Open Camera Device", interval=interval, latency=interval.duration)) return rv
def input_events(self, task=None, interval=None): all_inputs = self.event_intervals(name='aq:pending:', task=task, interval=interval, match_exact=False) return IntervalList( filter(lambda input_event: input_event.value == 1, all_inputs))
def frequency_intervals(self, device=None, interval=None): """Returns freq intervals for specified interval on device""" try: self._pwrlevel_intervals_by_device.keys() except AttributeError: self._pwrlevel_events_handler() try: if device is not None: intervals = self._pwrlevel_intervals_by_device[device] else: intervals = IntervalList( sorted_items( self._pwrlevel_intervals_by_device.values())) return intervals.slice(interval=interval) except: return IntervalList()
def buslevel_intervals(self, device=None, interval=None): """ """ try: self._buslevel_intervals_by_device.keys() except AttributeError: self._buslevel_events_handler() try: if device is not None: intervals = self._buslevel_intervals_by_device[device] else: intervals = IntervalList( sorted_items( self._buslevel_intervals_by_device.values())) return intervals.slice(interval=interval) except: return IntervalList()
def clock_intervals(self, clock, state=None, interval=None): """Returns clock (enabled/disabled) intervals for specified `clock`. For list of clocks, dump `names` """ try: clk_intervals = \ self._clk_intervals_by_clock[clock].slice(interval=interval) except AttributeError: clk_intervals = \ self._clk_events_handler()[clock].slice(interval=interval) except KeyError: log.warn('No such clock: {clock} in {clocks}'.format( clock=clock, clocks=self.names)) return IntervalList() # Hack in case clock was always ON: if not clk_intervals and self.frequency_intervals(clock=clock, interval=interval): clk_intervals = IntervalList([ClkInterval(clock, ClockState.ENABLED, self._trace.interval)]) filter_func = lambda ci: ci.state is state if state else None return IntervalList(filter(filter_func, clk_intervals)).slice(interval=interval)
def rendering_intervals(self, interval=None): """ """ frames = self.frame_intervals(interval=interval) rendering_intervals = IntervalList() slice_start = frames[0].interval.start for i, j in zip(frames[:-1], frames[1:]): if j.interval.start - i.interval.end > 2 * VSYNC: # new group of frames. ri = Rendering(interval=Interval(slice_start, i.interval.end)) rendering_intervals.append(ri) slice_start = j.interval.start return rendering_intervals
def _switch_device_latency_handler(self): """ Returns list of all input events """ self._switch_latencies = IntervalList() deliver_inputs = self._trace.android.event_intervals( "deliverInputEvent") def _preview_intervals(): """ Generator that yields intervals when still images are captured """ last_timestamp = self._trace.interval.start sp_events = self._trace.android.event_intervals( 'doStopPreviewSync') if not sp_events: preview_events = self._trace.android.event_intervals( 'AndroidCamera.startPreview') if preview_events: camera_task = preview_events[0].event.task sp_events = (context for context in \ self._trace.android.event_intervals('disconnect') \ if context.event.task.pid == camera_task.pid) for sp_event in sp_events: yield Interval(last_timestamp, sp_event.interval.start) last_timestamp = sp_event.interval.start for interval in _preview_intervals(): touch_events = deliver_inputs.slice(interval=interval, trimmed=False) if touch_events: start_ts = touch_events[-1].interval.start end_ts = start_ts post_touch_interval = Interval(start_ts, self._trace.duration) si_events = self._trace.android.event_intervals( name='StartPreviewThread', interval=post_touch_interval) if not si_events: si_events = self._trace.android.event_intervals( name='AndroidCamera.startPreview', interval=post_touch_interval) if si_events: end_ts = si_events[0].interval.end shutter_lag_interval = Interval(start=start_ts, end=end_ts) self._switch_latencies.append( CameraLatency("Camera Switch", interval=shutter_lag_interval, latency=shutter_lag_interval.duration)) return self._switch_latencies
def bus_request_intervals(self, device=None, state=None, interval=None): """Return device interval for specified cpu & interval """ try: self._bur_intervals_by_dev except AttributeError: _ = self._bur_events_handler() if device is not None: try: intervals = self._bur_intervals_by_dev[device].slice( interval=interval) except KeyError: log.warn('No such device: {device} in {devices}'.format( device=device, devices=self.names)) interval = IntervalList() else: intervals = IntervalList( sorted_items(self._bur_intervals_by_dev.values())).slice( interval=interval) filter_func = (lambda bi: bi.state is state) if state else None return IntervalList(filter(filter_func, intervals))
def cluster_intervals(self, cluster, interval=None): """Return interval for specified cluster & interval """ try: self._cluster_idle_intervals_by_cluster except AttributeError: _ = self._cluster_idle_events_handler() if cluster is not None: intervals = self._cluster_idle_intervals_by_cluster[cluster] else: intervals = IntervalList( sorted_items(self._cluster_idle_intervals_by_cluster.values())) return intervals.slice(interval=interval)
def store_image_intervals(self, interval=None): """ Returns list of intervals to store image intervals. # IMPORTANT: Not supported on Huawei devices yet. Missing markers. """ rv = IntervalList() for store_image_event in self._trace.android.event_intervals( name='storeImage', interval=interval): interval = store_image_event.interval rv.append( CameraLatency(op="Store Image/ Add To Media Store", interval=interval, latency=interval.duration)) return rv
def _shutter_lag_latency_handler(self): """ Returns list of all input events """ self._shutter_lag_latencies = IntervalList() deliver_inputs = self._trace.android.event_intervals( "deliverInputEvent") def _still_capture_intervals(): """ Generator that yields intervals when still images are captured """ last_timestamp = self._trace.interval.start for tp_event in self._trace.android.event_intervals( 'doTakePictureAsync'): yield Interval(last_timestamp, tp_event.interval.start) last_timestamp = tp_event.interval.start for interval in _still_capture_intervals(): touch_events = deliver_inputs.slice(interval=interval, trimmed=False) # Necessary as we may be interested in different IRQ name if touch_events: # Use last input event within this interval start_ts = touch_events[-1].interval.start end_ts = start_ts post_touch_interval = Interval(interval.end, self._trace.duration) si_events = self._trace.android.event_intervals( name='storeImage', interval=post_touch_interval) if si_events: end_ts = si_events[0].interval.end shutter_lag_interval = Interval(start=start_ts, end=end_ts) self._shutter_lag_latencies.append( CameraLatency("Shutter Lag", interval=shutter_lag_interval, latency=shutter_lag_interval.duration)) return self._shutter_lag_latencies
def _input_latency_handler(self, irq_name): """ Returns list of all input events """ self._input_latencies = IntervalList() all_tasks = self._trace.cpu.task_intervals() all_aq_events = self.input_events() touch_irqs = IntervalList( filter_by_task(all_tasks, 'name', irq_name, 'any')) def _input_intervals(): """ Generator that yields intervals when discrete input event(s) are read & decoded by Android `Input Reader`. x__x__x____IR___ID_ID_ID___DI_SU__DI_SU__DI_SU______ x = multiple input IRQs (multi-touch translated by Android Input Framework) IR = Input Reader [read/decodes multiple events @ once] ID = Input Dispatch [dispatches each input event] DI = Deliver Input [ appropriate window consumes input event ] SU = SurfaceFlinger Screen Update due to window handling input event Please note InputReader 'iq' will be set to 1 whenever InputReader had event to process. This could be disabled in some systems. """ last_timestamp = self._trace.interval.start for ir_event in filter_by_task(all_tasks, 'name', 'InputReader', 'any'): yield Interval(last_timestamp, ir_event.interval.end) last_timestamp = ir_event.interval.end for interval in _input_intervals(): irqs = touch_irqs.slice(interval=interval, trimmed=False) # Necessary as we may be interested in different IRQ name if irqs: # Use longest IRQ start_ts = max( irqs, key=lambda x: x.interval.duration).interval.start end_ts = start_ts post_ir_interval = Interval(start_ts, self._trace.duration) di_events = self.event_intervals( name=['deliverInputEvent', 'input'], interval=post_ir_interval) if di_events: # IMPORTANT: If InputDispatcher sythesizes multiple # events to same application, we ignore consequent event # and only parse 1st event. This is because we heuristically # can't determine start of next input event to differentiate. di_event = di_events[0] # necessary in case a synthetic events is cancelled # canceled appropriately when the events are no longer # being resynthesized (because the application or IME is # already handling them or dropping them entirely) # This is done by checking for dumping input latencies when # active input event queue length (aq) is > 1 for same task. # For more details, see # https://android.googlesource.com/platform/frameworks/base.git/+ # /f9e989d5f09e72f5c9a59d713521f37d3fdd93dd%5E!/ # This returns first interval when aq has pending event(s) di_event_name = getattr(di_event, 'name', None) if di_event_name and di_event_name == 'input': pfb_events = self.event_intervals( name='doComposition', interval=post_ir_interval) else: aq_event = filter_by_task( all_aq_events.slice(interval=post_ir_interval), 'pid', di_event.event.task.pid) if aq_event and aq_event.value > 0: post_di_start = aq_event.interval.start else: if aq_event: continue # if AQ event exists. post_di_start = di_events[0].interval.start post_di_interval = Interval(post_di_start, self._trace.duration) pfb_events = self.event_intervals( name='doComposition', interval=post_di_interval) if pfb_events: end_ts = pfb_events[0].interval.end if start_ts != end_ts and end_ts > start_ts and start_ts not in self._input_latencies._start_timestamps: input_interval = Interval(start=start_ts, end=end_ts) self._input_latencies.append( InputLatency(interval=input_interval, latency=input_interval.duration)) return self._input_latencies
def jank_intervals(self, interval=None): """ Returns list of intervals when a jank (missed frame) occurred. """ missedFrames = self.event_intervals('FrameMissed', interval=interval) return IntervalList(filter(lambda x: x.value == 1, missedFrames))