Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: Source/devtools/front_end/TracingAgent.js

Issue 212683005: Timeline Trace viewer prototype (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fixed tracing.html Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698