| Index: tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
|
| diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
|
| index 1a483b8e4bc54f8e2f579010f7b704eba6836940..e53bf417016ed133a2266c407ce577583dc789b0 100644
|
| --- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
|
| +++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
|
| @@ -30,76 +30,53 @@ class NotEnoughFramesError(page_measurement.MeasurementFailure):
|
| '- Pages that can\'t be scrolled')
|
|
|
|
|
| -def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range):
|
| - """Get scroll events' LatencyInfo from the browser process's trace buffer
|
| - that are within the timeline_range.
|
| +def GetInputLatencyEvents(process, timeline_range):
|
| + """Get input events' LatencyInfo from the process's trace buffer that are
|
| + within the timeline_range.
|
|
|
| - Scroll events (MouseWheel, GestureScrollUpdate or JS scroll on TouchMove)
|
| - dump their LatencyInfo into trace buffer as async trace event with name
|
| - "InputLatency". The trace event has a memeber 'step' containing its event
|
| - type and a memeber 'data' containing its latency history.
|
| + Input events dump their LatencyInfo into trace buffer as async trace event
|
| + with name "InputLatency". The trace event has a memeber 'data' containing
|
| + its latency history.
|
|
|
| """
|
| - scroll_events = []
|
| - if not browser_process:
|
| - return scroll_events
|
| - for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"):
|
| + input_events = []
|
| + if not process:
|
| + return input_events
|
| + for event in process.IterAllAsyncSlicesOfName("InputLatency"):
|
| if event.start >= timeline_range.min and event.end <= timeline_range.max:
|
| for ss in event.sub_slices:
|
| - if 'step' not in ss.args:
|
| - continue
|
| - if 'data' not in ss.args:
|
| - continue
|
| - if ss.args['step'] == scroll_type:
|
| - scroll_events.append(ss)
|
| - return scroll_events
|
| -
|
| -
|
| -def ComputeMouseWheelScrollLatency(mouse_wheel_events):
|
| - """ Compute the mouse wheel scroll latency.
|
| -
|
| - Mouse wheel scroll latency is the time from when mouse wheel event is sent
|
| - from browser RWH to renderer (the timestamp of component
|
| - 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is
|
| - buffer swapped (the timestamp of component
|
| - 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT')
|
| -
|
| - """
|
| - mouse_wheel_latency = []
|
| - for event in mouse_wheel_events:
|
| - data = event.args['data']
|
| - if BEGIN_COMP_NAME in data and END_COMP_NAME in data:
|
| - latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']
|
| - mouse_wheel_latency.append(latency / 1000.0)
|
| - return mouse_wheel_latency
|
| -
|
| -
|
| -def ComputeTouchScrollLatency(touch_scroll_events):
|
| - """ Compute the touch scroll latency.
|
| -
|
| - Touch scroll latency is the time from when the touch event is created to
|
| - when the scrolled page is buffer swapped.
|
| - Touch event on differnt platforms uses different LatencyInfo component to
|
| - record its creation timestamp. On Aura, the creation time is kept in
|
| - 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept
|
| - in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'.
|
| + if 'data' in ss.args:
|
| + input_events.append(ss)
|
| + return input_events
|
| +
|
| +def ComputeInputEventLatency(input_events):
|
| + """ Compute the input event latency.
|
| +
|
| + Input event latency is the time from when the input event is created to
|
| + when its resulted page is swap buffered.
|
| + Input event on differnt platforms uses different LatencyInfo component to
|
| + record its creation timestamp. We go through the following component list
|
| + to find the creation timestamp:
|
| + 1. INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT -- when event is created in OS
|
| + 2. INPUT_EVENT_LATENCY_UI_COMPONENT -- when event reaches Chrome
|
| + 3. INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT -- when event reaches RenderWidget
|
|
|
| """
|
| - touch_scroll_latency = []
|
| - for event in touch_scroll_events:
|
| + input_event_latency = []
|
| + for event in input_events:
|
| data = event.args['data']
|
| if END_COMP_NAME in data:
|
| end_time = data[END_COMP_NAME]['time']
|
| - if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data:
|
| - raise ValueError, 'LatencyInfo has both UI and ORIGINAL component'
|
| - if UI_COMP_NAME in data:
|
| - latency = end_time - data[UI_COMP_NAME]['time']
|
| - touch_scroll_latency.append(latency / 1000.0)
|
| - elif ORIGINAL_COMP_NAME in data:
|
| + if ORIGINAL_COMP_NAME in data:
|
| latency = end_time - data[ORIGINAL_COMP_NAME]['time']
|
| - touch_scroll_latency.append(latency / 1000.0)
|
| - return touch_scroll_latency
|
| -
|
| + elif UI_COMP_NAME in data:
|
| + latency = end_time - data[UI_COMP_NAME]['time']
|
| + elif BEGIN_COMP_NAME in data:
|
| + latency = end_time - data[BEGIN_COMP_NAME]['time']
|
| + else:
|
| + raise ValueError, 'LatencyInfo has no begin component'
|
| + input_event_latency.append(latency / 1000.0)
|
| + return input_event_latency
|
|
|
| def HasRenderingStats(process):
|
| """ Returns True if the process contains at least one
|
| @@ -146,15 +123,9 @@ class RenderingStats(object):
|
| self.rasterize_times = []
|
| self.rasterized_pixel_counts = []
|
| self.approximated_pixel_percentages = []
|
| - # End-to-end latency for MouseWheel scroll - from when mouse wheel event is
|
| - # generated to when the scrolled page is buffer swapped.
|
| - self.mouse_wheel_scroll_latency = []
|
| - # End-to-end latency for GestureScrollUpdate scroll - from when the touch
|
| - # event is generated to the scrolled page is buffer swapped.
|
| - self.touch_scroll_latency = []
|
| - # End-to-end latency for JS touch handler scrolling - from when the touch
|
| - # event is generated to the scrolled page is buffer swapped.
|
| - self.js_touch_scroll_latency = []
|
| + # End-to-end latency for input event - from when input event is
|
| + # generated to when the its resulted page is swap buffered.
|
| + self.input_event_latency = []
|
|
|
| for timeline_range in timeline_ranges:
|
| self.frame_timestamps.append([])
|
| @@ -166,9 +137,7 @@ class RenderingStats(object):
|
| self.rasterize_times.append([])
|
| self.rasterized_pixel_counts.append([])
|
| self.approximated_pixel_percentages.append([])
|
| - self.mouse_wheel_scroll_latency.append([])
|
| - self.touch_scroll_latency.append([])
|
| - self.js_touch_scroll_latency.append([])
|
| + self.input_event_latency.append([])
|
|
|
| if timeline_range.is_empty:
|
| continue
|
| @@ -177,7 +146,8 @@ class RenderingStats(object):
|
| renderer_process, timeline_range)
|
| self._InitImplThreadRenderingStatsFromTimeline(
|
| renderer_process, timeline_range)
|
| - self._InitScrollLatencyStatsFromTimeline(browser_process, timeline_range)
|
| + self._InitInputLatencyStatsFromTimeline(
|
| + browser_process, renderer_process, timeline_range)
|
|
|
| # Check if we have collected at least 2 frames in every range. Otherwise we
|
| # can't compute any meaningful metrics.
|
| @@ -185,21 +155,13 @@ class RenderingStats(object):
|
| if len(segment) < 2:
|
| raise NotEnoughFramesError(len(segment))
|
|
|
| - def _InitScrollLatencyStatsFromTimeline(
|
| - self, browser_process, timeline_range):
|
| - mouse_wheel_events = GetScrollInputLatencyEvents(
|
| - "MouseWheel", browser_process, timeline_range)
|
| - self.mouse_wheel_scroll_latency = ComputeMouseWheelScrollLatency(
|
| - mouse_wheel_events)
|
| -
|
| - touch_scroll_events = GetScrollInputLatencyEvents(
|
| - "GestureScrollUpdate", browser_process, timeline_range)
|
| - self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events)
|
| -
|
| - js_touch_scroll_events = GetScrollInputLatencyEvents(
|
| - "TouchMove", browser_process, timeline_range)
|
| - self.js_touch_scroll_latency = ComputeTouchScrollLatency(
|
| - js_touch_scroll_events)
|
| + def _InitInputLatencyStatsFromTimeline(
|
| + self, browser_process, renderer_process, timeline_range):
|
| + latency_events = GetInputLatencyEvents(browser_process, timeline_range)
|
| + # Plugin input event's latency slice is generated in renderer process.
|
| + latency_events.extend(GetInputLatencyEvents(renderer_process,
|
| + timeline_range))
|
| + self.input_event_latency[-1] = ComputeInputEventLatency(latency_events)
|
|
|
| def _GatherEvents(self, event_name, process, timeline_range):
|
| events = []
|
|
|