OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <!-- | 2 <!-- |
3 Copyright (c) 2013 The Chromium Authors. All rights reserved. | 3 Copyright (c) 2013 The Chromium Authors. All rights reserved. |
4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
5 found in the LICENSE file. | 5 found in the LICENSE file. |
6 --> | 6 --> |
7 | 7 |
8 <link rel="import" href="/tracing/model/async_slice.html"> | 8 <link rel="import" href="/tracing/model/async_slice.html"> |
9 <link rel="import" href="/tracing/model/event_set.html"> | 9 <link rel="import" href="/tracing/model/event_set.html"> |
10 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> | 10 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 TOUCH_END: 'TouchEnd', | 58 TOUCH_END: 'TouchEnd', |
59 TOUCH_MOVE: 'TouchMove', | 59 TOUCH_MOVE: 'TouchMove', |
60 TOUCH_START: 'TouchStart', | 60 TOUCH_START: 'TouchStart', |
61 UNKNOWN: 'UNKNOWN' | 61 UNKNOWN: 'UNKNOWN' |
62 }; | 62 }; |
63 | 63 |
64 function InputLatencyAsyncSlice() { | 64 function InputLatencyAsyncSlice() { |
65 AsyncSlice.apply(this, arguments); | 65 AsyncSlice.apply(this, arguments); |
66 this.associatedEvents_ = new EventSet(); | 66 this.associatedEvents_ = new EventSet(); |
67 this.typeName_ = undefined; | 67 this.typeName_ = undefined; |
68 if (!this.isLegacyEvent) | 68 if (!this.isLegacyEvent) { |
69 this.determineModernTypeName_(); | 69 this.determineModernTypeName_(); |
| 70 } |
70 } | 71 } |
71 | 72 |
72 InputLatencyAsyncSlice.prototype = { | 73 InputLatencyAsyncSlice.prototype = { |
73 __proto__: AsyncSlice.prototype, | 74 __proto__: AsyncSlice.prototype, |
74 | 75 |
75 // Legacy InputLatencyAsyncSlices involve a top-level slice titled | 76 // Legacy InputLatencyAsyncSlices involve a top-level slice titled |
76 // "InputLatency" containing a subSlice whose title starts with | 77 // "InputLatency" containing a subSlice whose title starts with |
77 // "InputLatency:". Modern InputLatencyAsyncSlices involve a single | 78 // "InputLatency:". Modern InputLatencyAsyncSlices involve a single |
78 // top-level slice whose title starts with "InputLatency::". | 79 // top-level slice whose title starts with "InputLatency::". |
79 // Legacy subSlices are not available at construction time, so | 80 // Legacy subSlices are not available at construction time, so |
80 // determineLegacyTypeName_() must be called at get time. | 81 // determineLegacyTypeName_() must be called at get time. |
81 // So this returns false for the legacy subSlice events titled like | 82 // So this returns false for the legacy subSlice events titled like |
82 // "InputLatency:Foo" even though they are technically legacy events. | 83 // "InputLatency:Foo" even though they are technically legacy events. |
83 get isLegacyEvent() { | 84 get isLegacyEvent() { |
84 return this.title === 'InputLatency'; | 85 return this.title === 'InputLatency'; |
85 }, | 86 }, |
86 | 87 |
87 get typeName() { | 88 get typeName() { |
88 if (!this.typeName_) | 89 if (!this.typeName_) { |
89 this.determineLegacyTypeName_(); | 90 this.determineLegacyTypeName_(); |
| 91 } |
90 return this.typeName_; | 92 return this.typeName_; |
91 }, | 93 }, |
92 | 94 |
93 checkTypeName_: function() { | 95 checkTypeName_: function() { |
94 if (!this.typeName_) | 96 if (!this.typeName_) { |
95 throw new Error('Unable to determine typeName'); | 97 throw new Error('Unable to determine typeName'); |
| 98 } |
96 var found = false; | 99 var found = false; |
97 for (var typeName in INPUT_EVENT_TYPE_NAMES) { | 100 for (var typeName in INPUT_EVENT_TYPE_NAMES) { |
98 if (this.typeName === INPUT_EVENT_TYPE_NAMES[typeName]) { | 101 if (this.typeName === INPUT_EVENT_TYPE_NAMES[typeName]) { |
99 found = true; | 102 found = true; |
100 break; | 103 break; |
101 } | 104 } |
102 } | 105 } |
103 if (!found) | 106 if (!found) { |
104 this.typeName_ = INPUT_EVENT_TYPE_NAMES.UNKNOWN; | 107 this.typeName_ = INPUT_EVENT_TYPE_NAMES.UNKNOWN; |
| 108 } |
105 }, | 109 }, |
106 | 110 |
107 determineModernTypeName_: function() { | 111 determineModernTypeName_: function() { |
108 // This method works both on modern events titled like | 112 // This method works both on modern events titled like |
109 // "InputLatency::Foo" and also on the legacy subSlices titled like | 113 // "InputLatency::Foo" and also on the legacy subSlices titled like |
110 // "InputLatency:Foo". Modern events' titles contain 2 colons, whereas the | 114 // "InputLatency:Foo". Modern events' titles contain 2 colons, whereas the |
111 // legacy subSlices events contain 1 colon. | 115 // legacy subSlices events contain 1 colon. |
112 | 116 |
113 var lastColonIndex = this.title.lastIndexOf(':'); | 117 var lastColonIndex = this.title.lastIndexOf(':'); |
114 if (lastColonIndex < 0) | 118 if (lastColonIndex < 0) return; |
115 return; | |
116 | 119 |
117 var characterAfterLastColonIndex = lastColonIndex + 1; | 120 var characterAfterLastColonIndex = lastColonIndex + 1; |
118 this.typeName_ = this.title.slice(characterAfterLastColonIndex); | 121 this.typeName_ = this.title.slice(characterAfterLastColonIndex); |
119 | 122 |
120 // Check that the determined typeName is known. | 123 // Check that the determined typeName is known. |
121 this.checkTypeName_(); | 124 this.checkTypeName_(); |
122 }, | 125 }, |
123 | 126 |
124 determineLegacyTypeName_: function() { | 127 determineLegacyTypeName_: function() { |
125 // Iterate over all descendent subSlices. | 128 // Iterate over all descendent subSlices. |
126 for (var subSlice of this.enumerateAllDescendents()) { | 129 for (var subSlice of this.enumerateAllDescendents()) { |
127 // If |subSlice| is not an InputLatencyAsyncSlice, then ignore it. | 130 // If |subSlice| is not an InputLatencyAsyncSlice, then ignore it. |
128 var subSliceIsAInputLatencyAsyncSlice = ( | 131 var subSliceIsAInputLatencyAsyncSlice = ( |
129 subSlice instanceof InputLatencyAsyncSlice); | 132 subSlice instanceof InputLatencyAsyncSlice); |
130 if (!subSliceIsAInputLatencyAsyncSlice) | 133 if (!subSliceIsAInputLatencyAsyncSlice) continue; |
131 continue; | |
132 | 134 |
133 // If |subSlice| does not have a typeName, then ignore it. | 135 // If |subSlice| does not have a typeName, then ignore it. |
134 if (!subSlice.typeName) | 136 if (!subSlice.typeName) continue; |
135 continue; | |
136 | 137 |
137 // If |this| already has a typeName and |subSlice| has a different | 138 // If |this| already has a typeName and |subSlice| has a different |
138 // typeName, then explode! | 139 // typeName, then explode! |
139 if (this.typeName_ && subSlice.typeName_) { | 140 if (this.typeName_ && subSlice.typeName_) { |
140 var subSliceHasDifferentTypeName = ( | 141 var subSliceHasDifferentTypeName = ( |
141 this.typeName_ !== subSlice.typeName_); | 142 this.typeName_ !== subSlice.typeName_); |
142 if (subSliceHasDifferentTypeName) { | 143 if (subSliceHasDifferentTypeName) { |
143 throw new Error( | 144 throw new Error( |
144 'InputLatencyAsyncSlice.determineLegacyTypeName_() ' + | 145 'InputLatencyAsyncSlice.determineLegacyTypeName_() ' + |
145 ' found multiple typeNames'); | 146 ' found multiple typeNames'); |
(...skipping 12 matching lines...) Expand all Loading... |
158 } | 159 } |
159 | 160 |
160 // Check that the determined typeName is known. | 161 // Check that the determined typeName is known. |
161 this.checkTypeName_(); | 162 this.checkTypeName_(); |
162 }, | 163 }, |
163 | 164 |
164 getRendererHelper: function(sourceSlices) { | 165 getRendererHelper: function(sourceSlices) { |
165 var traceModel = this.startThread.parent.model; | 166 var traceModel = this.startThread.parent.model; |
166 var modelHelper = traceModel.getOrCreateHelper( | 167 var modelHelper = traceModel.getOrCreateHelper( |
167 tr.model.helpers.ChromeModelHelper); | 168 tr.model.helpers.ChromeModelHelper); |
168 if (!modelHelper) | 169 if (!modelHelper) return undefined; |
169 return undefined; | |
170 | 170 |
171 var mainThread = undefined; | 171 var mainThread = undefined; |
172 var compositorThread = undefined; | 172 var compositorThread = undefined; |
173 | 173 |
174 for (var i in sourceSlices) { | 174 for (var i in sourceSlices) { |
175 if (sourceSlices[i].parentContainer.name === | 175 if (sourceSlices[i].parentContainer.name === |
176 MAIN_RENDERER_THREAD_NAME) | 176 MAIN_RENDERER_THREAD_NAME) { |
177 mainThread = sourceSlices[i].parentContainer; | 177 mainThread = sourceSlices[i].parentContainer; |
178 else if (sourceSlices[i].parentContainer.name === | 178 } else if (sourceSlices[i].parentContainer.name === |
179 COMPOSITOR_THREAD_NAME) | 179 COMPOSITOR_THREAD_NAME) { |
180 compositorThread = sourceSlices[i].parentContainer; | 180 compositorThread = sourceSlices[i].parentContainer; |
| 181 } |
181 | 182 |
182 if (mainThread && compositorThread) | 183 if (mainThread && compositorThread) break; |
183 break; | |
184 } | 184 } |
185 | 185 |
186 var rendererHelpers = modelHelper.rendererHelpers; | 186 var rendererHelpers = modelHelper.rendererHelpers; |
187 | 187 |
188 var pids = Object.keys(rendererHelpers); | 188 var pids = Object.keys(rendererHelpers); |
189 for (var i = 0; i < pids.length; i++) { | 189 for (var i = 0; i < pids.length; i++) { |
190 var pid = pids[i]; | 190 var pid = pids[i]; |
191 var rendererHelper = rendererHelpers[pid]; | 191 var rendererHelper = rendererHelpers[pid]; |
192 if (rendererHelper.mainThread === mainThread || | 192 if (rendererHelper.mainThread === mainThread || |
193 rendererHelper.compositorThread === compositorThread) | 193 rendererHelper.compositorThread === compositorThread) { |
194 return rendererHelper; | 194 return rendererHelper; |
| 195 } |
195 } | 196 } |
196 | 197 |
197 return undefined; | 198 return undefined; |
198 }, | 199 }, |
199 | 200 |
200 addEntireSliceHierarchy: function(slice) { | 201 addEntireSliceHierarchy: function(slice) { |
201 this.associatedEvents_.push(slice); | 202 this.associatedEvents_.push(slice); |
202 slice.iterateAllSubsequentSlices(function(subsequentSlice) { | 203 slice.iterateAllSubsequentSlices(function(subsequentSlice) { |
203 this.associatedEvents_.push(subsequentSlice); | 204 this.associatedEvents_.push(subsequentSlice); |
204 }, this); | 205 }, this); |
205 }, | 206 }, |
206 | 207 |
207 addDirectlyAssociatedEvents: function(flowEvents) { | 208 addDirectlyAssociatedEvents: function(flowEvents) { |
208 var slices = []; | 209 var slices = []; |
209 | 210 |
210 flowEvents.forEach(function(flowEvent) { | 211 flowEvents.forEach(function(flowEvent) { |
211 this.associatedEvents_.push(flowEvent); | 212 this.associatedEvents_.push(flowEvent); |
212 var newSource = flowEvent.startSlice.mostTopLevelSlice; | 213 var newSource = flowEvent.startSlice.mostTopLevelSlice; |
213 if (slices.indexOf(newSource) === -1) | 214 if (slices.indexOf(newSource) === -1) { |
214 slices.push(newSource); | 215 slices.push(newSource); |
| 216 } |
215 }, this); | 217 }, this); |
216 | 218 |
217 var lastFlowEvent = flowEvents[flowEvents.length - 1]; | 219 var lastFlowEvent = flowEvents[flowEvents.length - 1]; |
218 var lastSource = lastFlowEvent.endSlice.mostTopLevelSlice; | 220 var lastSource = lastFlowEvent.endSlice.mostTopLevelSlice; |
219 if (slices.indexOf(lastSource) === -1) | 221 if (slices.indexOf(lastSource) === -1) { |
220 slices.push(lastSource); | 222 slices.push(lastSource); |
| 223 } |
221 | 224 |
222 return slices; | 225 return slices; |
223 }, | 226 }, |
224 | 227 |
225 // Find the Latency::ScrollUpdate slice that corresponds to the | 228 // Find the Latency::ScrollUpdate slice that corresponds to the |
226 // InputLatency::GestureScrollUpdate slice. | 229 // InputLatency::GestureScrollUpdate slice. |
227 // The C++ CL that makes this connection is at: | 230 // The C++ CL that makes this connection is at: |
228 // https://codereview.chromium.org/1178963003 | 231 // https://codereview.chromium.org/1178963003 |
229 addScrollUpdateEvents: function(rendererHelper) { | 232 addScrollUpdateEvents: function(rendererHelper) { |
230 if (!rendererHelper || !rendererHelper.compositorThread) | 233 if (!rendererHelper || !rendererHelper.compositorThread) { |
231 return; | 234 return; |
| 235 } |
232 | 236 |
233 var compositorThread = rendererHelper.compositorThread; | 237 var compositorThread = rendererHelper.compositorThread; |
234 var gestureScrollUpdateStart = this.start; | 238 var gestureScrollUpdateStart = this.start; |
235 var gestureScrollUpdateEnd = this.end; | 239 var gestureScrollUpdateEnd = this.end; |
236 | 240 |
237 var allCompositorAsyncSlices = | 241 var allCompositorAsyncSlices = |
238 compositorThread.asyncSliceGroup.slices; | 242 compositorThread.asyncSliceGroup.slices; |
239 | 243 |
240 for (var i in allCompositorAsyncSlices) { | 244 for (var i in allCompositorAsyncSlices) { |
241 var slice = allCompositorAsyncSlices[i]; | 245 var slice = allCompositorAsyncSlices[i]; |
242 | 246 |
243 if (slice.title !== 'Latency::ScrollUpdate') | 247 if (slice.title !== 'Latency::ScrollUpdate') continue; |
244 continue; | |
245 | 248 |
246 var parentId = slice.args.data. | 249 var parentId = slice.args.data. |
247 INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT. | 250 INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT. |
248 sequence_number; | 251 sequence_number; |
249 | 252 |
250 if (parentId === undefined) { | 253 if (parentId === undefined) { |
251 // Old trace, we can only rely on the timestamp to find the slice | 254 // Old trace, we can only rely on the timestamp to find the slice |
252 if (slice.start < gestureScrollUpdateStart || | 255 if (slice.start < gestureScrollUpdateStart || |
253 slice.start >= gestureScrollUpdateEnd) | 256 slice.start >= gestureScrollUpdateEnd) { |
254 continue; | 257 continue; |
| 258 } |
255 } else { | 259 } else { |
256 // New trace, we can definitively find the latency slice by comparing | 260 // New trace, we can definitively find the latency slice by comparing |
257 // its sequence number with gesture id | 261 // its sequence number with gesture id |
258 if (parseInt(parentId) !== parseInt(this.id)) | 262 if (parseInt(parentId) !== parseInt(this.id)) { |
259 continue; | 263 continue; |
| 264 } |
260 } | 265 } |
261 | 266 |
262 slice.associatedEvents.forEach(function(event) { | 267 slice.associatedEvents.forEach(function(event) { |
263 this.associatedEvents_.push(event); | 268 this.associatedEvents_.push(event); |
264 }, this); | 269 }, this); |
265 break; | 270 break; |
266 } | 271 } |
267 }, | 272 }, |
268 | 273 |
269 // Return true if the slice hierarchy is tracked by LatencyInfo of other | 274 // Return true if the slice hierarchy is tracked by LatencyInfo of other |
270 // input latency events. If the slice hierarchy is tracked by both, this | 275 // input latency events. If the slice hierarchy is tracked by both, this |
271 // function still returns true. | 276 // function still returns true. |
272 belongToOtherInputs: function(slice, flowEvents) { | 277 belongToOtherInputs: function(slice, flowEvents) { |
273 var fromOtherInputs = false; | 278 var fromOtherInputs = false; |
274 | 279 |
275 slice.iterateEntireHierarchy(function(subsequentSlice) { | 280 slice.iterateEntireHierarchy(function(subsequentSlice) { |
276 if (fromOtherInputs) | 281 if (fromOtherInputs) return; |
277 return; | |
278 | 282 |
279 subsequentSlice.inFlowEvents.forEach(function(inflow) { | 283 subsequentSlice.inFlowEvents.forEach(function(inflow) { |
280 if (fromOtherInputs) | 284 if (fromOtherInputs) return; |
281 return; | |
282 | 285 |
283 if (inflow.category.indexOf('input') > -1) { | 286 if (inflow.category.indexOf('input') > -1) { |
284 if (flowEvents.indexOf(inflow) === -1) | 287 if (flowEvents.indexOf(inflow) === -1) { |
285 fromOtherInputs = true; | 288 fromOtherInputs = true; |
| 289 } |
286 } | 290 } |
287 }, this); | 291 }, this); |
288 }, this); | 292 }, this); |
289 | 293 |
290 return fromOtherInputs; | 294 return fromOtherInputs; |
291 }, | 295 }, |
292 | 296 |
293 // Return true if |event| triggers slices of other inputs. | 297 // Return true if |event| triggers slices of other inputs. |
294 triggerOtherInputs: function(event, flowEvents) { | 298 triggerOtherInputs: function(event, flowEvents) { |
295 if (event.outFlowEvents === undefined || | 299 if (event.outFlowEvents === undefined || |
296 event.outFlowEvents.length === 0) | 300 event.outFlowEvents.length === 0) { |
297 return false; | 301 return false; |
| 302 } |
298 | 303 |
299 // Once we fix the bug of flow event binding, there should exist one and | 304 // Once we fix the bug of flow event binding, there should exist one and |
300 // only one outgoing flow (PostTask) from ScheduleBeginImplFrameDeadline | 305 // only one outgoing flow (PostTask) from ScheduleBeginImplFrameDeadline |
301 // and PostComposite. | 306 // and PostComposite. |
302 var flow = event.outFlowEvents[0]; | 307 var flow = event.outFlowEvents[0]; |
303 | 308 |
304 if (flow.category !== POSTTASK_FLOW_EVENT || | 309 if (flow.category !== POSTTASK_FLOW_EVENT || |
305 !flow.endSlice) | 310 !flow.endSlice) { |
306 return false; | 311 return false; |
| 312 } |
307 | 313 |
308 var endSlice = flow.endSlice; | 314 var endSlice = flow.endSlice; |
309 if (this.belongToOtherInputs(endSlice.mostTopLevelSlice, flowEvents)) | 315 if (this.belongToOtherInputs(endSlice.mostTopLevelSlice, flowEvents)) { |
310 return true; | 316 return true; |
| 317 } |
311 | 318 |
312 return false; | 319 return false; |
313 }, | 320 }, |
314 | 321 |
315 // Follow outgoing flow of subsequentSlices in the current hierarchy. | 322 // Follow outgoing flow of subsequentSlices in the current hierarchy. |
316 // We also handle cases where different inputs interfere with each other. | 323 // We also handle cases where different inputs interfere with each other. |
317 followSubsequentSlices: function(event, queue, visited, flowEvents) { | 324 followSubsequentSlices: function(event, queue, visited, flowEvents) { |
318 var stopFollowing = false; | 325 var stopFollowing = false; |
319 var inputAck = false; | 326 var inputAck = false; |
320 | 327 |
321 event.iterateAllSubsequentSlices(function(slice) { | 328 event.iterateAllSubsequentSlices(function(slice) { |
322 if (stopFollowing) | 329 if (stopFollowing) return; |
323 return; | |
324 | 330 |
325 // Do not follow TaskQueueManager::RunTask because it causes | 331 // Do not follow TaskQueueManager::RunTask because it causes |
326 // many false events to be included. | 332 // many false events to be included. |
327 if (slice.title === 'TaskQueueManager::RunTask') | 333 if (slice.title === 'TaskQueueManager::RunTask') return; |
328 return; | |
329 | 334 |
330 // Do not follow ScheduledActionSendBeginMainFrame because the real | 335 // Do not follow ScheduledActionSendBeginMainFrame because the real |
331 // main thread BeginMainFrame is already traced by LatencyInfo flow. | 336 // main thread BeginMainFrame is already traced by LatencyInfo flow. |
332 if (slice.title === 'ThreadProxy::ScheduledActionSendBeginMainFrame') | 337 if (slice.title === 'ThreadProxy::ScheduledActionSendBeginMainFrame') { |
333 return; | 338 return; |
| 339 } |
334 | 340 |
335 // Do not follow ScheduleBeginImplFrameDeadline that triggers an | 341 // Do not follow ScheduleBeginImplFrameDeadline that triggers an |
336 // OnBeginImplFrameDeadline that is tracked by another LatencyInfo. | 342 // OnBeginImplFrameDeadline that is tracked by another LatencyInfo. |
337 if (slice.title === 'Scheduler::ScheduleBeginImplFrameDeadline') { | 343 if (slice.title === 'Scheduler::ScheduleBeginImplFrameDeadline') { |
338 if (this.triggerOtherInputs(slice, flowEvents)) | 344 if (this.triggerOtherInputs(slice, flowEvents)) return; |
339 return; | |
340 } | 345 } |
341 | 346 |
342 // Do not follow PostComposite that triggers CompositeImmediately | 347 // Do not follow PostComposite that triggers CompositeImmediately |
343 // that is tracked by another LatencyInfo. | 348 // that is tracked by another LatencyInfo. |
344 if (slice.title === 'CompositorImpl::PostComposite') { | 349 if (slice.title === 'CompositorImpl::PostComposite') { |
345 if (this.triggerOtherInputs(slice, flowEvents)) | 350 if (this.triggerOtherInputs(slice, flowEvents)) return; |
346 return; | |
347 } | 351 } |
348 | 352 |
349 // Stop following the rest of the current slice hierarchy if | 353 // Stop following the rest of the current slice hierarchy if |
350 // FilterAndSendWebInputEvent occurs after ProcessInputEventAck. | 354 // FilterAndSendWebInputEvent occurs after ProcessInputEventAck. |
351 if (slice.title === 'InputRouterImpl::ProcessInputEventAck') | 355 if (slice.title === 'InputRouterImpl::ProcessInputEventAck') { |
352 inputAck = true; | 356 inputAck = true; |
| 357 } |
353 if (inputAck && | 358 if (inputAck && |
354 slice.title === 'InputRouterImpl::FilterAndSendWebInputEvent') | 359 slice.title === 'InputRouterImpl::FilterAndSendWebInputEvent') { |
355 stopFollowing = true; | 360 stopFollowing = true; |
| 361 } |
356 | 362 |
357 this.followCurrentSlice(slice, queue, visited); | 363 this.followCurrentSlice(slice, queue, visited); |
358 }, this); | 364 }, this); |
359 }, | 365 }, |
360 | 366 |
361 // Follow outgoing flow events of the current slice. | 367 // Follow outgoing flow events of the current slice. |
362 followCurrentSlice: function(event, queue, visited) { | 368 followCurrentSlice: function(event, queue, visited) { |
363 event.outFlowEvents.forEach(function(outflow) { | 369 event.outFlowEvents.forEach(function(outflow) { |
364 if ((outflow.category === POSTTASK_FLOW_EVENT || | 370 if ((outflow.category === POSTTASK_FLOW_EVENT || |
365 outflow.category === IPC_FLOW_EVENT) && | 371 outflow.category === IPC_FLOW_EVENT) && |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 }, | 406 }, |
401 | 407 |
402 sortRasterizerSlices: function(rasterWorkerThreads, | 408 sortRasterizerSlices: function(rasterWorkerThreads, |
403 sortedRasterizerSlices) { | 409 sortedRasterizerSlices) { |
404 rasterWorkerThreads.forEach(function(rasterizer) { | 410 rasterWorkerThreads.forEach(function(rasterizer) { |
405 Array.prototype.push.apply(sortedRasterizerSlices, | 411 Array.prototype.push.apply(sortedRasterizerSlices, |
406 rasterizer.sliceGroup.slices); | 412 rasterizer.sliceGroup.slices); |
407 }, this); | 413 }, this); |
408 | 414 |
409 sortedRasterizerSlices.sort(function(a, b) { | 415 sortedRasterizerSlices.sort(function(a, b) { |
410 if (a.start !== b.start) | 416 if (a.start !== b.start) { |
411 return a.start - b.start; | 417 return a.start - b.start; |
| 418 } |
412 return a.guid - b.guid; | 419 return a.guid - b.guid; |
413 }); | 420 }); |
414 }, | 421 }, |
415 | 422 |
416 // Find rasterization slices that have the source_prepare_tiles_id | 423 // Find rasterization slices that have the source_prepare_tiles_id |
417 // same as the prepare_tiles_id of TileManager::PrepareTiles | 424 // same as the prepare_tiles_id of TileManager::PrepareTiles |
418 // The C++ CL that makes this connection is at: | 425 // The C++ CL that makes this connection is at: |
419 // https://codereview.chromium.org/1208683002/ | 426 // https://codereview.chromium.org/1208683002/ |
420 addRasterizationEvents: function(prepareTiles, rendererHelper, | 427 addRasterizationEvents: function(prepareTiles, rendererHelper, |
421 visited, flowEvents, sortedRasterizerSlices) { | 428 visited, flowEvents, sortedRasterizerSlices) { |
422 if (!prepareTiles.args.prepare_tiles_id) | 429 if (!prepareTiles.args.prepare_tiles_id) return; |
| 430 |
| 431 if (!rendererHelper || !rendererHelper.rasterWorkerThreads) { |
423 return; | 432 return; |
424 | 433 } |
425 if (!rendererHelper || !rendererHelper.rasterWorkerThreads) | |
426 return; | |
427 | 434 |
428 var rasterWorkerThreads = rendererHelper.rasterWorkerThreads; | 435 var rasterWorkerThreads = rendererHelper.rasterWorkerThreads; |
429 var prepareTileId = prepareTiles.args.prepare_tiles_id; | 436 var prepareTileId = prepareTiles.args.prepare_tiles_id; |
430 var pendingEventQueue = []; | 437 var pendingEventQueue = []; |
431 | 438 |
432 // Collect all the rasterizer tasks. Return the cached copy if possible. | 439 // Collect all the rasterizer tasks. Return the cached copy if possible. |
433 if (sortedRasterizerSlices.length === 0) | 440 if (sortedRasterizerSlices.length === 0) { |
434 this.sortRasterizerSlices(rasterWorkerThreads, sortedRasterizerSlices); | 441 this.sortRasterizerSlices(rasterWorkerThreads, sortedRasterizerSlices); |
| 442 } |
435 | 443 |
436 // TODO(yuhao): Once TaskSetFinishedTaskImpl also get the prepareTileId | 444 // TODO(yuhao): Once TaskSetFinishedTaskImpl also get the prepareTileId |
437 // we can simply track by checking id rather than counting. | 445 // we can simply track by checking id rather than counting. |
438 var numFinishedTasks = 0; | 446 var numFinishedTasks = 0; |
439 var RASTER_TASK_TITLE = 'RasterizerTaskImpl::RunOnWorkerThread'; | 447 var RASTER_TASK_TITLE = 'RasterizerTaskImpl::RunOnWorkerThread'; |
440 var IMAGEDECODE_TASK_TITLE = 'ImageDecodeTaskImpl::RunOnWorkerThread'; | 448 var IMAGEDECODE_TASK_TITLE = 'ImageDecodeTaskImpl::RunOnWorkerThread'; |
441 var FINISHED_TASK_TITLE = 'TaskSetFinishedTaskImpl::RunOnWorkerThread'; | 449 var FINISHED_TASK_TITLE = 'TaskSetFinishedTaskImpl::RunOnWorkerThread'; |
442 | 450 |
443 for (var i = 0; i < sortedRasterizerSlices.length; i++) { | 451 for (var i = 0; i < sortedRasterizerSlices.length; i++) { |
444 var task = sortedRasterizerSlices[i]; | 452 var task = sortedRasterizerSlices[i]; |
445 | 453 |
446 if (task.title === RASTER_TASK_TITLE || | 454 if (task.title === RASTER_TASK_TITLE || |
447 task.title === IMAGEDECODE_TASK_TITLE) { | 455 task.title === IMAGEDECODE_TASK_TITLE) { |
448 if (task.args.source_prepare_tiles_id === prepareTileId) | 456 if (task.args.source_prepare_tiles_id === prepareTileId) { |
449 this.addEntireSliceHierarchy(task.mostTopLevelSlice); | 457 this.addEntireSliceHierarchy(task.mostTopLevelSlice); |
| 458 } |
450 } else if (task.title === FINISHED_TASK_TITLE) { | 459 } else if (task.title === FINISHED_TASK_TITLE) { |
451 if (task.start > prepareTiles.start) { | 460 if (task.start > prepareTiles.start) { |
452 pendingEventQueue.push(task.mostTopLevelSlice); | 461 pendingEventQueue.push(task.mostTopLevelSlice); |
453 if (++numFinishedTasks === 3) | 462 if (++numFinishedTasks === 3) break; |
454 break; | |
455 } | 463 } |
456 } | 464 } |
457 } | 465 } |
458 | 466 |
459 // Trace PostTask from rasterizer tasks. | 467 // Trace PostTask from rasterizer tasks. |
460 while (pendingEventQueue.length !== 0) { | 468 while (pendingEventQueue.length !== 0) { |
461 var event = pendingEventQueue.pop(); | 469 var event = pendingEventQueue.pop(); |
462 | 470 |
463 this.addEntireSliceHierarchy(event); | 471 this.addEntireSliceHierarchy(event); |
464 this.followSubsequentSlices(event, pendingEventQueue, visited, | 472 this.followSubsequentSlices(event, pendingEventQueue, visited, |
(...skipping 26 matching lines...) Expand all Loading... |
491 this.followCurrentSlice(event, pendingEventQueue, visitedEvents); | 499 this.followCurrentSlice(event, pendingEventQueue, visitedEvents); |
492 | 500 |
493 this.followSubsequentSlices(event, pendingEventQueue, visitedEvents, | 501 this.followSubsequentSlices(event, pendingEventQueue, visitedEvents, |
494 flowEvents); | 502 flowEvents); |
495 | 503 |
496 // The rasterization work (CompositorTileWorker thread) and the | 504 // The rasterization work (CompositorTileWorker thread) and the |
497 // Compositor tile manager are connect by the prepare_tiles_id | 505 // Compositor tile manager are connect by the prepare_tiles_id |
498 // instead of flow events. | 506 // instead of flow events. |
499 var COMPOSITOR_PREPARE_TILES = 'TileManager::PrepareTiles'; | 507 var COMPOSITOR_PREPARE_TILES = 'TileManager::PrepareTiles'; |
500 prepareTiles = event.findDescendentSlice(COMPOSITOR_PREPARE_TILES); | 508 prepareTiles = event.findDescendentSlice(COMPOSITOR_PREPARE_TILES); |
501 if (prepareTiles) | 509 if (prepareTiles) { |
502 this.addRasterizationEvents(prepareTiles, rendererHelper, | 510 this.addRasterizationEvents(prepareTiles, rendererHelper, |
503 visitedEvents, flowEvents, sortedRasterizerSlices); | 511 visitedEvents, flowEvents, sortedRasterizerSlices); |
| 512 } |
504 | 513 |
505 // OnBeginImplFrameDeadline could be triggered by other inputs. | 514 // OnBeginImplFrameDeadline could be triggered by other inputs. |
506 // For now, we backtrace from it. | 515 // For now, we backtrace from it. |
507 // TODO(yuhao): There are more such slices that we need to backtrace | 516 // TODO(yuhao): There are more such slices that we need to backtrace |
508 var COMPOSITOR_ON_BIFD = 'Scheduler::OnBeginImplFrameDeadline'; | 517 var COMPOSITOR_ON_BIFD = 'Scheduler::OnBeginImplFrameDeadline'; |
509 beginImplFrame = event.findDescendentSlice(COMPOSITOR_ON_BIFD); | 518 beginImplFrame = event.findDescendentSlice(COMPOSITOR_ON_BIFD); |
510 if (beginImplFrame) | 519 if (beginImplFrame) { |
511 this.backtraceFromDraw(beginImplFrame, visitedEvents); | 520 this.backtraceFromDraw(beginImplFrame, visitedEvents); |
| 521 } |
512 } | 522 } |
513 | 523 |
514 // A separate pass on GestureScrollUpdate. | 524 // A separate pass on GestureScrollUpdate. |
515 // Scroll update doesn't go through the main thread, but the compositor | 525 // Scroll update doesn't go through the main thread, but the compositor |
516 // may go back to the main thread if there is an onscroll event handler. | 526 // may go back to the main thread if there is an onscroll event handler. |
517 // This is captured by a different flow event, which does not have the | 527 // This is captured by a different flow event, which does not have the |
518 // same ID as the Input Latency Event, but it is technically causally | 528 // same ID as the Input Latency Event, but it is technically causally |
519 // related to the GestureScrollUpdate input. Add them manually for now. | 529 // related to the GestureScrollUpdate input. Add them manually for now. |
520 var INPUT_GSU = 'InputLatency::GestureScrollUpdate'; | 530 var INPUT_GSU = 'InputLatency::GestureScrollUpdate'; |
521 if (this.title === INPUT_GSU) | 531 if (this.title === INPUT_GSU) { |
522 this.addScrollUpdateEvents(rendererHelper); | 532 this.addScrollUpdateEvents(rendererHelper); |
| 533 } |
523 }, | 534 }, |
524 | 535 |
525 get associatedEvents() { | 536 get associatedEvents() { |
526 if (this.associatedEvents_.length !== 0) | 537 if (this.associatedEvents_.length !== 0) { |
527 return this.associatedEvents_; | 538 return this.associatedEvents_; |
| 539 } |
528 | 540 |
529 var modelIndices = this.startThread.parent.model.modelIndices; | 541 var modelIndices = this.startThread.parent.model.modelIndices; |
530 var flowEvents = modelIndices.getFlowEventsWithId(this.id); | 542 var flowEvents = modelIndices.getFlowEventsWithId(this.id); |
531 | 543 |
532 if (flowEvents.length === 0) | 544 if (flowEvents.length === 0) { |
533 return this.associatedEvents_; | 545 return this.associatedEvents_; |
| 546 } |
534 | 547 |
535 // Step 1: Get events that are directly connected by the LatencyInfo | 548 // Step 1: Get events that are directly connected by the LatencyInfo |
536 // flow events. This gives us a small set of events that are guaranteed | 549 // flow events. This gives us a small set of events that are guaranteed |
537 // to be associated with the input, but are almost certain incomplete. | 550 // to be associated with the input, but are almost certain incomplete. |
538 // We call this set "source" event set. | 551 // We call this set "source" event set. |
539 // This step returns the "source" event set (sourceSlices), which is then | 552 // This step returns the "source" event set (sourceSlices), which is then |
540 // used in the second step. | 553 // used in the second step. |
541 var sourceSlices = this.addDirectlyAssociatedEvents(flowEvents); | 554 var sourceSlices = this.addDirectlyAssociatedEvents(flowEvents); |
542 | 555 |
543 // Step 2: Start from the previously constructed "source" event set, we | 556 // Step 2: Start from the previously constructed "source" event set, we |
544 // follow the toplevel (i.e., PostTask) and IPC flow events. Any slices | 557 // follow the toplevel (i.e., PostTask) and IPC flow events. Any slices |
545 // that are reachable from the "source" event set via PostTasks or IPCs | 558 // that are reachable from the "source" event set via PostTasks or IPCs |
546 // are conservatively considered associated with the input event. | 559 // are conservatively considered associated with the input event. |
547 // We then deal with specific cases where flow events either over include | 560 // We then deal with specific cases where flow events either over include |
548 // or miss capturing slices. | 561 // or miss capturing slices. |
549 var rendererHelper = this.getRendererHelper(sourceSlices); | 562 var rendererHelper = this.getRendererHelper(sourceSlices); |
550 this.addOtherCausallyRelatedEvents(rendererHelper, sourceSlices, | 563 this.addOtherCausallyRelatedEvents(rendererHelper, sourceSlices, |
551 flowEvents); | 564 flowEvents); |
552 | 565 |
553 return this.associatedEvents_; | 566 return this.associatedEvents_; |
554 }, | 567 }, |
555 | 568 |
556 get inputLatency() { | 569 get inputLatency() { |
557 if (!('data' in this.args)) | 570 if (!('data' in this.args)) return undefined; |
558 return undefined; | |
559 | 571 |
560 var data = this.args.data; | 572 var data = this.args.data; |
561 if (!(END_COMP_NAME in data)) | 573 if (!(END_COMP_NAME in data)) return undefined; |
562 return undefined; | |
563 | 574 |
564 var latency = 0; | 575 var latency = 0; |
565 var endTime = data[END_COMP_NAME].time; | 576 var endTime = data[END_COMP_NAME].time; |
566 if (ORIGINAL_COMP_NAME in data) { | 577 if (ORIGINAL_COMP_NAME in data) { |
567 latency = endTime - data[ORIGINAL_COMP_NAME].time; | 578 latency = endTime - data[ORIGINAL_COMP_NAME].time; |
568 } else if (UI_COMP_NAME in data) { | 579 } else if (UI_COMP_NAME in data) { |
569 latency = endTime - data[UI_COMP_NAME].time; | 580 latency = endTime - data[UI_COMP_NAME].time; |
570 } else if (BEGIN_COMP_NAME in data) { | 581 } else if (BEGIN_COMP_NAME in data) { |
571 latency = endTime - data[BEGIN_COMP_NAME].time; | 582 latency = endTime - data[BEGIN_COMP_NAME].time; |
572 } else { | 583 } else { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 typeNames: allTypeNames, | 633 typeNames: allTypeNames, |
623 categoryParts: ['latencyInfo'] | 634 categoryParts: ['latencyInfo'] |
624 }); | 635 }); |
625 | 636 |
626 return { | 637 return { |
627 InputLatencyAsyncSlice, | 638 InputLatencyAsyncSlice, |
628 INPUT_EVENT_TYPE_NAMES, | 639 INPUT_EVENT_TYPE_NAMES, |
629 }; | 640 }; |
630 }); | 641 }); |
631 </script> | 642 </script> |
OLD | NEW |