OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2014 The Chromium Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 /** | |
8 * @constructor | |
9 * @extends {WebInspector.Object} | |
10 * @implements {WebInspector.TargetManager.Observer} | |
11 */ | |
12 WebInspector.TracingManager = function() | |
13 { | |
14 WebInspector.Object.call(this); | |
15 this._active = false; | |
16 WebInspector.targetManager.observeTargets(this); | |
17 } | |
18 | |
19 WebInspector.TracingManager.Events = { | |
20 "BufferUsage": "BufferUsage", | |
21 "TracingStarted": "TracingStarted", | |
22 "EventsCollected": "EventsCollected", | |
23 "TracingStopped": "TracingStopped", | |
24 "TracingComplete": "TracingComplete" | |
25 } | |
26 | |
27 /** @typedef {!{ | |
28 cat: string, | |
29 pid: number, | |
30 tid: number, | |
31 ts: number, | |
32 ph: string, | |
33 name: string, | |
34 args: !Object, | |
35 dur: number, | |
36 id: number, | |
37 s: string | |
38 }} | |
39 */ | |
40 WebInspector.TracingManager.EventPayload; | |
41 | |
42 | |
43 WebInspector.TracingManager.prototype = { | |
44 /** | |
45 * @param {!WebInspector.Target} target | |
46 */ | |
47 targetAdded: function(target) | |
48 { | |
49 if (this._target) | |
50 return; | |
51 this._target = target; | |
52 InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispa
tcher(this)); | |
53 }, | |
54 | |
55 /** | |
56 * @param {!WebInspector.Target} target | |
57 */ | |
58 targetRemoved: function(target) | |
59 { | |
60 if (this._target !== target) | |
61 return; | |
62 delete this._target; | |
63 }, | |
64 | |
65 /** | |
66 * @param {number} usage | |
67 */ | |
68 _bufferUsage: function(usage) | |
69 { | |
70 this.dispatchEventToListeners(WebInspector.TracingManager.Events.BufferU
sage, usage); | |
71 }, | |
72 | |
73 /** | |
74 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
75 */ | |
76 _eventsCollected: function(events) | |
77 { | |
78 this.dispatchEventToListeners(WebInspector.TracingManager.Events.EventsC
ollected, events); | |
79 }, | |
80 | |
81 _tracingComplete: function() | |
82 { | |
83 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Complete); | |
84 }, | |
85 | |
86 _tracingStarted: function() | |
87 { | |
88 if (this._active) | |
89 return; | |
90 this._active = true; | |
91 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Started); | |
92 }, | |
93 | |
94 /** | |
95 * @param {string} categoryFilter | |
96 * @param {string} options | |
97 * @param {function(?string)=} callback | |
98 */ | |
99 start: function(categoryFilter, options, callback) | |
100 { | |
101 if (this._active) | |
102 return; | |
103 WebInspector.profilingLock().acquire(); | |
104 this._shouldReleaseLock = true; | |
105 var bufferUsageReportingIntervalMs = 500; | |
106 TracingAgent.start(categoryFilter, options, bufferUsageReportingInterval
Ms, callback); | |
107 this._tracingStarted(); | |
108 this._active = true; | |
109 }, | |
110 | |
111 stop: function() | |
112 { | |
113 if (!this._active) | |
114 return; | |
115 TracingAgent.end(this._onStop.bind(this)); | |
116 if (this._shouldReleaseLock) { | |
117 this._shouldReleaseLock = false; | |
118 WebInspector.profilingLock().release(); | |
119 } | |
120 }, | |
121 | |
122 _onStop: function() | |
123 { | |
124 if (!this._active) | |
125 return; | |
126 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Stopped); | |
127 this._active = false; | |
128 }, | |
129 | |
130 __proto__: WebInspector.Object.prototype | |
131 } | |
132 | |
133 /** | |
134 * @constructor | |
135 */ | |
136 WebInspector.TracingModel = function() | |
137 { | |
138 this.reset(); | |
139 } | |
140 | |
141 /** | |
142 * @enum {string} | |
143 */ | |
144 WebInspector.TracingModel.Phase = { | |
145 Begin: "B", | |
146 End: "E", | |
147 Complete: "X", | |
148 Instant: "I", | |
149 AsyncBegin: "S", | |
150 AsyncStepInto: "T", | |
151 AsyncStepPast: "p", | |
152 AsyncEnd: "F", | |
153 FlowBegin: "s", | |
154 FlowStep: "t", | |
155 FlowEnd: "f", | |
156 Metadata: "M", | |
157 Counter: "C", | |
158 Sample: "P", | |
159 CreateObject: "N", | |
160 SnapshotObject: "O", | |
161 DeleteObject: "D" | |
162 }; | |
163 | |
164 WebInspector.TracingModel.MetadataEvent = { | |
165 ProcessSortIndex: "process_sort_index", | |
166 ProcessName: "process_name", | |
167 ThreadSortIndex: "thread_sort_index", | |
168 ThreadName: "thread_name" | |
169 } | |
170 | |
171 WebInspector.TracingModel.DevToolsMetadataEventCategory = "disabled-by-default-d
evtools.timeline"; | |
172 | |
173 WebInspector.TracingModel.ConsoleEventCategory = "blink.console"; | |
174 | |
175 WebInspector.TracingModel.FrameLifecycleEventCategory = "cc,devtools"; | |
176 | |
177 WebInspector.TracingModel.DevToolsMetadataEvent = { | |
178 TracingStartedInPage: "TracingStartedInPage", | |
179 TracingStartedInWorker: "TracingStartedInWorker", | |
180 }; | |
181 | |
182 /** | |
183 * @param {string} phase | |
184 * @return {boolean} | |
185 */ | |
186 WebInspector.TracingModel.isAsyncPhase = function(phase) | |
187 { | |
188 return phase === WebInspector.TracingModel.Phase.AsyncBegin || phase === Web
Inspector.TracingModel.Phase.AsyncEnd || | |
189 phase === WebInspector.TracingModel.Phase.AsyncStepInto || phase === Web
Inspector.TracingModel.Phase.AsyncStepPast; | |
190 } | |
191 | |
192 WebInspector.TracingModel.prototype = { | |
193 /** | |
194 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
195 */ | |
196 devtoolsPageMetadataEvents: function() | |
197 { | |
198 return this._devtoolsPageMetadataEvents; | |
199 }, | |
200 | |
201 /** | |
202 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
203 */ | |
204 devtoolsWorkerMetadataEvents: function() | |
205 { | |
206 return this._devtoolsWorkerMetadataEvents; | |
207 }, | |
208 | |
209 /** | |
210 * @return {?string} | |
211 */ | |
212 sessionId: function() | |
213 { | |
214 return this._sessionId; | |
215 }, | |
216 | |
217 /** | |
218 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
219 */ | |
220 setEventsForTest: function(events) | |
221 { | |
222 this.reset(); | |
223 this.addEvents(events); | |
224 this.tracingComplete(); | |
225 }, | |
226 | |
227 /** | |
228 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
229 */ | |
230 addEvents: function(events) | |
231 { | |
232 for (var i = 0; i < events.length; ++i) { | |
233 this._addEvent(events[i]); | |
234 this._rawEvents.push(events[i]); | |
235 } | |
236 }, | |
237 | |
238 tracingComplete: function() | |
239 { | |
240 this._processMetadataEvents(); | |
241 for (var process in this._processById) | |
242 this._processById[process]._tracingComplete(this._maximumRecordTime)
; | |
243 }, | |
244 | |
245 reset: function() | |
246 { | |
247 this._processById = {}; | |
248 this._minimumRecordTime = 0; | |
249 this._maximumRecordTime = 0; | |
250 this._sessionId = null; | |
251 this._devtoolsPageMetadataEvents = []; | |
252 this._devtoolsWorkerMetadataEvents = []; | |
253 this._rawEvents = []; | |
254 }, | |
255 | |
256 /** | |
257 * @return {!Array.<!WebInspector.TracingManager.EventPayload>} | |
258 */ | |
259 rawEvents: function() | |
260 { | |
261 return this._rawEvents; | |
262 }, | |
263 | |
264 /** | |
265 * @param {!WebInspector.TracingManager.EventPayload} payload | |
266 */ | |
267 _addEvent: function(payload) | |
268 { | |
269 var process = this._processById[payload.pid]; | |
270 if (!process) { | |
271 process = new WebInspector.TracingModel.Process(payload.pid); | |
272 this._processById[payload.pid] = process; | |
273 } | |
274 if (payload.ph !== WebInspector.TracingModel.Phase.Metadata) { | |
275 var timestamp = payload.ts / 1000; | |
276 // We do allow records for unrelated threads to arrive out-of-order, | |
277 // so there's a chance we're getting records from the past. | |
278 if (timestamp && (!this._minimumRecordTime || timestamp < this._mini
mumRecordTime)) | |
279 this._minimumRecordTime = timestamp; | |
280 var endTimeStamp = (payload.ts + (payload.dur || 0)) / 1000; | |
281 this._maximumRecordTime = Math.max(this._maximumRecordTime, endTimeS
tamp); | |
282 var event = process._addEvent(payload); | |
283 if (event && event.name === WebInspector.TracingModel.DevToolsMetada
taEvent.TracingStartedInPage && | |
284 event.category === WebInspector.TracingModel.DevToolsMetadataEve
ntCategory) { | |
285 this._devtoolsPageMetadataEvents.push(event); | |
286 } | |
287 if (event && event.name === WebInspector.TracingModel.DevToolsMetada
taEvent.TracingStartedInWorker && | |
288 event.category === WebInspector.TracingModel.DevToolsMetadataEve
ntCategory) { | |
289 this._devtoolsWorkerMetadataEvents.push(event); | |
290 } | |
291 return; | |
292 } | |
293 switch (payload.name) { | |
294 case WebInspector.TracingModel.MetadataEvent.ProcessSortIndex: | |
295 process._setSortIndex(payload.args["sort_index"]); | |
296 break; | |
297 case WebInspector.TracingModel.MetadataEvent.ProcessName: | |
298 process._setName(payload.args["name"]); | |
299 break; | |
300 case WebInspector.TracingModel.MetadataEvent.ThreadSortIndex: | |
301 process.threadById(payload.tid)._setSortIndex(payload.args["sort_ind
ex"]); | |
302 break; | |
303 case WebInspector.TracingModel.MetadataEvent.ThreadName: | |
304 process.threadById(payload.tid)._setName(payload.args["name"]); | |
305 break; | |
306 } | |
307 }, | |
308 | |
309 _processMetadataEvents: function() | |
310 { | |
311 this._devtoolsPageMetadataEvents.sort(WebInspector.TracingModel.Event.co
mpareStartTime); | |
312 if (!this._devtoolsPageMetadataEvents.length) { | |
313 WebInspector.console.error(WebInspector.TracingModel.DevToolsMetadat
aEvent.TracingStartedInPage + " event not found."); | |
314 return; | |
315 } | |
316 var sessionId = this._devtoolsPageMetadataEvents[0].args["sessionId"]; | |
317 this._sessionId = sessionId; | |
318 | |
319 var mismatchingIds = {}; | |
320 function checkSessionId(event) | |
321 { | |
322 var id = event.args["sessionId"]; | |
323 if (id === sessionId) | |
324 return true; | |
325 mismatchingIds[id] = true; | |
326 return false; | |
327 } | |
328 this._devtoolsPageMetadataEvents = this._devtoolsPageMetadataEvents.filt
er(checkSessionId); | |
329 this._devtoolsWorkerMetadataEvents = this._devtoolsWorkerMetadataEvents.
filter(checkSessionId); | |
330 | |
331 var idList = Object.keys(mismatchingIds); | |
332 if (idList.length) | |
333 WebInspector.console.error("Timeline recording was started in more t
han one page simulaniously. Session id mismatch: " + this._sessionId + " and " +
idList + "."); | |
334 }, | |
335 | |
336 /** | |
337 * @return {number} | |
338 */ | |
339 minimumRecordTime: function() | |
340 { | |
341 return this._minimumRecordTime; | |
342 }, | |
343 | |
344 /** | |
345 * @return {number} | |
346 */ | |
347 maximumRecordTime: function() | |
348 { | |
349 return this._maximumRecordTime; | |
350 }, | |
351 | |
352 /** | |
353 * @return {!Array.<!WebInspector.TracingModel.Process>} | |
354 */ | |
355 sortedProcesses: function() | |
356 { | |
357 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._p
rocessById)); | |
358 } | |
359 } | |
360 | |
361 | |
362 /** | |
363 * @constructor | |
364 * @param {!WebInspector.TracingModel} tracingModel | |
365 */ | |
366 WebInspector.TracingModel.Loader = function(tracingModel) | |
367 { | |
368 this._tracingModel = tracingModel; | |
369 this._firstChunkReceived = false; | |
370 } | |
371 | |
372 WebInspector.TracingModel.Loader.prototype = { | |
373 /** | |
374 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
375 */ | |
376 loadNextChunk: function(events) | |
377 { | |
378 if (!this._firstChunkReceived) { | |
379 this._tracingModel.reset(); | |
380 this._firstChunkReceived = true; | |
381 } | |
382 this._tracingModel.addEvents(events); | |
383 }, | |
384 | |
385 finish: function() | |
386 { | |
387 this._tracingModel.tracingComplete(); | |
388 } | |
389 } | |
390 | |
391 | |
392 /** | |
393 * @constructor | |
394 * @param {string} category | |
395 * @param {string} name | |
396 * @param {string} phase | |
397 * @param {number} startTime | |
398 * @param {?WebInspector.TracingModel.Thread} thread | |
399 */ | |
400 WebInspector.TracingModel.Event = function(category, name, phase, startTime, thr
ead) | |
401 { | |
402 this.category = category; | |
403 this.name = name; | |
404 this.phase = phase; | |
405 this.startTime = startTime; | |
406 this.thread = thread; | |
407 this.args = {}; | |
408 | |
409 /** @type {?string} */ | |
410 this.warning = null; | |
411 /** @type {?WebInspector.TracingModel.Event} */ | |
412 this.initiator = null; | |
413 /** @type {?Array.<!ConsoleAgent.CallFrame>} */ | |
414 this.stackTrace = null; | |
415 /** @type {?Element} */ | |
416 this.previewElement = null; | |
417 /** @type {?string} */ | |
418 this.imageURL = null; | |
419 /** @type {number} */ | |
420 this.backendNodeId = 0; | |
421 | |
422 /** @type {number} */ | |
423 this.selfTime = 0; | |
424 } | |
425 | |
426 /** | |
427 * @param {!WebInspector.TracingManager.EventPayload} payload | |
428 * @param {?WebInspector.TracingModel.Thread} thread | |
429 * @return {!WebInspector.TracingModel.Event} | |
430 */ | |
431 WebInspector.TracingModel.Event.fromPayload = function(payload, thread) | |
432 { | |
433 var event = new WebInspector.TracingModel.Event(payload.cat, payload.name, p
ayload.ph, payload.ts / 1000, thread); | |
434 if (payload.args) | |
435 event.addArgs(payload.args); | |
436 else | |
437 console.error("Missing mandatory event argument 'args' at " + payload.ts
/ 1000); | |
438 if (typeof payload.dur === "number") | |
439 event.setEndTime((payload.ts + payload.dur) / 1000); | |
440 if (payload.id) | |
441 event.id = payload.id; | |
442 return event; | |
443 } | |
444 | |
445 WebInspector.TracingModel.Event.prototype = { | |
446 /** | |
447 * @param {number} endTime | |
448 */ | |
449 setEndTime: function(endTime) | |
450 { | |
451 if (endTime < this.startTime) { | |
452 console.assert(false, "Event out of order: " + this.name); | |
453 return; | |
454 } | |
455 this.endTime = endTime; | |
456 this.duration = endTime - this.startTime; | |
457 }, | |
458 | |
459 /** | |
460 * @param {!Object} args | |
461 */ | |
462 addArgs: function(args) | |
463 { | |
464 // Shallow copy args to avoid modifying original payload which may be sa
ved to file. | |
465 for (var name in args) { | |
466 if (name in this.args) | |
467 console.error("Same argument name (" + name + ") is used for be
gin and end phases of " + this.name); | |
468 this.args[name] = args[name]; | |
469 } | |
470 }, | |
471 | |
472 /** | |
473 * @param {!WebInspector.TracingManager.EventPayload} payload | |
474 */ | |
475 _complete: function(payload) | |
476 { | |
477 if (payload.args) | |
478 this.addArgs(payload.args); | |
479 else | |
480 console.error("Missing mandatory event argument 'args' at " + payloa
d.ts / 1000); | |
481 this.setEndTime(payload.ts / 1000); | |
482 } | |
483 } | |
484 | |
485 /** | |
486 * @param {!WebInspector.TracingModel.Event} a | |
487 * @param {!WebInspector.TracingModel.Event} b | |
488 * @return {number} | |
489 */ | |
490 WebInspector.TracingModel.Event.compareStartTime = function (a, b) | |
491 { | |
492 return a.startTime - b.startTime; | |
493 } | |
494 | |
495 /** | |
496 * @param {!WebInspector.TracingModel.Event} a | |
497 * @param {!WebInspector.TracingModel.Event} b | |
498 * @return {number} | |
499 */ | |
500 WebInspector.TracingModel.Event.orderedCompareStartTime = function (a, b) | |
501 { | |
502 // Array.mergeOrdered coalesces objects if comparator returns 0. | |
503 // To change this behavior this comparator return -1 in the case events | |
504 // startTime's are equal, so both events got placed into the result array. | |
505 return a.startTime - b.startTime || -1; | |
506 } | |
507 | |
508 /** | |
509 * @constructor | |
510 */ | |
511 WebInspector.TracingModel.NamedObject = function() | |
512 { | |
513 } | |
514 | |
515 WebInspector.TracingModel.NamedObject.prototype = | |
516 { | |
517 /** | |
518 * @param {string} name | |
519 */ | |
520 _setName: function(name) | |
521 { | |
522 this._name = name; | |
523 }, | |
524 | |
525 /** | |
526 * @return {string} | |
527 */ | |
528 name: function() | |
529 { | |
530 return this._name; | |
531 }, | |
532 | |
533 /** | |
534 * @param {number} sortIndex | |
535 */ | |
536 _setSortIndex: function(sortIndex) | |
537 { | |
538 this._sortIndex = sortIndex; | |
539 }, | |
540 } | |
541 | |
542 /** | |
543 * @param {!Array.<!WebInspector.TracingModel.NamedObject>} array | |
544 */ | |
545 WebInspector.TracingModel.NamedObject._sort = function(array) | |
546 { | |
547 /** | |
548 * @param {!WebInspector.TracingModel.NamedObject} a | |
549 * @param {!WebInspector.TracingModel.NamedObject} b | |
550 */ | |
551 function comparator(a, b) | |
552 { | |
553 return a._sortIndex !== b._sortIndex ? a._sortIndex - b._sortIndex : a.n
ame().localeCompare(b.name()); | |
554 } | |
555 return array.sort(comparator); | |
556 } | |
557 | |
558 /** | |
559 * @constructor | |
560 * @extends {WebInspector.TracingModel.NamedObject} | |
561 * @param {number} id | |
562 */ | |
563 WebInspector.TracingModel.Process = function(id) | |
564 { | |
565 WebInspector.TracingModel.NamedObject.call(this); | |
566 this._setName("Process " + id); | |
567 this._threads = {}; | |
568 this._objects = {}; | |
569 /** @type {!Array.<!WebInspector.TracingManager.EventPayload>} */ | |
570 this._asyncEvents = []; | |
571 /** @type {!Object.<string, ?Array.<!WebInspector.TracingModel.Event>>} */ | |
572 this._openAsyncEvents = []; | |
573 } | |
574 | |
575 WebInspector.TracingModel.Process.prototype = { | |
576 /** | |
577 * @param {number} id | |
578 * @return {!WebInspector.TracingModel.Thread} | |
579 */ | |
580 threadById: function(id) | |
581 { | |
582 var thread = this._threads[id]; | |
583 if (!thread) { | |
584 thread = new WebInspector.TracingModel.Thread(this, id); | |
585 this._threads[id] = thread; | |
586 } | |
587 return thread; | |
588 }, | |
589 | |
590 /** | |
591 * @param {!WebInspector.TracingManager.EventPayload} payload | |
592 * @return {?WebInspector.TracingModel.Event} event | |
593 */ | |
594 _addEvent: function(payload) | |
595 { | |
596 var phase = WebInspector.TracingModel.Phase; | |
597 // Build async event when we've got events from all threads, so we can s
ort them and process in the chronological order. | |
598 // However, also add individual async events to the thread flow, so we c
an easily display them on the same chart as | |
599 // other events, should we choose so. | |
600 if (WebInspector.TracingModel.isAsyncPhase(payload.ph)) | |
601 this._asyncEvents.push(payload); | |
602 | |
603 var event = this.threadById(payload.tid)._addEvent(payload); | |
604 if (event && payload.ph === phase.SnapshotObject) | |
605 this.objectsByName(event.name).push(event); | |
606 return event; | |
607 }, | |
608 | |
609 /** | |
610 * @param {!number} lastEventTime | |
611 */ | |
612 _tracingComplete: function(lastEventTime) | |
613 { | |
614 /** | |
615 * @param {!WebInspector.TracingManager.EventPayload} a | |
616 * @param {!WebInspector.TracingManager.EventPayload} b | |
617 */ | |
618 function comparePayloadTimestamp(a, b) | |
619 { | |
620 return a.ts - b.ts; | |
621 } | |
622 this._asyncEvents.sort(comparePayloadTimestamp).forEach(this._addAsyncEv
ent, this); | |
623 for (var key in this._openAsyncEvents) { | |
624 var steps = this._openAsyncEvents[key]; | |
625 if (!steps) | |
626 continue; | |
627 var startEvent = steps[0]; | |
628 var syntheticEndEvent = new WebInspector.TracingModel.Event(startEve
nt.category, startEvent.name, WebInspector.TracingModel.Phase.AsyncEnd, lastEven
tTime, startEvent.thread); | |
629 steps.push(syntheticEndEvent); | |
630 } | |
631 this._asyncEvents = []; | |
632 this._openAsyncEvents = []; | |
633 }, | |
634 | |
635 /** | |
636 * @param {!WebInspector.TracingManager.EventPayload} payload | |
637 */ | |
638 _addAsyncEvent: function(payload) | |
639 { | |
640 var phase = WebInspector.TracingModel.Phase; | |
641 var timestamp = payload.ts / 1000; | |
642 var key = payload.name + "." + payload.id; | |
643 var steps = this._openAsyncEvents[key]; | |
644 | |
645 var thread = this.threadById(payload.tid); | |
646 if (payload.ph === phase.AsyncBegin) { | |
647 if (steps) { | |
648 console.error("Event " + key + " at " + timestamp + " was alread
y started at " + steps[0].startTime); | |
649 return; | |
650 } | |
651 steps = [WebInspector.TracingModel.Event.fromPayload(payload, thread
)]; | |
652 this._openAsyncEvents[key] = steps; | |
653 thread._addAsyncEventSteps(steps); | |
654 return; | |
655 } | |
656 if (!steps) { | |
657 console.error("Unexpected async event, phase " + payload.ph + " at "
+ timestamp); | |
658 return; | |
659 } | |
660 var newEvent = WebInspector.TracingModel.Event.fromPayload(payload, thre
ad); | |
661 if (payload.ph === phase.AsyncEnd) { | |
662 steps.push(newEvent); | |
663 delete this._openAsyncEvents[key]; | |
664 } else if (payload.ph === phase.AsyncStepInto || payload.ph === phase.As
yncStepPast) { | |
665 var lastPhase = steps.peekLast().phase; | |
666 if (lastPhase !== phase.AsyncBegin && lastPhase !== payload.ph) { | |
667 console.assert(false, "Async event step phase mismatch: " + last
Phase + " at " + steps.peekLast().startTime + " vs. " + payload.ph + " at " + ti
mestamp); | |
668 return; | |
669 } | |
670 steps.push(newEvent); | |
671 } else { | |
672 console.assert(false, "Invalid async event phase"); | |
673 } | |
674 }, | |
675 | |
676 /** | |
677 * @param {string} name | |
678 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
679 */ | |
680 objectsByName: function(name) | |
681 { | |
682 var objects = this._objects[name]; | |
683 if (!objects) { | |
684 objects = []; | |
685 this._objects[name] = objects; | |
686 } | |
687 return objects; | |
688 }, | |
689 | |
690 /** | |
691 * @return {!Array.<string>} | |
692 */ | |
693 sortedObjectNames: function() | |
694 { | |
695 return Object.keys(this._objects).sort(); | |
696 }, | |
697 | |
698 /** | |
699 * @return {!Array.<!WebInspector.TracingModel.Thread>} | |
700 */ | |
701 sortedThreads: function() | |
702 { | |
703 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._t
hreads)); | |
704 }, | |
705 | |
706 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
707 } | |
708 | |
709 /** | |
710 * @constructor | |
711 * @extends {WebInspector.TracingModel.NamedObject} | |
712 * @param {!WebInspector.TracingModel.Process} process | |
713 * @param {number} id | |
714 */ | |
715 WebInspector.TracingModel.Thread = function(process, id) | |
716 { | |
717 WebInspector.TracingModel.NamedObject.call(this); | |
718 this._process = process; | |
719 this._setName("Thread " + id); | |
720 this._events = []; | |
721 this._asyncEvents = []; | |
722 | |
723 this._stack = []; | |
724 } | |
725 | |
726 WebInspector.TracingModel.Thread.prototype = { | |
727 | |
728 /** | |
729 * @return {?WebInspector.Target} | |
730 */ | |
731 target: function() | |
732 { | |
733 //FIXME: correctly specify target | |
734 return WebInspector.targetManager.targets()[0]; | |
735 }, | |
736 | |
737 /** | |
738 * @param {!WebInspector.TracingManager.EventPayload} payload | |
739 * @return {?WebInspector.TracingModel.Event} event | |
740 */ | |
741 _addEvent: function(payload) | |
742 { | |
743 var timestamp = payload.ts / 1000; | |
744 if (payload.ph === WebInspector.TracingModel.Phase.End) { | |
745 // Quietly ignore unbalanced close events, they're legit (we could h
ave missed start one). | |
746 if (!this._stack.length) | |
747 return null; | |
748 var top = this._stack.pop(); | |
749 if (top.name !== payload.name || top.category !== payload.cat) | |
750 console.error("B/E events mismatch at " + top.startTime + " (" +
top.name + ") vs. " + timestamp + " (" + payload.name + ")"); | |
751 else | |
752 top._complete(payload); | |
753 return null; | |
754 } | |
755 var event = WebInspector.TracingModel.Event.fromPayload(payload, this); | |
756 if (payload.ph === WebInspector.TracingModel.Phase.Begin) | |
757 this._stack.push(event); | |
758 if (this._events.length && this._events.peekLast().startTime > event.sta
rtTime) | |
759 console.assert(false, "Event is our of order: " + event.name); | |
760 this._events.push(event); | |
761 return event; | |
762 }, | |
763 | |
764 /** | |
765 * @param {!Array.<!WebInspector.TracingModel.Event>} eventSteps | |
766 */ | |
767 _addAsyncEventSteps: function(eventSteps) | |
768 { | |
769 this._asyncEvents.push(eventSteps); | |
770 }, | |
771 | |
772 /** | |
773 * @return {!WebInspector.TracingModel.Process} | |
774 */ | |
775 process: function() | |
776 { | |
777 return this._process; | |
778 }, | |
779 | |
780 /** | |
781 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
782 */ | |
783 events: function() | |
784 { | |
785 return this._events; | |
786 }, | |
787 | |
788 /** | |
789 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
790 */ | |
791 asyncEvents: function() | |
792 { | |
793 return this._asyncEvents; | |
794 }, | |
795 | |
796 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
797 } | |
798 | |
799 | |
800 /** | |
801 * @constructor | |
802 * @implements {TracingAgent.Dispatcher} | |
803 * @param {!WebInspector.TracingManager} tracingManager | |
804 */ | |
805 WebInspector.TracingDispatcher = function(tracingManager) | |
806 { | |
807 this._tracingManager = tracingManager; | |
808 } | |
809 | |
810 WebInspector.TracingDispatcher.prototype = { | |
811 /** | |
812 * @param {number} usage | |
813 */ | |
814 bufferUsage: function(usage) | |
815 { | |
816 this._tracingManager._bufferUsage(usage); | |
817 }, | |
818 | |
819 /** | |
820 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} data | |
821 */ | |
822 dataCollected: function(data) | |
823 { | |
824 this._tracingManager._eventsCollected(data); | |
825 }, | |
826 | |
827 tracingComplete: function() | |
828 { | |
829 this._tracingManager._tracingComplete(); | |
830 }, | |
831 | |
832 started: function() | |
833 { | |
834 this._tracingManager._tracingStarted(); | |
835 } | |
836 } | |
OLD | NEW |