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() | |
pfeldman
2014/03/31 09:28:43
Lets have this in its own file.
| |
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) | |
254 { | |
255 this.name = payload.name; | |
256 this.startTime = payload.ts; | |
257 this.args = payload.args; | |
258 this.phase = payload.phase; | |
259 this.level = level; | |
260 } | |
261 | |
262 WebInspector.TracingModel.Event.prototype = { | |
263 /** | |
264 * @param {number} duration | |
265 */ | |
266 _setDuration: function(duration) | |
267 { | |
268 this.endTime = this.startTime + duration; | |
269 this.duration = duration; | |
270 }, | |
271 | |
272 /** | |
273 * @param {!WebInspector.TracingAgent.Event} payload | |
274 */ | |
275 _complete: function(payload) | |
276 { | |
277 if (this.name !== payload.name) { | |
278 console.assert(false, "Open/close event mismatch: " + this.name + " vs. " + payload.name); | |
279 return; | |
280 } | |
281 var duration = payload.ts - this.startTime; | |
282 if (duration < 0) { | |
283 console.assert(false, "Event out of order: " + this.name); | |
284 return; | |
285 } | |
286 this._setDuration(duration); | |
287 } | |
288 }; | |
pfeldman
2014/03/31 09:28:43
remove ;
| |
289 | |
290 /** | |
291 * @constructor | |
292 */ | |
293 WebInspector.TracingModel.NamedObject = function() | |
294 { | |
295 } | |
296 | |
297 WebInspector.TracingModel.NamedObject.prototype = | |
298 { | |
299 /** | |
300 * @param {string} name | |
301 */ | |
302 _setName: function(name) | |
303 { | |
304 this._name = name; | |
305 }, | |
306 | |
307 /** | |
308 * @return {string} | |
309 */ | |
310 name: function() | |
311 { | |
312 return this._name; | |
313 }, | |
314 | |
315 /** | |
316 * @param {number} sortIndex | |
317 */ | |
318 _setSortIndex: function(sortIndex) | |
319 { | |
320 this._sortIndex = sortIndex; | |
321 }, | |
322 } | |
323 | |
324 /** | |
325 * @param {!Array.<!WebInspector.TracingModel.NamedObject>} array | |
326 */ | |
327 WebInspector.TracingModel.NamedObject._sort = function(array) | |
328 { | |
329 /** | |
330 * @param {!WebInspector.TracingModel.NamedObject} a | |
331 * @param {!WebInspector.TracingModel.NamedObject} b | |
332 */ | |
333 function comparator(a, b) | |
334 { | |
335 return a._sortIndex !== b._sortIndex ? a._sortIndex - b._sortIndex : a.n ame().localeCompare(b.name()); | |
336 } | |
337 return array.sort(comparator); | |
338 } | |
339 | |
340 /** | |
341 * @constructor | |
342 * @extends {WebInspector.TracingModel.NamedObject} | |
343 * @param {number} id | |
344 */ | |
345 WebInspector.TracingModel.Process = function(id) | |
346 { | |
347 WebInspector.TracingModel.NamedObject.call(this); | |
348 this._setName("Process " + id); | |
349 this._threads = {}; | |
350 } | |
351 | |
352 WebInspector.TracingModel.Process.prototype = { | |
353 /** | |
354 * @param {number} id | |
355 * @return {!WebInspector.TracingModel.Thread} | |
356 */ | |
357 threadById: function(id) | |
358 { | |
359 var thread = this._threads[id]; | |
360 if (!thread) { | |
361 thread = new WebInspector.TracingModel.Thread(id); | |
362 this._threads[id] = thread; | |
363 } | |
364 return thread; | |
365 }, | |
366 | |
367 /** | |
368 * @return {!Array.<!WebInspector.TracingModel.Thread>} | |
369 */ | |
370 sortedThreads: function() | |
371 { | |
372 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._t hreads)); | |
373 }, | |
374 | |
375 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
376 } | |
377 | |
378 /** | |
379 * @constructor | |
380 * @extends {WebInspector.TracingModel.NamedObject} | |
381 * @param {number} id | |
382 */ | |
383 WebInspector.TracingModel.Thread = function(id) | |
384 { | |
385 WebInspector.TracingModel.NamedObject.call(this); | |
386 this._setName("Thread " + id); | |
387 this._events = []; | |
388 this._stack = []; | |
389 this._maxStackDepth = 0; | |
390 } | |
391 | |
392 WebInspector.TracingModel.Thread.prototype = { | |
393 /** | |
394 * @param {!WebInspector.TracingAgent.Event} payload | |
395 */ | |
396 addEvent: function(payload) | |
397 { | |
398 for (var top = this._stack.peekLast(); top && top.endTime && top.endTime <= payload.ts;) { | |
399 this._stack.pop(); | |
400 top = this._stack.peekLast(); | |
401 } | |
402 if (payload.ph === WebInspector.TracingAgent.Phase.End) { | |
403 var openEvent = this._stack.pop(); | |
404 // Quietly ignore unbalanced close events, they're legit (we could h ave missed start one). | |
405 if (openEvent) | |
406 openEvent._complete(payload); | |
407 return; | |
408 } | |
409 | |
410 var event = new WebInspector.TracingModel.Event(payload, this._stack.len gth); | |
411 if (payload.ph === WebInspector.TracingAgent.Phase.Begin || payload.ph = == WebInspector.TracingAgent.Phase.Complete) { | |
412 if (payload.ph === WebInspector.TracingAgent.Phase.Complete) | |
413 event._setDuration(payload.dur); | |
414 this._stack.push(event); | |
415 if (this._maxStackDepth < this._stack.length) | |
416 this._maxStackDepth = this._stack.length; | |
417 } | |
418 if (this._events.length && this._events.peekLast().startTime > event.sta rtTime) | |
419 console.assert(false, "Event is our of order: " + event.name); | |
420 this._events.push(event); | |
421 }, | |
422 | |
423 /** | |
424 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
425 */ | |
426 events: function() | |
427 { | |
428 return this._events; | |
429 }, | |
430 | |
431 /** | |
432 * @return {number} | |
433 */ | |
434 maxStackDepth: function() | |
435 { | |
436 // Reserve one for non-container events. | |
437 return this._maxStackDepth + 1; | |
438 }, | |
439 | |
440 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
441 } | |
OLD | NEW |