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

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: use 95 percentil for input latency metric Created 6 years, 11 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 7
8 class RenderingStats(object): 8 class RenderingStats(object):
9 def __init__(self, renderer_process, timeline_ranges): 9 def __init__(self, renderer_process, browser_main_thread, timeline_ranges):
10 """ 10 """
11 Utility class for extracting rendering statistics from the timeline (or 11 Utility class for extracting rendering statistics from the timeline (or
12 other loggin facilities), and providing them in a common format to classes 12 other loggin facilities), and providing them in a common format to classes
13 that compute benchmark metrics from this data. 13 that compute benchmark metrics from this data.
14 14
15 Stats can either be numbers, or lists of numbers. Classes that calculate 15 Stats can either be numbers, or lists of numbers. Classes that calculate
16 metrics from the stats must be able to handle both cases. The length of 16 metrics from the stats must be able to handle both cases. The length of
17 different list stats may vary. 17 different list stats may vary.
18 18
19 All *_time values are measured in milliseconds. 19 All *_time values are measured in milliseconds.
20 """ 20 """
21 assert(len(timeline_ranges) > 0) 21 assert(len(timeline_ranges) > 0)
22 self.renderer_process = renderer_process 22 self.renderer_process = renderer_process
23 self.browser_main_thread = browser_main_thread
23 24
24 self.frame_timestamps = [] 25 self.frame_timestamps = []
25 self.frame_times = [] 26 self.frame_times = []
26 self.paint_time = [] 27 self.paint_time = []
27 self.painted_pixel_count = [] 28 self.painted_pixel_count = []
28 self.record_time = [] 29 self.record_time = []
29 self.recorded_pixel_count = [] 30 self.recorded_pixel_count = []
30 self.rasterize_time = [] 31 self.rasterize_time = []
31 self.rasterized_pixel_count = [] 32 self.rasterized_pixel_count = []
33 self.mouse_wheel_latency = []
34 self.gesture_scroll_latency = []
35 self.touch_scroll_latency = []
32 36
33 for timeline_range in timeline_ranges: 37 for timeline_range in timeline_ranges:
34 if timeline_range.is_empty: 38 if timeline_range.is_empty:
35 continue 39 continue
36 self.initMainThreadStatsFromTimeline(timeline_range) 40 self.initMainThreadStatsFromTimeline(timeline_range)
37 self.initImplThreadStatsFromTimeline(timeline_range) 41 self.initImplThreadStatsFromTimeline(timeline_range)
42 if self.browser_main_thread:
43 self.initInputLatencyFromTimeline(timeline_range)
44
45 def initInputLatencyFromTimeline(self, timeline_range):
46 event_name = "InputLatency"
47 ui_comp_name = 'INPUT_EVENT_LATENCY_UI_COMPONENT'
nduca 2014/01/23 18:34:45 this code is incredibly dense and hard to read and
Yufeng Shen (Slow to review) 2014/01/30 01:16:05 I refactored this into a few helper functions, hop
48 original_comp_name = 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'
49 begin_comp_name = 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT'
50 end_comp_name = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT'
51 mouse_wheel_events = []
52 scroll_events = []
53 for event in self.browser_main_thread.IterAllAsyncSlicesOfName(event_name):
nduca 2014/01/23 18:34:45 i dont get the point of event_name as a variable h
nduca 2014/01/23 18:34:45 this function should really be split into a few fu
54 if event.start >= timeline_range.min and event.end <= timeline_range.max:
55 for ss in event.sub_slices:
56 if 'step' not in ss.args:
57 continue
58 if 'data' not in ss.args:
59 continue
60 if ss.args['step'] == 'MouseWheel':
61 mouse_wheel_events.append(ss)
62 elif ss.args['step'] == 'GestureScrollUpdate':
63 scroll_events.append(ss)
64
65 # mouse_wheel_latency is the time from when mouse wheel event reaches RWH
66 # to buffer swapped.
67 for event in mouse_wheel_events:
68 data = event.args['data']
69 if begin_comp_name in data and end_comp_name in data:
70 latency = data[end_comp_name]['time'] - data[begin_comp_name]['time']
71 self.mouse_wheel_latency.append(latency / 1000.0)
72
73 # gesture_scroll_latency is the time from when gesture scroll event reaches
74 # RWH to buffer swapped. It is available on all platforms.
75 # touch_scroll_latency is the time from when the touch event is created
76 # to when the buffer swapped due to the scroll generated from the original
77 # touch event. On Aura, the starting timestamp is kept in UI_COMPONENT, and
78 # on Android, the starting timestamp is kept in ORIGINAL_COMPONENT.
79 for event in scroll_events:
80 data = event.args['data']
81 if end_comp_name in data:
82 end_time = data[end_comp_name]['time']
83 if begin_comp_name in data:
nduca 2014/01/23 18:34:45 this huge set of branches shold be broken into a s
84 latency = end_time - data[begin_comp_name]['time']
85 self.gesture_scroll_latency.append(latency / 1000.0)
86 if ui_comp_name in data and original_comp_name in data:
87 raise ValueError, 'LatencyInfo has both UI and ORIGINAL component'
88 if ui_comp_name in data:
89 latency = end_time - data[ui_comp_name]['time']
90 self.touch_scroll_latency.append(latency / 1000.0)
91 elif original_comp_name in data:
92 latency = end_time - data[original_comp_name]['time']
93 self.touch_scroll_latency.append(latency / 1000.0)
38 94
39 def initMainThreadStatsFromTimeline(self, timeline_range): 95 def initMainThreadStatsFromTimeline(self, timeline_range):
40 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats' 96 event_name = 'BenchmarkInstrumentation::MainThreadRenderingStats'
41 events = [] 97 events = []
42 for event in self.renderer_process.IterAllSlicesOfName(event_name): 98 for event in self.renderer_process.IterAllSlicesOfName(event_name):
43 if event.start >= timeline_range.min and event.end <= timeline_range.max: 99 if event.start >= timeline_range.min and event.end <= timeline_range.max:
44 if 'data' not in event.args: 100 if 'data' not in event.args:
45 continue 101 continue
46 events.append(event) 102 events.append(event)
47 events.sort(key=attrgetter('start')) 103 events.sort(key=attrgetter('start'))
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 self.frame_timestamps.append( 142 self.frame_timestamps.append(
87 event.start) 143 event.start)
88 if not first_frame: 144 if not first_frame:
89 self.frame_times.append(round(self.frame_timestamps[-1] - 145 self.frame_times.append(round(self.frame_timestamps[-1] -
90 self.frame_timestamps[-2], 2)) 146 self.frame_timestamps[-2], 2))
91 first_frame = False 147 first_frame = False
92 self.rasterize_time.append(1000.0 * 148 self.rasterize_time.append(1000.0 *
93 event.args['data']['rasterize_time']) 149 event.args['data']['rasterize_time'])
94 self.rasterized_pixel_count.append( 150 self.rasterized_pixel_count.append(
95 event.args['data']['rasterized_pixel_count']) 151 event.args['data']['rasterized_pixel_count'])
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698