Beispiel #1
0
    def _audio_flinger_handler(self, buffer_size_frames=None):
        """
        Parses audio callback routines.
        """
        
        all_tasks = self._trace.cpu.task_intervals()
        self._OSL_cbks = IntervalList(filter_by_task(all_tasks, 'name', 'OSLcbk', 'any'))

        self._fRdy2s = self._trace.android.event_intervals(name='fRdy2')
        
        # Lets estimate buffer size (in seconds)
        # By taking geomean of intervals between OSL callbacks
        cbk_delta = [cbk_b.interval.start - cbk_a.interval.start \
            for cbk_a, cbk_b in zip(self._OSL_cbks, self._OSL_cbks[1:])]
        
        self.buffer_size_seconds = round(percentile(cbk_delta, 0.9), 3)
        
        # Find audio jitter intervals
        # This is delta (in seconds) between expected OSL callback arrival time
        # and actual arrival time. We want this interval reasonably small.
        self._cbk_jitters = IntervalList()
        for cbk_a, cbk_b in zip(self._OSL_cbks, self._OSL_cbks[1:]):
            expected_cbk_arrival_time = \
                cbk_a.interval.start  + self.buffer_size_seconds
            delta = cbk_b.interval.start - expected_cbk_arrival_time
            interval = Interval(cbk_a.interval.start, cbk_b.interval.start)
            self._cbk_jitters.append(AudioJitter(interval=interval, latency=delta))
        
        if self.buffer_size_frames is None:
            # Estimate buffer sizes (frames)
            self.buffer_size_frames = int(percentile([frdy.value for frdy in self._fRdy2s if frdy.value >= 0], 0.9))
        else:
            self.buffer_size_frames = buffer_size_frames
Beispiel #2
0
        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
Beispiel #3
0
    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