OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 /** | 5 /** |
6 * @constructor | 6 * @constructor |
7 */ | 7 */ |
8 WebInspector.TimelineIRModel = function() | 8 WebInspector.TimelineIRModel = function() |
9 { | 9 { |
10 this.reset(); | 10 this.reset(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 75 |
76 var groups = WebInspector.TimelineUIUtils.asyncEventGroups(); | 76 var groups = WebInspector.TimelineUIUtils.asyncEventGroups(); |
77 var asyncEventsByGroup = timelineModel.mainThreadAsyncEvents(); | 77 var asyncEventsByGroup = timelineModel.mainThreadAsyncEvents(); |
78 var inputLatencies = asyncEventsByGroup.get(groups.input); | 78 var inputLatencies = asyncEventsByGroup.get(groups.input); |
79 if (!inputLatencies) | 79 if (!inputLatencies) |
80 return; | 80 return; |
81 this._processInputLatencies(inputLatencies); | 81 this._processInputLatencies(inputLatencies); |
82 var animations = asyncEventsByGroup.get(groups.animation); | 82 var animations = asyncEventsByGroup.get(groups.animation); |
83 if (animations) | 83 if (animations) |
84 this._processAnimations(animations); | 84 this._processAnimations(animations); |
85 var range = new WebInspector.SegmentedRange(); | 85 var range = new SegmentedRange(); |
86 range.appendRange(this._drags); // Drags take lower precedence than anim
ation, as we can't detect them reliably. | 86 range.appendRange(this._drags); // Drags take lower precedence than anim
ation, as we can't detect them reliably. |
87 range.appendRange(this._cssAnimations); | 87 range.appendRange(this._cssAnimations); |
88 range.appendRange(this._scrolls); | 88 range.appendRange(this._scrolls); |
89 range.appendRange(this._responses); | 89 range.appendRange(this._responses); |
90 this._segments = range.segments(); | 90 this._segments = range.segments(); |
91 }, | 91 }, |
92 | 92 |
93 /** | 93 /** |
94 * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} events | 94 * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} events |
95 */ | 95 */ |
(...skipping 26 matching lines...) Expand all Loading... |
122 WebInspector.console.error(WebInspector.UIString("Two flings
at the same time? %s vs %s", flingStart.startTime, event.startTime)); | 122 WebInspector.console.error(WebInspector.UIString("Two flings
at the same time? %s vs %s", flingStart.startTime, event.startTime)); |
123 break; | 123 break; |
124 } | 124 } |
125 flingStart = event; | 125 flingStart = event; |
126 break; | 126 break; |
127 | 127 |
128 case eventTypes.FlingCancel: | 128 case eventTypes.FlingCancel: |
129 // FIXME: also process renderer fling events. | 129 // FIXME: also process renderer fling events. |
130 if (!flingStart) | 130 if (!flingStart) |
131 break; | 131 break; |
132 this._scrolls.append(new WebInspector.Segment(flingStart.startTi
me, event.endTime, phases.Fling)); | 132 this._scrolls.append(new Segment(flingStart.startTime, event.end
Time, phases.Fling)); |
133 flingStart = null; | 133 flingStart = null; |
134 break; | 134 break; |
135 | 135 |
136 case eventTypes.ImplSideFling: | 136 case eventTypes.ImplSideFling: |
137 this._scrolls.append(this._segmentForEvent(event, phases.Fling))
; | 137 this._scrolls.append(this._segmentForEvent(event, phases.Fling))
; |
138 break; | 138 break; |
139 | 139 |
140 case eventTypes.ShowPress: | 140 case eventTypes.ShowPress: |
141 case eventTypes.Tap: | 141 case eventTypes.Tap: |
142 case eventTypes.KeyDown: | 142 case eventTypes.KeyDown: |
(...skipping 18 matching lines...) Expand all Loading... |
161 | 161 |
162 case eventTypes.TouchCancel: | 162 case eventTypes.TouchCancel: |
163 touchStart = null; | 163 touchStart = null; |
164 break; | 164 break; |
165 | 165 |
166 case eventTypes.TouchMove: | 166 case eventTypes.TouchMove: |
167 if (firstTouchMove) { | 167 if (firstTouchMove) { |
168 this._drags.append(this._segmentForEvent(event, phases.Drag)
); | 168 this._drags.append(this._segmentForEvent(event, phases.Drag)
); |
169 } else if (touchStart) { | 169 } else if (touchStart) { |
170 firstTouchMove = event; | 170 firstTouchMove = event; |
171 this._responses.append(new WebInspector.Segment(touchStart.s
tartTime, event.endTime, phases.Response)); | 171 this._responses.append(new Segment(touchStart.startTime, eve
nt.endTime, phases.Response)); |
172 } | 172 } |
173 break; | 173 break; |
174 | 174 |
175 case eventTypes.TouchEnd: | 175 case eventTypes.TouchEnd: |
176 touchStart = null; | 176 touchStart = null; |
177 break; | 177 break; |
178 | 178 |
179 case eventTypes.MouseDown: | 179 case eventTypes.MouseDown: |
180 mouseDown = event; | 180 mouseDown = event; |
181 mouseMove = null; | 181 mouseMove = null; |
(...skipping 10 matching lines...) Expand all Loading... |
192 break; | 192 break; |
193 | 193 |
194 case eventTypes.MouseUp: | 194 case eventTypes.MouseUp: |
195 this._responses.append(this._segmentForEvent(event, phases.Respo
nse)); | 195 this._responses.append(this._segmentForEvent(event, phases.Respo
nse)); |
196 mouseDown = null; | 196 mouseDown = null; |
197 break; | 197 break; |
198 | 198 |
199 case eventTypes.MouseWheel: | 199 case eventTypes.MouseWheel: |
200 // Do not consider first MouseWheel as trace viewer's implementa
tion does -- in case of MouseWheel it's not really special. | 200 // Do not consider first MouseWheel as trace viewer's implementa
tion does -- in case of MouseWheel it's not really special. |
201 if (mouseWheel && canMerge(thresholdsMs.mouse, mouseWheel, event
)) | 201 if (mouseWheel && canMerge(thresholdsMs.mouse, mouseWheel, event
)) |
202 this._scrolls.append(new WebInspector.Segment(mouseWheel.end
Time, event.startTime, phases.Scroll)); | 202 this._scrolls.append(new Segment(mouseWheel.endTime, event.s
tartTime, phases.Scroll)); |
203 this._scrolls.append(this._segmentForEvent(event, phases.Scroll)
); | 203 this._scrolls.append(this._segmentForEvent(event, phases.Scroll)
); |
204 mouseWheel = event; | 204 mouseWheel = event; |
205 break; | 205 break; |
206 } | 206 } |
207 } | 207 } |
208 | 208 |
209 /** | 209 /** |
210 * @param {number} threshold | 210 * @param {number} threshold |
211 * @param {!WebInspector.TracingModel.AsyncEvent} first | 211 * @param {!WebInspector.TracingModel.AsyncEvent} first |
212 * @param {!WebInspector.TracingModel.AsyncEvent} second | 212 * @param {!WebInspector.TracingModel.AsyncEvent} second |
(...skipping 10 matching lines...) Expand all Loading... |
223 */ | 223 */ |
224 _processAnimations: function(events) | 224 _processAnimations: function(events) |
225 { | 225 { |
226 for (var i = 0; i < events.length; ++i) | 226 for (var i = 0; i < events.length; ++i) |
227 this._cssAnimations.append(this._segmentForEvent(events[i], WebInspe
ctor.TimelineIRModel.Phases.Animation)); | 227 this._cssAnimations.append(this._segmentForEvent(events[i], WebInspe
ctor.TimelineIRModel.Phases.Animation)); |
228 }, | 228 }, |
229 | 229 |
230 /** | 230 /** |
231 * @param {!WebInspector.TracingModel.AsyncEvent} event | 231 * @param {!WebInspector.TracingModel.AsyncEvent} event |
232 * @param {!WebInspector.TimelineIRModel.Phases} phase | 232 * @param {!WebInspector.TimelineIRModel.Phases} phase |
233 * @return {!WebInspector.Segment} | 233 * @return {!Segment} |
234 */ | 234 */ |
235 _segmentForEvent: function(event, phase) | 235 _segmentForEvent: function(event, phase) |
236 { | 236 { |
237 return new WebInspector.Segment(event.startTime, event.endTime, phase); | 237 return new Segment(event.startTime, event.endTime, phase); |
238 }, | 238 }, |
239 | 239 |
240 /** | 240 /** |
241 * @return {!Array<!WebInspector.Segment>} | 241 * @return {!Array<!Segment>} |
242 */ | 242 */ |
243 interactionRecords: function() | 243 interactionRecords: function() |
244 { | 244 { |
245 return this._segments; | 245 return this._segments; |
246 }, | 246 }, |
247 | 247 |
248 reset: function() | 248 reset: function() |
249 { | 249 { |
250 var thresholdsMs = WebInspector.TimelineIRModel._mergeThresholdsMs; | 250 var thresholdsMs = WebInspector.TimelineIRModel._mergeThresholdsMs; |
251 | 251 |
252 this._segments = []; | 252 this._segments = []; |
253 this._drags = new WebInspector.SegmentedRange(merge.bind(null, threshold
sMs.mouse)); | 253 this._drags = new SegmentedRange(merge.bind(null, thresholdsMs.mouse)); |
254 this._cssAnimations = new WebInspector.SegmentedRange(merge.bind(null, t
hresholdsMs.animation)); | 254 this._cssAnimations = new SegmentedRange(merge.bind(null, thresholdsMs.a
nimation)); |
255 this._responses = new WebInspector.SegmentedRange(merge.bind(null, 0)); | 255 this._responses = new SegmentedRange(merge.bind(null, 0)); |
256 this._scrolls = new WebInspector.SegmentedRange(merge.bind(null, thresho
ldsMs.animation)); | 256 this._scrolls = new SegmentedRange(merge.bind(null, thresholdsMs.animati
on)); |
257 | 257 |
258 /** | 258 /** |
259 * @param {number} threshold | 259 * @param {number} threshold |
260 * @param {!WebInspector.Segment} first | 260 * @param {!Segment} first |
261 * @param {!WebInspector.Segment} second | 261 * @param {!Segment} second |
262 */ | 262 */ |
263 function merge(threshold, first, second) | 263 function merge(threshold, first, second) |
264 { | 264 { |
265 return first.end + threshold >= second.begin && first.data === secon
d.data ? first : null; | 265 return first.end + threshold >= second.begin && first.data === secon
d.data ? first : null; |
266 } | 266 } |
267 }, | 267 }, |
268 | 268 |
269 /** | 269 /** |
270 * @param {string} eventName | 270 * @param {string} eventName |
271 * @return {?WebInspector.TimelineIRModel.InputEvents} | 271 * @return {?WebInspector.TimelineIRModel.InputEvents} |
272 */ | 272 */ |
273 _inputEventType: function(eventName) | 273 _inputEventType: function(eventName) |
274 { | 274 { |
275 var prefix = "InputLatency::"; | 275 var prefix = "InputLatency::"; |
276 if (!eventName.startsWith(prefix)) { | 276 if (!eventName.startsWith(prefix)) { |
277 if (eventName === WebInspector.TimelineIRModel.InputEvents.ImplSideF
ling) | 277 if (eventName === WebInspector.TimelineIRModel.InputEvents.ImplSideF
ling) |
278 return /** @type {!WebInspector.TimelineIRModel.InputEvents} */
(eventName); | 278 return /** @type {!WebInspector.TimelineIRModel.InputEvents} */
(eventName); |
279 console.error("Unrecognized input latency event: " + eventName); | 279 console.error("Unrecognized input latency event: " + eventName); |
280 return null; | 280 return null; |
281 } | 281 } |
282 return /** @type {!WebInspector.TimelineIRModel.InputEvents} */ (eventNa
me.substr(prefix.length)); | 282 return /** @type {!WebInspector.TimelineIRModel.InputEvents} */ (eventNa
me.substr(prefix.length)); |
283 } | 283 } |
284 }; | 284 }; |
285 | 285 |
286 /** | |
287 * @constructor | |
288 * @param {(function(!WebInspector.Segment, !WebInspector.Segment): ?WebInspecto
r.Segment)=} mergeCallback | |
289 */ | |
290 WebInspector.SegmentedRange = function(mergeCallback) | |
291 { | |
292 /** @type {!Array<!WebInspector.Segment>} */ | |
293 this._segments = []; | |
294 this._mergeCallback = mergeCallback; | |
295 } | |
296 | |
297 /** | |
298 * @constructor | |
299 * @param {number} begin | |
300 * @param {number} end | |
301 * @param {*} data | |
302 */ | |
303 WebInspector.Segment = function(begin, end, data) | |
304 { | |
305 if (begin > end) | |
306 console.assert(false, "Invalid segment"); | |
307 this.begin = begin; | |
308 this.end = end; | |
309 this.data = data; | |
310 } | |
311 | |
312 WebInspector.Segment.prototype = { | |
313 /** | |
314 * @param {!WebInspector.Segment} that | |
315 * @return {boolean} | |
316 */ | |
317 intersects: function(that) | |
318 { | |
319 return this.begin < that.end && that.begin < this.end; | |
320 } | |
321 }; | |
322 | |
323 WebInspector.SegmentedRange.prototype = { | |
324 /** | |
325 * @param {!WebInspector.Segment} newSegment | |
326 */ | |
327 append: function(newSegment) | |
328 { | |
329 // 1. Find the proper insertion point for new segment | |
330 var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin
- b.begin); | |
331 var endIndex = startIndex; | |
332 var merged = null; | |
333 if (startIndex > 0) { | |
334 // 2. Try mering the preceding segment | |
335 var precedingSegment = this._segments[startIndex - 1]; | |
336 merged = this._tryMerge(precedingSegment, newSegment); | |
337 if (merged) { | |
338 --startIndex; | |
339 newSegment = merged; | |
340 } else if (this._segments[startIndex - 1].end >= newSegment.begin) { | |
341 // 2a. If merge failed and segments overlap, adjust preceding se
gment. | |
342 // If an old segment entirely contains new one, split it in two. | |
343 if (newSegment.end < precedingSegment.end) | |
344 this._segments.splice(startIndex, 0, new WebInspector.Segmen
t(newSegment.end, precedingSegment.end, precedingSegment.data)); | |
345 precedingSegment.end = newSegment.begin; | |
346 } | |
347 } | |
348 // 3. Consume all segments that are entirely covered by the new one. | |
349 while (endIndex < this._segments.length && this._segments[endIndex].end
<= newSegment.end) | |
350 ++endIndex; | |
351 // 4. Merge or adjust the succeeding segment if it overlaps. | |
352 if (endIndex < this._segments.length) { | |
353 merged = this._tryMerge(newSegment, this._segments[endIndex]); | |
354 if (merged) { | |
355 endIndex++; | |
356 newSegment = merged; | |
357 } else if (newSegment.intersects(this._segments[endIndex])) | |
358 this._segments[endIndex].begin = newSegment.end; | |
359 } | |
360 this._segments.splice(startIndex, endIndex - startIndex, newSegment); | |
361 }, | |
362 | |
363 /** | |
364 * @param {!WebInspector.SegmentedRange} that | |
365 */ | |
366 appendRange: function(that) | |
367 { | |
368 that.segments().forEach(segment => this.append(segment)); | |
369 }, | |
370 | |
371 /** | |
372 * @return {!Array<!WebInspector.Segment>} | |
373 */ | |
374 segments: function() | |
375 { | |
376 return this._segments; | |
377 }, | |
378 | |
379 /** | |
380 * @param {!WebInspector.Segment} first | |
381 * @param {!WebInspector.Segment} second | |
382 * @return {?WebInspector.Segment} | |
383 */ | |
384 _tryMerge: function(first, second) | |
385 { | |
386 var merged = this._mergeCallback && this._mergeCallback(first, second); | |
387 if (!merged) | |
388 return null; | |
389 merged.begin = first.begin; | |
390 merged.end = Math.max(first.end, second.end); | |
391 return merged; | |
392 } | |
393 } | |
OLD | NEW |