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

Side by Side Diff: tools/perf/metrics/rendering_stats.py

Issue 132433004: Collecting LatencyInfo in telemetry (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: fix presubmit error "unused variable" Created 6 years, 10 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
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 from operator import attrgetter 5 from operator import attrgetter
6 6
7 # These are LatencyInfo component names indicating the various components
8 # that the input event has travelled through.
9 # This is when the input event first reaches chrome.
10 UI_COMP_NAME = 'INPUT_EVENT_LATENCY_UI_COMPONENT'
11 # This is when the input event was originally created by OS.
12 ORIGINAL_COMP_NAME = 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'
13 # This is when the input event was sent from browser to renderer.
14 BEGIN_COMP_NAME = 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT'
15 # This is when the input event has reached swap buffer.
16 END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT'
17
18 def GetScrollInputLatencyEvents(browser_process, timeline_range):
19 """Get scroll events' LatencyInfo from the browser process's trace buffer
20 that are within the timeline_range.
21
22 Scroll events (MouseWheel or GestureScrollUpdate) dump their LatencyInfo
23 into trace buffer as async trace event with name "InputLatency". The trace
24 event has a memeber 'step' containing its event type and a memeber 'data'
25 containing its latency history.
26
27 """
28 mouse_wheel_events = []
29 touch_scroll_events = []
30 if not browser_process:
31 return (mouse_wheel_events, touch_scroll_events)
32 for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"):
33 if event.start >= timeline_range.min and event.end <= timeline_range.max:
34 for ss in event.sub_slices:
35 if 'step' not in ss.args:
36 continue
37 if 'data' not in ss.args:
38 continue
39 if ss.args['step'] == 'MouseWheel':
40 mouse_wheel_events.append(ss)
41 elif ss.args['step'] == 'GestureScrollUpdate':
42 touch_scroll_events.append(ss)
43 return (mouse_wheel_events, touch_scroll_events)
44
45 def ComputeMouseWheelScrollLatency(mouse_wheel_events):
46 """ Compute the mouse wheel scroll latency.
47
48 Mouse wheel scroll latency is the time from when mouse wheel event is sent
49 from browser RWH to renderer (the timestamp of component
50 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is
51 buffer swapped (the timestamp of component
52 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT')
53
54 """
55 mouse_wheel_latency = []
56 for event in mouse_wheel_events:
57 data = event.args['data']
58 if BEGIN_COMP_NAME in data and END_COMP_NAME in data:
59 latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']
60 mouse_wheel_latency.append(latency / 1000.0)
61 return mouse_wheel_latency
62
63 def ComputeTouchScrollLatency(touch_scroll_events):
64 """ Compute the touch scroll latency.
65
66 Touch scroll latency is the time from when the touch event is created to
67 when the scrolled page is buffer swapped.
68 Touch event on differnt platforms uses different LatencyInfo component to
69 record its creation timestamp. On Aura, the creation time is kept in
70 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept
71 in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'.
72
73 """
74 touch_scroll_latency = []
75 for event in touch_scroll_events:
76 data = event.args['data']
77 if END_COMP_NAME in data:
78 end_time = data[END_COMP_NAME]['time']
79 if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data:
80 raise ValueError, 'LatencyInfo has both UI and ORIGINAL component'
81 if UI_COMP_NAME in data:
82 latency = end_time - data[UI_COMP_NAME]['time']
83 touch_scroll_latency.append(latency / 1000.0)
84 elif ORIGINAL_COMP_NAME in data:
85 latency = end_time - data[ORIGINAL_COMP_NAME]['time']
86 touch_scroll_latency.append(latency / 1000.0)
87 return touch_scroll_latency
7 88
8 class RenderingStats(object): 89 class RenderingStats(object):
9 def __init__(self, renderer_process, timeline_ranges): 90 def __init__(self, renderer_process, browser_process, timeline_ranges):
10 """ 91 """
11 Utility class for extracting rendering statistics from the timeline (or 92 Utility class for extracting rendering statistics from the timeline (or
12 other loggin facilities), and providing them in a common format to classes 93 other loggin facilities), and providing them in a common format to classes
13 that compute benchmark metrics from this data. 94 that compute benchmark metrics from this data.
14 95
15 Stats are lists of lists of numbers. The outer list stores one list per 96 Stats are lists of lists of numbers. The outer list stores one list per
16 timeline range. 97 timeline range.
17 98
18 All *_time values are measured in milliseconds. 99 All *_time values are measured in milliseconds.
19 """ 100 """
20 assert(len(timeline_ranges) > 0) 101 assert(len(timeline_ranges) > 0)
21 self.renderer_process = renderer_process 102 self.renderer_process = renderer_process
22 103
23 self.frame_timestamps = [] 104 self.frame_timestamps = []
24 self.frame_times = [] 105 self.frame_times = []
25 self.paint_times = [] 106 self.paint_times = []
26 self.painted_pixel_counts = [] 107 self.painted_pixel_counts = []
27 self.record_times = [] 108 self.record_times = []
28 self.recorded_pixel_counts = [] 109 self.recorded_pixel_counts = []
29 self.rasterize_times = [] 110 self.rasterize_times = []
30 self.rasterized_pixel_counts = [] 111 self.rasterized_pixel_counts = []
112 # End-to-end latency for MouseWheel scroll - from when mouse wheel event is
113 # generated to when the scrolled page is buffer swapped.
114 self.mouse_wheel_scroll_latency = []
115 # End-to-end latency for touch scroll event - from when the touch event is
116 # generated to the scrolled page is buffer swapped.
117 self.touch_scroll_latency = []
31 118
32 for timeline_range in timeline_ranges: 119 for timeline_range in timeline_ranges:
33 self.frame_timestamps.append([]) 120 self.frame_timestamps.append([])
34 self.frame_times.append([]) 121 self.frame_times.append([])
35 self.paint_times.append([]) 122 self.paint_times.append([])
36 self.painted_pixel_counts.append([]) 123 self.painted_pixel_counts.append([])
37 self.record_times.append([]) 124 self.record_times.append([])
38 self.recorded_pixel_counts.append([]) 125 self.recorded_pixel_counts.append([])
39 self.rasterize_times.append([]) 126 self.rasterize_times.append([])
40 self.rasterized_pixel_counts.append([]) 127 self.rasterized_pixel_counts.append([])
128 self.mouse_wheel_scroll_latency.append([])
129 self.touch_scroll_latency.append([])
41 130
42 if timeline_range.is_empty: 131 if timeline_range.is_empty:
43 continue 132 continue
44 self.initMainThreadStatsFromTimeline(timeline_range) 133 self.initMainThreadStatsFromTimeline(timeline_range)
45 self.initImplThreadStatsFromTimeline(timeline_range) 134 self.initImplThreadStatsFromTimeline(timeline_range)
135 self.initScrollLatencyStatsFromTimeline(browser_process, timeline_range)
136
137 def initScrollLatencyStatsFromTimeline(self, browser_process, timeline_range):
138 mouse_wheel_events, touch_scroll_events = GetScrollInputLatencyEvents(
139 browser_process, timeline_range)
140 self.mouse_wheel_scroll_latency = ComputeMouseWheelScrollLatency(
141 mouse_wheel_events)
142 self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events)
46 143
47 def initMainThreadStatsFromTimeline(self, timeline_range): 144 def initMainThreadStatsFromTimeline(self, timeline_range):
48 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats' 145 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats'
49 events = [] 146 events = []
50 for event in self.renderer_process.IterAllSlicesOfName(event_name): 147 for event in self.renderer_process.IterAllSlicesOfName(event_name):
51 if event.start >= timeline_range.min and event.end <= timeline_range.max: 148 if event.start >= timeline_range.min and event.end <= timeline_range.max:
52 if 'data' not in event.args: 149 if 'data' not in event.args:
53 continue 150 continue
54 events.append(event) 151 events.append(event)
55 events.sort(key=attrgetter('start')) 152 events.sort(key=attrgetter('start'))
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 self.frame_timestamps[-1].append( 191 self.frame_timestamps[-1].append(
95 event.start) 192 event.start)
96 if not first_frame: 193 if not first_frame:
97 self.frame_times[-1].append(round(self.frame_timestamps[-1][-1] - 194 self.frame_times[-1].append(round(self.frame_timestamps[-1][-1] -
98 self.frame_timestamps[-1][-2], 2)) 195 self.frame_timestamps[-1][-2], 2))
99 first_frame = False 196 first_frame = False
100 self.rasterize_times[-1].append(1000.0 * 197 self.rasterize_times[-1].append(1000.0 *
101 event.args['data']['rasterize_time']) 198 event.args['data']['rasterize_time'])
102 self.rasterized_pixel_counts[-1].append( 199 self.rasterized_pixel_counts[-1].append(
103 event.args['data']['rasterized_pixel_count']) 200 event.args['data']['rasterized_pixel_count'])
OLDNEW
« no previous file with comments | « tools/perf/measurements/smoothness_unittest.py ('k') | tools/perf/metrics/rendering_stats_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698