OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 12 matching lines...) Expand all Loading... | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 /** | 31 /** |
32 * @constructor | 32 * @constructor |
33 * @extends {WebInspector.Object} | |
33 */ | 34 */ |
34 WebInspector.TracingAgent = function() | 35 WebInspector.TracingAgent = function() |
35 { | 36 { |
37 WebInspector.Object.call(this); | |
36 this._active = false; | 38 this._active = false; |
37 InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispatche r(this)); | 39 InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispatche r(this)); |
38 } | 40 } |
39 | 41 |
42 WebInspector.TracingAgent.Events = { | |
43 EventsCollected: "EventsCollected" | |
44 }; | |
45 | |
46 /** @typedef {!{ | |
47 cat: string, | |
48 pid: number, | |
49 tid: number, | |
50 ts: number, | |
51 ph: string, | |
52 name: string, | |
53 args: !Object, | |
54 dur: number, | |
55 id: number, | |
56 s: string | |
57 }} | |
58 */ | |
59 WebInspector.TracingAgent.Event; | |
60 | |
61 /** | |
62 * @enum {string} | |
63 */ | |
64 WebInspector.TracingAgent.Phase = { | |
65 Begin: "B", | |
66 End: "E", | |
67 Complete: "X", | |
68 Instant: "i", | |
69 AsyncBegin: "S", | |
70 AsyncStepInto: "T", | |
71 AsyncStepPast: "p", | |
72 AsyncEnd: "F", | |
73 FlowBegin: "s", | |
74 FlowStep: "t", | |
75 FlowEnd: "f", | |
76 Metadata: "M", | |
77 Counter: "C", | |
78 Sample: "P", | |
79 CreateObject: "N", | |
80 SnapshotObject: "O", | |
81 DeleteObject: "D" | |
82 }; | |
83 | |
84 WebInspector.TracingAgent.MetadataEvent = { | |
85 ProcessSortIndex: "process_sort_index", | |
86 ProcessName: "process_name", | |
87 ThreadSortIndex: "thread_sort_index", | |
88 ThreadName: "thread_name" | |
89 } | |
90 | |
40 WebInspector.TracingAgent.prototype = { | 91 WebInspector.TracingAgent.prototype = { |
41 /** | 92 /** |
42 * @param {string} categoryPatterns | 93 * @param {string} categoryPatterns |
43 * @param {string} options | 94 * @param {string} options |
44 * @param {function(?string)=} callback | 95 * @param {function(?string)=} callback |
45 */ | 96 */ |
46 start: function(categoryPatterns, options, callback) | 97 start: function(categoryPatterns, options, callback) |
47 { | 98 { |
48 TracingAgent.start(categoryPatterns, options, callback); | 99 TracingAgent.start(categoryPatterns, options, callback); |
49 this._active = true; | 100 this._active = true; |
50 this._events = []; | |
51 }, | 101 }, |
52 | 102 |
53 /** | 103 /** |
54 * @param {function()} callback | 104 * @param {function()} callback |
55 */ | 105 */ |
56 stop: function(callback) | 106 stop: function(callback) |
57 { | 107 { |
58 if (!this._active) { | 108 if (!this._active) { |
59 callback(); | 109 callback(); |
60 return; | 110 return; |
61 } | 111 } |
62 this._pendingStopCallback = callback; | 112 this._pendingStopCallback = callback; |
63 TracingAgent.end(); | 113 TracingAgent.end(); |
64 }, | 114 }, |
65 | 115 |
66 /** | |
67 * @return {!Array.<!{cat: string, args: !Object, ph: string, ts: number}>} | |
68 */ | |
69 events: function() | |
70 { | |
71 return this._events; | |
72 }, | |
73 | |
74 _eventsCollected: function(events) | 116 _eventsCollected: function(events) |
75 { | 117 { |
76 Array.prototype.push.apply(this._events, events); | 118 this.dispatchEventToListeners(WebInspector.TracingAgent.Events.EventsCol lected, events); |
77 }, | 119 }, |
78 | 120 |
79 _tracingComplete: function() | 121 _tracingComplete: function() |
80 { | 122 { |
81 this._active = false; | 123 this._active = false; |
82 if (this._pendingStopCallback) { | 124 if (!this._pendingStopCallback) |
83 this._pendingStopCallback(); | 125 return; |
84 this._pendingStopCallback = null; | 126 this._pendingStopCallback(); |
85 } | 127 this._pendingStopCallback = null; |
86 } | 128 }, |
129 | |
130 __proto__: WebInspector.Object.prototype | |
87 } | 131 } |
88 | 132 |
89 /** | 133 /** |
90 * @constructor | 134 * @constructor |
91 * @implements {TracingAgent.Dispatcher} | 135 * @implements {TracingAgent.Dispatcher} |
92 * @param {!WebInspector.TracingAgent} tracingAgent | 136 * @param {!WebInspector.TracingAgent} tracingAgent |
93 */ | 137 */ |
94 WebInspector.TracingDispatcher = function(tracingAgent) | 138 WebInspector.TracingDispatcher = function(tracingAgent) |
95 { | 139 { |
96 this._tracingAgent = tracingAgent; | 140 this._tracingAgent = tracingAgent; |
97 } | 141 } |
98 | 142 |
99 WebInspector.TracingDispatcher.prototype = { | 143 WebInspector.TracingDispatcher.prototype = { |
100 dataCollected: function(data) | 144 dataCollected: function(data) |
101 { | 145 { |
102 this._tracingAgent._eventsCollected(data); | 146 this._tracingAgent._eventsCollected(data); |
103 }, | 147 }, |
104 | 148 |
105 tracingComplete: function() | 149 tracingComplete: function() |
106 { | 150 { |
107 this._tracingAgent._tracingComplete(); | 151 this._tracingAgent._tracingComplete(); |
108 } | 152 } |
109 } | 153 } |
110 | 154 |
111 /** | 155 /** |
112 * @type {!WebInspector.TracingAgent} | 156 * @type {!WebInspector.TracingAgent} |
113 */ | 157 */ |
114 WebInspector.tracingAgent; | 158 WebInspector.tracingAgent; |
159 | |
160 /** | |
161 * @constructor | |
162 */ | |
163 WebInspector.TracingModel = function() | |
164 { | |
165 this.reset(); | |
166 } | |
167 | |
168 WebInspector.TracingModel.prototype = { | |
169 reset: function() | |
170 { | |
171 this._processById = {}; | |
172 this._minimumRecordTime = null; | |
173 this._maximumRecordTime = null; | |
174 }, | |
175 | |
176 /** | |
177 * @param {!Array.<!WebInspector.TracingAgent.Event>} payload | |
178 */ | |
179 addEvents: function(payload) | |
180 { | |
181 for (var i = 0; i < payload.length; ++i) | |
182 this.addEvent(payload[i]); | |
183 }, | |
184 | |
185 /** | |
186 * @param {!WebInspector.TracingAgent.Event} payload | |
187 */ | |
188 addEvent: function(payload) | |
189 { | |
190 var process = this._processById[payload.pid]; | |
191 if (!process) { | |
192 process = new WebInspector.TracingModel.Process(payload.pid); | |
193 this._processById[payload.pid] = process; | |
194 } | |
195 var thread = process.threadById(payload.tid); | |
196 if (payload.ph !== WebInspector.TracingAgent.Phase.Metadata) { | |
197 var timestamp = payload.ts; | |
198 // We do allow records for unrelated threads to arrive out-of-order, | |
199 // so there's a chance we're getting records from the past. | |
200 if (timestamp && (!this._minimumRecordTime || timestamp < this._mini mumRecordTime)) | |
201 this._minimumRecordTime = timestamp; | |
202 if (!this._maximumRecordTime || timestamp > this._maximumRecordTime) | |
203 this._maximumRecordTime = timestamp; | |
204 thread.addEvent(payload); | |
205 return; | |
206 } | |
207 switch (payload.name) { | |
208 case WebInspector.TracingAgent.MetadataEvent.ProcessSortIndex: | |
209 process._setSortIndex(payload.args["sort_index"]); | |
210 break; | |
211 case WebInspector.TracingAgent.MetadataEvent.ProcessName: | |
212 process._setName(payload.args["name"]); | |
213 break; | |
214 case WebInspector.TracingAgent.MetadataEvent.ThreadSortIndex: | |
215 thread._setSortIndex(payload.args["sort_index"]); | |
216 break; | |
217 case WebInspector.TracingAgent.MetadataEvent.ThreadName: | |
218 thread._setName(payload.args["name"]); | |
219 break; | |
220 } | |
221 }, | |
222 | |
223 /** | |
224 * @return {?number} | |
225 */ | |
226 minimumRecordTime: function() | |
227 { | |
228 return this._minimumRecordTime; | |
229 }, | |
230 | |
231 /** | |
232 * @return {?number} | |
233 */ | |
234 maximumRecordTime: function() | |
235 { | |
236 return this._maximumRecordTime; | |
237 }, | |
238 | |
239 /** | |
240 * @return {!Array.<!WebInspector.TracingModel.Process>} | |
241 */ | |
242 sortedProcesses: function() | |
243 { | |
244 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._p rocessById)); | |
245 } | |
246 } | |
247 | |
248 /** | |
249 * @constructor | |
250 * @param {!WebInspector.TracingAgent.Event} payload | |
251 * @param {number} level | |
252 */ | |
253 WebInspector.TracingModel.Event = function(payload, level) | |
pfeldman
2014/03/26 20:10:06
Can we actually afford keeping both - payload and
caseq
2014/03/28 17:13:41
Dropped payload, we just shallow-copy properties o
| |
254 { | |
255 this._payload = payload; | |
256 this.level = level; | |
257 } | |
258 | |
259 WebInspector.TracingModel.Event.prototype = { | |
260 /** | |
261 * @return {string} | |
262 */ | |
263 get name() | |
pfeldman
2014/03/26 18:32:09
no getters please.
caseq
2014/03/28 17:13:41
Gone with the above change.
| |
264 { | |
265 return this._payload.name; | |
266 }, | |
267 | |
268 /** | |
269 * @return {number} | |
270 */ | |
271 get startTime() | |
272 { | |
273 return this._payload.ts; | |
274 }, | |
275 | |
276 /** | |
277 * @return {!Object} | |
278 */ | |
279 get args() | |
280 { | |
281 return this._payload.args; | |
282 }, | |
283 | |
284 /** | |
285 * @return {string} | |
286 */ | |
287 get phase() | |
288 { | |
289 return this._payload.ph; | |
290 }, | |
291 | |
292 /** | |
293 * @param {number} duration | |
294 */ | |
295 _setDuration: function(duration) | |
296 { | |
297 this.endTime = this.startTime + duration; | |
298 this.duration = duration; | |
299 }, | |
300 | |
301 /** | |
302 * @param {!WebInspector.TracingAgent.Event} payload | |
303 */ | |
304 _complete: function(payload) | |
305 { | |
306 if (this.name !== payload.name) { | |
307 console.assert(false, "Open/close event mismatch: " + JSON.stringify (this._payload) + " vs. " + JSON.stringify(payload)); | |
pfeldman
2014/03/27 13:09:53
It is fine to complete the event you did not start
caseq
2014/03/28 17:13:41
This check shouldn't normally hit in the case you
| |
308 return; | |
309 } | |
310 var duration = payload.ts - this.startTime; | |
311 if (duration < 0) { | |
312 console.assert(false, "Event out of order: " + this.name); | |
313 return; | |
314 } | |
315 this._setDuration(duration); | |
316 } | |
317 }; | |
318 | |
319 /** | |
320 * @constructor | |
321 */ | |
322 WebInspector.TracingModel.NamedObject = function() | |
323 { | |
324 } | |
325 | |
326 WebInspector.TracingModel.NamedObject.prototype = | |
327 { | |
328 /** | |
329 * @param {string} name | |
330 */ | |
331 _setName: function(name) | |
332 { | |
333 this._name = name; | |
334 }, | |
335 | |
336 /** | |
337 * @return {string} | |
338 */ | |
339 name: function() | |
340 { | |
341 return this._name; | |
342 }, | |
343 | |
344 /** | |
345 * @param {number} sortIndex | |
346 */ | |
347 _setSortIndex: function(sortIndex) | |
348 { | |
349 this._sortIndex = sortIndex; | |
350 }, | |
351 } | |
352 | |
353 /** | |
354 * @param {!Array.<!WebInspector.TracingModel.NamedObject>} array | |
355 */ | |
356 WebInspector.TracingModel.NamedObject._sort = function(array) | |
357 { | |
358 /** | |
359 * @param {!WebInspector.TracingModel.NamedObject} a | |
360 * @param {!WebInspector.TracingModel.NamedObject} b | |
361 */ | |
362 function comparator(a, b) | |
363 { | |
364 return a._sortIndex !== b._sortIndex ? a._sortIndex - b._sortIndex : a.n ame().localeCompare(b.name()); | |
365 } | |
366 return array.sort(comparator); | |
367 } | |
368 | |
369 /** | |
370 * @constructor | |
371 * @extends {WebInspector.TracingModel.NamedObject} | |
372 * @param {number} id | |
373 */ | |
374 WebInspector.TracingModel.Process = function(id) | |
375 { | |
376 WebInspector.TracingModel.NamedObject.call(this); | |
377 this._setName("Process " + id); | |
378 this._threads = {}; | |
379 } | |
380 | |
381 WebInspector.TracingModel.Process.prototype = { | |
382 /** | |
383 * @param {number} id | |
384 * @return {!WebInspector.TracingModel.Thread} | |
385 */ | |
386 threadById: function(id) | |
387 { | |
388 var thread = this._threads[id]; | |
389 if (!thread) { | |
390 thread = new WebInspector.TracingModel.Thread(id); | |
391 this._threads[id] = thread; | |
392 } | |
393 return thread; | |
394 }, | |
395 | |
396 /** | |
397 * @return {!Array.<!WebInspector.TracingModel.Thread>} | |
398 */ | |
399 sortedThreads: function() | |
400 { | |
401 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._t hreads)); | |
402 }, | |
403 | |
404 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
405 } | |
406 | |
407 /** | |
408 * @constructor | |
409 * @extends {WebInspector.TracingModel.NamedObject} | |
410 * @param {number} id | |
411 */ | |
412 WebInspector.TracingModel.Thread = function(id) | |
413 { | |
414 WebInspector.TracingModel.NamedObject.call(this); | |
415 this._setName("Thread " + id); | |
416 this._events = []; | |
417 this._stack = []; | |
418 this._maxStackDepth = 0; | |
419 } | |
420 | |
421 WebInspector.TracingModel.Thread.prototype = { | |
422 /** | |
423 * @param {!WebInspector.TracingAgent.Event} payload | |
424 */ | |
425 addEvent: function(payload) | |
426 { | |
427 for (var top = this._stack.peekLast(); top && top.endTime && top.endTime <= payload.ts;) { | |
428 this._stack.pop(); | |
429 top = this._stack.peekLast(); | |
430 } | |
431 if (payload.ph === WebInspector.TracingAgent.Phase.End) { | |
432 var openEvent = this._stack.pop(); | |
433 // Quietly ignore unbalanced close events, they're legit (we could h ave missed start one). | |
434 if (openEvent) | |
435 openEvent._complete(payload); | |
436 return; | |
437 } | |
438 | |
439 var event = new WebInspector.TracingModel.Event(payload, this._stack.len gth); | |
440 if (payload.ph === WebInspector.TracingAgent.Phase.Begin || payload.ph = == WebInspector.TracingAgent.Phase.Complete) { | |
441 if (payload.ph === WebInspector.TracingAgent.Phase.Complete) | |
442 event._setDuration(payload.dur); | |
443 this._stack.push(event); | |
pfeldman
2014/03/27 13:09:53
You should not put the complete event into the sta
caseq
2014/03/28 17:13:41
I should -- we wouldn't compute level properly oth
| |
444 if (this._maxStackDepth < this._stack.length) | |
445 this._maxStackDepth = this._stack.length; | |
446 } | |
447 if (this._events.length && this._events.peekLast().startTime > event.sta rtTime) | |
448 console.assert(false, "Event is our of order: " + event.name); | |
449 this._events.push(event); | |
450 }, | |
451 | |
452 /** | |
453 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
454 */ | |
455 events: function() | |
456 { | |
457 return this._events; | |
458 }, | |
459 | |
460 /** | |
461 * @return {number} | |
462 */ | |
463 maxStackDepth: function() | |
464 { | |
465 // Reserve one for non-container events. | |
466 return this._maxStackDepth + 1; | |
467 }, | |
468 | |
469 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
470 } | |
OLD | NEW |