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

Side by Side Diff: tools/telemetry/telemetry/web_perf/timeline_interaction_record.py

Issue 273103003: Add responsiveness_metric for timeline_based_measurement (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Chris's comments Created 6 years, 6 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 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 import re 5 import re
6 6
7 from telemetry import decorators 7 from telemetry import decorators
8 import telemetry.core.timeline.bounds as timeline_bounds 8 import telemetry.core.timeline.bounds as timeline_bounds
9 9
10 10
11 IS_SMOOTH = 'is_smooth' 11 IS_SMOOTH = 'is_smooth'
12 IS_LOADING_RESOURCES = 'is_loading_resources' 12 IS_RESPONSIVE = 'is_responsive'
13 13
14 FLAGS = [ 14 FLAGS = [
15 IS_SMOOTH, 15 IS_SMOOTH,
16 IS_LOADING_RESOURCES 16 IS_RESPONSIVE
17 ] 17 ]
18 18
19 19
20 class ThreadTimeRangeOverlappedException(Exception): 20 class ThreadTimeRangeOverlappedException(Exception):
21 """Exception that can be thrown when computing overlapped thread time range 21 """Exception that can be thrown when computing overlapped thread time range
22 with other events. 22 with other events.
23 """ 23 """
24 24
25 class NoThreadTimeDataException(ThreadTimeRangeOverlappedException):
26 """Exception that can be thrown if there is not sufficient thread time data
27 to compute the overlapped thread time range."""
25 28
26 def IsTimelineInteractionRecord(event_name): 29 def IsTimelineInteractionRecord(event_name):
27 return event_name.startswith('Interaction.') 30 return event_name.startswith('Interaction.')
28 31
29 32
30 class TimelineInteractionRecord(object): 33 class TimelineInteractionRecord(object):
31 """Represents an interaction that took place during a timeline recording. 34 """Represents an interaction that took place during a timeline recording.
32 35
33 As a page runs, typically a number of different (simulated) user interactions 36 As a page runs, typically a number of different (simulated) user interactions
34 take place. For instance, a user might click a button in a mail app causing a 37 take place. For instance, a user might click a button in a mail app causing a
(...skipping 10 matching lines...) Expand all
45 Determining these things is hard to do, simply by observing the state given to 48 Determining these things is hard to do, simply by observing the state given to
46 a page from javascript. There are hints, for instance if network requests are 49 a page from javascript. There are hints, for instance if network requests are
47 sent, or if a CSS animation is pending. But this is by no means a complete 50 sent, or if a CSS animation is pending. But this is by no means a complete
48 story. 51 story.
49 52
50 Instead, we expect pages to mark up the timeline what they are doing, with 53 Instead, we expect pages to mark up the timeline what they are doing, with
51 logical names, and flags indicating the semantics of that interaction. This 54 logical names, and flags indicating the semantics of that interaction. This
52 is currently done by pushing markers into the console.time/timeEnd API: this 55 is currently done by pushing markers into the console.time/timeEnd API: this
53 for instance can be issued in JS: 56 for instance can be issued in JS:
54 57
55 var str = 'Interaction.SendEmail/is_smooth,is_loading_resources'; 58 var str = 'Interaction.SendEmail/is_smooth,is_responsive';
56 console.time(str); 59 console.time(str);
57 setTimeout(function() { 60 setTimeout(function() {
58 console.timeEnd(str); 61 console.timeEnd(str);
59 }, 1000); 62 }, 1000);
60 63
61 When run with perf.measurements.timeline_based_measurement running, this will 64 When run with perf.measurements.timeline_based_measurement running, this will
62 then cause a TimelineInteractionRecord to be created for this range and both 65 then cause a TimelineInteractionRecord to be created for this range and both
63 smoothness and network metrics to be reported for the marked up 1000ms 66 smoothness and network metrics to be reported for the marked up 1000ms
64 time-range. 67 time-range.
65 68
66 """ 69 """
67 70
68 def __init__(self, logical_name, start, end, async_event=None): 71 def __init__(self, logical_name, start, end, async_event=None):
69 assert logical_name 72 assert logical_name
70 self.logical_name = logical_name 73 self.logical_name = logical_name
71 self.start = start 74 self.start = start
72 self.end = end 75 self.end = end
73 self.is_smooth = False 76 self.is_smooth = False
74 self.is_loading_resources = False 77 self.is_responsive = False
75 self._async_event = async_event 78 self._async_event = async_event
76 79
77 # TODO(nednguyen): After crbug.com/367175 is marked fixed, we should be able 80 # TODO(nednguyen): After crbug.com/367175 is marked fixed, we should be able
78 # to get rid of perf.measurements.smooth_gesture_util and make this the only 81 # to get rid of perf.measurements.smooth_gesture_util and make this the only
79 # constructor method for TimelineInteractionRecord. 82 # constructor method for TimelineInteractionRecord.
80 @staticmethod 83 @staticmethod
81 def FromAsyncEvent(async_event): 84 def FromAsyncEvent(async_event):
82 """Construct an timeline_interaction_record from an async event. 85 """Construct an timeline_interaction_record from an async event.
83 Args: 86 Args:
84 async_event: An instance of 87 async_event: An instance of
85 telemetry.core.timeline.async_slices.AsyncSlice 88 telemetry.core.timeline.async_slices.AsyncSlice
86 """ 89 """
90 assert async_event.start_thread == async_event.end_thread, (
91 'Start thread of this record\'s async event is not the same as its '
92 'end thread')
87 m = re.match('Interaction\.(.+)\/(.+)', async_event.name) 93 m = re.match('Interaction\.(.+)\/(.+)', async_event.name)
88 if m: 94 if m:
89 logical_name = m.group(1) 95 logical_name = m.group(1)
90 if m.group(1) != '': 96 if m.group(1) != '':
91 flags = m.group(2).split(',') 97 flags = m.group(2).split(',')
92 else: 98 else:
93 flags = [] 99 flags = []
94 else: 100 else:
95 m = re.match('Interaction\.(.+)', async_event.name) 101 m = re.match('Interaction\.(.+)', async_event.name)
96 assert m 102 assert m
97 logical_name = m.group(1) 103 logical_name = m.group(1)
98 flags = [] 104 flags = []
99 105
100 record = TimelineInteractionRecord(logical_name, async_event.start, 106 record = TimelineInteractionRecord(logical_name, async_event.start,
101 async_event.end, async_event) 107 async_event.end, async_event)
102 for f in flags: 108 for f in flags:
103 if not f in FLAGS: 109 if not f in FLAGS:
104 raise Exception( 110 raise Exception(
105 'Unrecognized flag in timeline Interaction record: %s' % f) 111 'Unrecognized flag in timeline Interaction record: %s' % f)
106 record.is_smooth = IS_SMOOTH in flags 112 record.is_smooth = IS_SMOOTH in flags
107 record.is_loading_resources = IS_LOADING_RESOURCES in flags 113 record.is_responsive = IS_RESPONSIVE in flags
108 return record 114 return record
109 115
110 def GetResultNameFor(self, result_name): 116 def GetResultNameFor(self, result_name):
111 return '%s-%s' % (self.logical_name, result_name) 117 return '%s-%s' % (self.logical_name, result_name)
112 118
113 @decorators.Cache 119 @decorators.Cache
114 def GetBounds(self): 120 def GetBounds(self):
115 bounds = timeline_bounds.Bounds() 121 bounds = timeline_bounds.Bounds()
116 bounds.AddValue(self.start) 122 bounds.AddValue(self.start)
117 bounds.AddValue(self.end) 123 bounds.AddValue(self.end)
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 thread, and thus can't be used to compute the overlapped thread duration. 168 thread, and thus can't be used to compute the overlapped thread duration.
163 Hence, we use a heuristic to compute the overlap (see 169 Hence, we use a heuristic to compute the overlap (see
164 _GetOverlappedThreadTimeForSliceInDifferentThread for more details) 170 _GetOverlappedThreadTimeForSliceInDifferentThread for more details)
165 171
166 Args: 172 Args:
167 timeline_slice: An instance of telemetry.core.timeline.slice.Slice 173 timeline_slice: An instance of telemetry.core.timeline.slice.Slice
168 """ 174 """
169 if not self._async_event: 175 if not self._async_event:
170 raise ThreadTimeRangeOverlappedException( 176 raise ThreadTimeRangeOverlappedException(
171 'This record was not constructed from async event') 177 'This record was not constructed from async event')
172 if self._async_event.start_thread != self._async_event.end_thread:
173 raise ThreadTimeRangeOverlappedException(
174 'Start thread of this record\'s async event is not the same as its '
175 'end thread')
176 if not self._async_event.has_thread_timestamps: 178 if not self._async_event.has_thread_timestamps:
177 raise ThreadTimeRangeOverlappedException( 179 raise NoThreadTimeDataException(
178 'This record\'s async_event does not contain thread time data. ' 180 'This record\'s async_event does not contain thread time data. '
179 'Event data: %s' % repr(self._async_event)) 181 'Event data: %s' % repr(self._async_event))
180 if not timeline_slice.has_thread_timestamps: 182 if not timeline_slice.has_thread_timestamps:
181 raise ThreadTimeRangeOverlappedException( 183 raise NoThreadTimeDataException(
182 'slice does not contain thread time data') 184 'slice does not contain thread time data')
183 185
184 if timeline_slice.parent_thread == self._async_event.start_thread: 186 if timeline_slice.parent_thread == self._async_event.start_thread:
185 return self._GetOverlappedThreadTimeForSliceInSameThread( 187 return self._GetOverlappedThreadTimeForSliceInSameThread(
186 timeline_slice) 188 timeline_slice)
187 else: 189 else:
188 return self._GetOverlappedThreadTimeForSliceInDifferentThread( 190 return self._GetOverlappedThreadTimeForSliceInDifferentThread(
189 timeline_slice) 191 timeline_slice)
190 192
191 def _GetOverlappedThreadTimeForSliceInSameThread(self, timeline_slice): 193 def _GetOverlappedThreadTimeForSliceInSameThread(self, timeline_slice):
(...skipping 11 matching lines...) Expand all
203 timeline_slice.start, timeline_slice.end, 205 timeline_slice.start, timeline_slice.end,
204 self.start, self.end) 206 self.start, self.end)
205 if timeline_slice.duration == 0 or self._async_event.duration == 0: 207 if timeline_slice.duration == 0 or self._async_event.duration == 0:
206 return 0 208 return 0
207 timeline_slice_scheduled_ratio = ( 209 timeline_slice_scheduled_ratio = (
208 timeline_slice.thread_duration / float(timeline_slice.duration)) 210 timeline_slice.thread_duration / float(timeline_slice.duration))
209 record_scheduled_ratio = ( 211 record_scheduled_ratio = (
210 self._async_event.thread_duration / float(self._async_event.duration)) 212 self._async_event.thread_duration / float(self._async_event.duration))
211 return (overlapped_walltime_duration * timeline_slice_scheduled_ratio * 213 return (overlapped_walltime_duration * timeline_slice_scheduled_ratio *
212 record_scheduled_ratio) 214 record_scheduled_ratio)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698