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

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

Issue 174663008: re-land: Use browser compositor rendering stats in smoothness (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Check if browser process is None. Created 6 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/perf/metrics/rendering_stats_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 7 # These are LatencyInfo component names indicating the various components
8 # that the input event has travelled through. 8 # that the input event has travelled through.
9 # This is when the input event first reaches chrome. 9 # This is when the input event first reaches chrome.
10 UI_COMP_NAME = 'INPUT_EVENT_LATENCY_UI_COMPONENT' 10 UI_COMP_NAME = 'INPUT_EVENT_LATENCY_UI_COMPONENT'
11 # This is when the input event was originally created by OS. 11 # This is when the input event was originally created by OS.
12 ORIGINAL_COMP_NAME = 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT' 12 ORIGINAL_COMP_NAME = 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'
13 # This is when the input event was sent from browser to renderer. 13 # This is when the input event was sent from browser to renderer.
14 BEGIN_COMP_NAME = 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT' 14 BEGIN_COMP_NAME = 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT'
15 # This is when the input event has reached swap buffer. 15 # This is when the input event has reached swap buffer.
16 END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT' 16 END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT'
17 17
18
18 def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range): 19 def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range):
19 """Get scroll events' LatencyInfo from the browser process's trace buffer 20 """Get scroll events' LatencyInfo from the browser process's trace buffer
20 that are within the timeline_range. 21 that are within the timeline_range.
21 22
22 Scroll events (MouseWheel, GestureScrollUpdate or JS scroll on TouchMove) 23 Scroll events (MouseWheel, GestureScrollUpdate or JS scroll on TouchMove)
23 dump their LatencyInfo into trace buffer as async trace event with name 24 dump their LatencyInfo into trace buffer as async trace event with name
24 "InputLatency". The trace event has a memeber 'step' containing its event 25 "InputLatency". The trace event has a memeber 'step' containing its event
25 type and a memeber 'data' containing its latency history. 26 type and a memeber 'data' containing its latency history.
26 27
27 """ 28 """
28 scroll_events = [] 29 scroll_events = []
29 if not browser_process: 30 if not browser_process:
30 return scroll_events 31 return scroll_events
31 for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"): 32 for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"):
32 if event.start >= timeline_range.min and event.end <= timeline_range.max: 33 if event.start >= timeline_range.min and event.end <= timeline_range.max:
33 for ss in event.sub_slices: 34 for ss in event.sub_slices:
34 if 'step' not in ss.args: 35 if 'step' not in ss.args:
35 continue 36 continue
36 if 'data' not in ss.args: 37 if 'data' not in ss.args:
37 continue 38 continue
38 if ss.args['step'] == scroll_type: 39 if ss.args['step'] == scroll_type:
39 scroll_events.append(ss) 40 scroll_events.append(ss)
40 return scroll_events 41 return scroll_events
41 42
43
42 def ComputeMouseWheelScrollLatency(mouse_wheel_events): 44 def ComputeMouseWheelScrollLatency(mouse_wheel_events):
43 """ Compute the mouse wheel scroll latency. 45 """ Compute the mouse wheel scroll latency.
44 46
45 Mouse wheel scroll latency is the time from when mouse wheel event is sent 47 Mouse wheel scroll latency is the time from when mouse wheel event is sent
46 from browser RWH to renderer (the timestamp of component 48 from browser RWH to renderer (the timestamp of component
47 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is 49 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is
48 buffer swapped (the timestamp of component 50 buffer swapped (the timestamp of component
49 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT') 51 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT')
50 52
51 """ 53 """
52 mouse_wheel_latency = [] 54 mouse_wheel_latency = []
53 for event in mouse_wheel_events: 55 for event in mouse_wheel_events:
54 data = event.args['data'] 56 data = event.args['data']
55 if BEGIN_COMP_NAME in data and END_COMP_NAME in data: 57 if BEGIN_COMP_NAME in data and END_COMP_NAME in data:
56 latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time'] 58 latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']
57 mouse_wheel_latency.append(latency / 1000.0) 59 mouse_wheel_latency.append(latency / 1000.0)
58 return mouse_wheel_latency 60 return mouse_wheel_latency
59 61
62
60 def ComputeTouchScrollLatency(touch_scroll_events): 63 def ComputeTouchScrollLatency(touch_scroll_events):
61 """ Compute the touch scroll latency. 64 """ Compute the touch scroll latency.
62 65
63 Touch scroll latency is the time from when the touch event is created to 66 Touch scroll latency is the time from when the touch event is created to
64 when the scrolled page is buffer swapped. 67 when the scrolled page is buffer swapped.
65 Touch event on differnt platforms uses different LatencyInfo component to 68 Touch event on differnt platforms uses different LatencyInfo component to
66 record its creation timestamp. On Aura, the creation time is kept in 69 record its creation timestamp. On Aura, the creation time is kept in
67 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept 70 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept
68 in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'. 71 in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'.
69 72
70 """ 73 """
71 touch_scroll_latency = [] 74 touch_scroll_latency = []
72 for event in touch_scroll_events: 75 for event in touch_scroll_events:
73 data = event.args['data'] 76 data = event.args['data']
74 if END_COMP_NAME in data: 77 if END_COMP_NAME in data:
75 end_time = data[END_COMP_NAME]['time'] 78 end_time = data[END_COMP_NAME]['time']
76 if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data: 79 if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data:
77 raise ValueError, 'LatencyInfo has both UI and ORIGINAL component' 80 raise ValueError, 'LatencyInfo has both UI and ORIGINAL component'
78 if UI_COMP_NAME in data: 81 if UI_COMP_NAME in data:
79 latency = end_time - data[UI_COMP_NAME]['time'] 82 latency = end_time - data[UI_COMP_NAME]['time']
80 touch_scroll_latency.append(latency / 1000.0) 83 touch_scroll_latency.append(latency / 1000.0)
81 elif ORIGINAL_COMP_NAME in data: 84 elif ORIGINAL_COMP_NAME in data:
82 latency = end_time - data[ORIGINAL_COMP_NAME]['time'] 85 latency = end_time - data[ORIGINAL_COMP_NAME]['time']
83 touch_scroll_latency.append(latency / 1000.0) 86 touch_scroll_latency.append(latency / 1000.0)
84 return touch_scroll_latency 87 return touch_scroll_latency
85 88
89
90 def HasRenderingStats(process):
91 """ Returns True if the process contains at least one
92 BenchmarkInstrumentation::*RenderingStats event with a frame.
93 """
94 if not process:
95 return False
96 for event in process.IterAllSlicesOfName(
97 'BenchmarkInstrumentation::MainThreadRenderingStats'):
98 if 'data' in event.args and event.args['data']['frame_count'] == 1:
99 return True
100 for event in process.IterAllSlicesOfName(
101 'BenchmarkInstrumentation::ImplThreadRenderingStats'):
102 if 'data' in event.args and event.args['data']['frame_count'] == 1:
103 return True
104 return False
105
106
86 class RenderingStats(object): 107 class RenderingStats(object):
87 def __init__(self, renderer_process, browser_process, timeline_ranges): 108 def __init__(self, renderer_process, browser_process, timeline_ranges):
88 """ 109 """
89 Utility class for extracting rendering statistics from the timeline (or 110 Utility class for extracting rendering statistics from the timeline (or
90 other loggin facilities), and providing them in a common format to classes 111 other loggin facilities), and providing them in a common format to classes
91 that compute benchmark metrics from this data. 112 that compute benchmark metrics from this data.
92 113
93 Stats are lists of lists of numbers. The outer list stores one list per 114 Stats are lists of lists of numbers. The outer list stores one list per
94 timeline range. 115 timeline range.
95 116
96 All *_time values are measured in milliseconds. 117 All *_time values are measured in milliseconds.
97 """ 118 """
98 assert(len(timeline_ranges) > 0) 119 assert(len(timeline_ranges) > 0)
99 self.renderer_process = renderer_process 120 # Find the top level process with rendering stats (browser or renderer).
121 if HasRenderingStats(browser_process):
122 self.top_level_process = browser_process
123 else:
124 self.top_level_process = renderer_process
100 125
101 self.frame_timestamps = [] 126 self.frame_timestamps = []
102 self.frame_times = [] 127 self.frame_times = []
103 self.paint_times = [] 128 self.paint_times = []
104 self.painted_pixel_counts = [] 129 self.painted_pixel_counts = []
105 self.record_times = [] 130 self.record_times = []
106 self.recorded_pixel_counts = [] 131 self.recorded_pixel_counts = []
107 self.rasterize_times = [] 132 self.rasterize_times = []
108 self.rasterized_pixel_counts = [] 133 self.rasterized_pixel_counts = []
109 # End-to-end latency for MouseWheel scroll - from when mouse wheel event is 134 # End-to-end latency for MouseWheel scroll - from when mouse wheel event is
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events) 171 self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events)
147 172
148 js_touch_scroll_events = GetScrollInputLatencyEvents( 173 js_touch_scroll_events = GetScrollInputLatencyEvents(
149 "TouchMove", browser_process, timeline_range) 174 "TouchMove", browser_process, timeline_range)
150 self.js_touch_scroll_latency = ComputeTouchScrollLatency( 175 self.js_touch_scroll_latency = ComputeTouchScrollLatency(
151 js_touch_scroll_events) 176 js_touch_scroll_events)
152 177
153 def initMainThreadStatsFromTimeline(self, timeline_range): 178 def initMainThreadStatsFromTimeline(self, timeline_range):
154 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats' 179 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats'
155 events = [] 180 events = []
156 for event in self.renderer_process.IterAllSlicesOfName(event_name): 181 for event in self.top_level_process.IterAllSlicesOfName(event_name):
157 if event.start >= timeline_range.min and event.end <= timeline_range.max: 182 if event.start >= timeline_range.min and event.end <= timeline_range.max:
158 if 'data' not in event.args: 183 if 'data' not in event.args:
159 continue 184 continue
160 events.append(event) 185 events.append(event)
161 events.sort(key=attrgetter('start')) 186 events.sort(key=attrgetter('start'))
162 187
163 first_frame = True 188 first_frame = True
164 for event in events: 189 for event in events:
165 frame_count = event.args['data']['frame_count'] 190 frame_count = event.args['data']['frame_count']
166 if frame_count > 1: 191 if frame_count > 1:
(...skipping 10 matching lines...) Expand all
177 self.painted_pixel_counts[-1].append( 202 self.painted_pixel_counts[-1].append(
178 event.args['data']['painted_pixel_count']) 203 event.args['data']['painted_pixel_count'])
179 self.record_times[-1].append(1000.0 * 204 self.record_times[-1].append(1000.0 *
180 event.args['data']['record_time']) 205 event.args['data']['record_time'])
181 self.recorded_pixel_counts[-1].append( 206 self.recorded_pixel_counts[-1].append(
182 event.args['data']['recorded_pixel_count']) 207 event.args['data']['recorded_pixel_count'])
183 208
184 def initImplThreadStatsFromTimeline(self, timeline_range): 209 def initImplThreadStatsFromTimeline(self, timeline_range):
185 event_name = 'BenchmarkInstrumentation::ImplThreadRenderingStats' 210 event_name = 'BenchmarkInstrumentation::ImplThreadRenderingStats'
186 events = [] 211 events = []
187 for event in self.renderer_process.IterAllSlicesOfName(event_name): 212 for event in self.top_level_process.IterAllSlicesOfName(event_name):
188 if event.start >= timeline_range.min and event.end <= timeline_range.max: 213 if event.start >= timeline_range.min and event.end <= timeline_range.max:
189 if 'data' not in event.args: 214 if 'data' not in event.args:
190 continue 215 continue
191 events.append(event) 216 events.append(event)
192 events.sort(key=attrgetter('start')) 217 events.sort(key=attrgetter('start'))
193 218
194 first_frame = True 219 first_frame = True
195 for event in events: 220 for event in events:
196 frame_count = event.args['data']['frame_count'] 221 frame_count = event.args['data']['frame_count']
197 if frame_count > 1: 222 if frame_count > 1:
198 raise ValueError, 'trace contains multi-frame render stats' 223 raise ValueError, 'trace contains multi-frame render stats'
199 if frame_count == 1: 224 if frame_count == 1:
200 self.frame_timestamps[-1].append( 225 self.frame_timestamps[-1].append(
201 event.start) 226 event.start)
202 if not first_frame: 227 if not first_frame:
203 self.frame_times[-1].append(round(self.frame_timestamps[-1][-1] - 228 self.frame_times[-1].append(round(self.frame_timestamps[-1][-1] -
204 self.frame_timestamps[-1][-2], 2)) 229 self.frame_timestamps[-1][-2], 2))
205 first_frame = False 230 first_frame = False
206 self.rasterize_times[-1].append(1000.0 * 231 self.rasterize_times[-1].append(1000.0 *
207 event.args['data']['rasterize_time']) 232 event.args['data']['rasterize_time'])
208 self.rasterized_pixel_counts[-1].append( 233 self.rasterized_pixel_counts[-1].append(
209 event.args['data']['rasterized_pixel_count']) 234 event.args['data']['rasterized_pixel_count'])
OLDNEW
« no previous file with comments | « no previous file | tools/perf/metrics/rendering_stats_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698