Index: Source/devtools/front_end/TracingAgent.js |
diff --git a/Source/devtools/front_end/TracingAgent.js b/Source/devtools/front_end/TracingAgent.js |
index e7ad664f91a48cede2ca1a3581f2773cd58adfe4..5d04eef788f07375f085b88493f520e234897541 100644 |
--- a/Source/devtools/front_end/TracingAgent.js |
+++ b/Source/devtools/front_end/TracingAgent.js |
@@ -30,13 +30,64 @@ |
/** |
* @constructor |
+ * @extends {WebInspector.Object} |
*/ |
WebInspector.TracingAgent = function() |
{ |
+ WebInspector.Object.call(this); |
this._active = false; |
InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispatcher(this)); |
} |
+WebInspector.TracingAgent.Events = { |
+ EventsCollected: "EventsCollected" |
+}; |
+ |
+/** @typedef {!{ |
+ cat: string, |
+ pid: number, |
+ tid: number, |
+ ts: number, |
+ ph: string, |
+ name: string, |
+ args: !Object, |
+ dur: number, |
+ id: number, |
+ s: string |
+ }} |
+ */ |
+WebInspector.TracingAgent.Event; |
+ |
+/** |
+ * @enum {string} |
+ */ |
+WebInspector.TracingAgent.Phase = { |
+ Begin: "B", |
+ End: "E", |
+ Complete: "X", |
+ Instant: "i", |
+ AsyncBegin: "S", |
+ AsyncStepInto: "T", |
+ AsyncStepPast: "p", |
+ AsyncEnd: "F", |
+ FlowBegin: "s", |
+ FlowStep: "t", |
+ FlowEnd: "f", |
+ Metadata: "M", |
+ Counter: "C", |
+ Sample: "P", |
+ CreateObject: "N", |
+ SnapshotObject: "O", |
+ DeleteObject: "D" |
+}; |
+ |
+WebInspector.TracingAgent.MetadataEvent = { |
+ ProcessSortIndex: "process_sort_index", |
+ ProcessName: "process_name", |
+ ThreadSortIndex: "thread_sort_index", |
+ ThreadName: "thread_name" |
+} |
+ |
WebInspector.TracingAgent.prototype = { |
/** |
* @param {string} categoryPatterns |
@@ -47,7 +98,6 @@ WebInspector.TracingAgent.prototype = { |
{ |
TracingAgent.start(categoryPatterns, options, callback); |
this._active = true; |
- this._events = []; |
}, |
/** |
@@ -63,27 +113,21 @@ WebInspector.TracingAgent.prototype = { |
TracingAgent.end(); |
}, |
- /** |
- * @return {!Array.<!{cat: string, args: !Object, ph: string, ts: number}>} |
- */ |
- events: function() |
- { |
- return this._events; |
- }, |
- |
_eventsCollected: function(events) |
{ |
- Array.prototype.push.apply(this._events, events); |
+ this.dispatchEventToListeners(WebInspector.TracingAgent.Events.EventsCollected, events); |
}, |
_tracingComplete: function() |
{ |
this._active = false; |
- if (this._pendingStopCallback) { |
- this._pendingStopCallback(); |
- this._pendingStopCallback = null; |
- } |
- } |
+ if (!this._pendingStopCallback) |
+ return; |
+ this._pendingStopCallback(); |
+ this._pendingStopCallback = null; |
+ }, |
+ |
+ __proto__: WebInspector.Object.prototype |
} |
/** |
@@ -112,3 +156,286 @@ WebInspector.TracingDispatcher.prototype = { |
* @type {!WebInspector.TracingAgent} |
*/ |
WebInspector.tracingAgent; |
+ |
+/** |
+ * @constructor |
+ */ |
+WebInspector.TracingModel = function() |
pfeldman
2014/03/31 09:28:43
Lets have this in its own file.
|
+{ |
+ this.reset(); |
+} |
+ |
+WebInspector.TracingModel.prototype = { |
+ reset: function() |
+ { |
+ this._processById = {}; |
+ this._minimumRecordTime = null; |
+ this._maximumRecordTime = null; |
+ }, |
+ |
+ /** |
+ * @param {!Array.<!WebInspector.TracingAgent.Event>} payload |
+ */ |
+ addEvents: function(payload) |
+ { |
+ for (var i = 0; i < payload.length; ++i) |
+ this.addEvent(payload[i]); |
+ }, |
+ |
+ /** |
+ * @param {!WebInspector.TracingAgent.Event} payload |
+ */ |
+ addEvent: function(payload) |
+ { |
+ var process = this._processById[payload.pid]; |
+ if (!process) { |
+ process = new WebInspector.TracingModel.Process(payload.pid); |
+ this._processById[payload.pid] = process; |
+ } |
+ var thread = process.threadById(payload.tid); |
+ if (payload.ph !== WebInspector.TracingAgent.Phase.Metadata) { |
+ var timestamp = payload.ts; |
+ // We do allow records for unrelated threads to arrive out-of-order, |
+ // so there's a chance we're getting records from the past. |
+ if (timestamp && (!this._minimumRecordTime || timestamp < this._minimumRecordTime)) |
+ this._minimumRecordTime = timestamp; |
+ if (!this._maximumRecordTime || timestamp > this._maximumRecordTime) |
+ this._maximumRecordTime = timestamp; |
+ thread.addEvent(payload); |
+ return; |
+ } |
+ switch (payload.name) { |
+ case WebInspector.TracingAgent.MetadataEvent.ProcessSortIndex: |
+ process._setSortIndex(payload.args["sort_index"]); |
+ break; |
+ case WebInspector.TracingAgent.MetadataEvent.ProcessName: |
+ process._setName(payload.args["name"]); |
+ break; |
+ case WebInspector.TracingAgent.MetadataEvent.ThreadSortIndex: |
+ thread._setSortIndex(payload.args["sort_index"]); |
+ break; |
+ case WebInspector.TracingAgent.MetadataEvent.ThreadName: |
+ thread._setName(payload.args["name"]); |
+ break; |
+ } |
+ }, |
+ |
+ /** |
+ * @return {?number} |
+ */ |
+ minimumRecordTime: function() |
+ { |
+ return this._minimumRecordTime; |
+ }, |
+ |
+ /** |
+ * @return {?number} |
+ */ |
+ maximumRecordTime: function() |
+ { |
+ return this._maximumRecordTime; |
+ }, |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TracingModel.Process>} |
+ */ |
+ sortedProcesses: function() |
+ { |
+ return WebInspector.TracingModel.NamedObject._sort(Object.values(this._processById)); |
+ } |
+} |
+ |
+/** |
+ * @constructor |
+ * @param {!WebInspector.TracingAgent.Event} payload |
+ * @param {number} level |
+ */ |
+WebInspector.TracingModel.Event = function(payload, level) |
+{ |
+ this.name = payload.name; |
+ this.startTime = payload.ts; |
+ this.args = payload.args; |
+ this.phase = payload.phase; |
+ this.level = level; |
+} |
+ |
+WebInspector.TracingModel.Event.prototype = { |
+ /** |
+ * @param {number} duration |
+ */ |
+ _setDuration: function(duration) |
+ { |
+ this.endTime = this.startTime + duration; |
+ this.duration = duration; |
+ }, |
+ |
+ /** |
+ * @param {!WebInspector.TracingAgent.Event} payload |
+ */ |
+ _complete: function(payload) |
+ { |
+ if (this.name !== payload.name) { |
+ console.assert(false, "Open/close event mismatch: " + this.name + " vs. " + payload.name); |
+ return; |
+ } |
+ var duration = payload.ts - this.startTime; |
+ if (duration < 0) { |
+ console.assert(false, "Event out of order: " + this.name); |
+ return; |
+ } |
+ this._setDuration(duration); |
+ } |
+}; |
pfeldman
2014/03/31 09:28:43
remove ;
|
+ |
+/** |
+ * @constructor |
+ */ |
+WebInspector.TracingModel.NamedObject = function() |
+{ |
+} |
+ |
+WebInspector.TracingModel.NamedObject.prototype = |
+{ |
+ /** |
+ * @param {string} name |
+ */ |
+ _setName: function(name) |
+ { |
+ this._name = name; |
+ }, |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ name: function() |
+ { |
+ return this._name; |
+ }, |
+ |
+ /** |
+ * @param {number} sortIndex |
+ */ |
+ _setSortIndex: function(sortIndex) |
+ { |
+ this._sortIndex = sortIndex; |
+ }, |
+} |
+ |
+/** |
+ * @param {!Array.<!WebInspector.TracingModel.NamedObject>} array |
+ */ |
+WebInspector.TracingModel.NamedObject._sort = function(array) |
+{ |
+ /** |
+ * @param {!WebInspector.TracingModel.NamedObject} a |
+ * @param {!WebInspector.TracingModel.NamedObject} b |
+ */ |
+ function comparator(a, b) |
+ { |
+ return a._sortIndex !== b._sortIndex ? a._sortIndex - b._sortIndex : a.name().localeCompare(b.name()); |
+ } |
+ return array.sort(comparator); |
+} |
+ |
+/** |
+ * @constructor |
+ * @extends {WebInspector.TracingModel.NamedObject} |
+ * @param {number} id |
+ */ |
+WebInspector.TracingModel.Process = function(id) |
+{ |
+ WebInspector.TracingModel.NamedObject.call(this); |
+ this._setName("Process " + id); |
+ this._threads = {}; |
+} |
+ |
+WebInspector.TracingModel.Process.prototype = { |
+ /** |
+ * @param {number} id |
+ * @return {!WebInspector.TracingModel.Thread} |
+ */ |
+ threadById: function(id) |
+ { |
+ var thread = this._threads[id]; |
+ if (!thread) { |
+ thread = new WebInspector.TracingModel.Thread(id); |
+ this._threads[id] = thread; |
+ } |
+ return thread; |
+ }, |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TracingModel.Thread>} |
+ */ |
+ sortedThreads: function() |
+ { |
+ return WebInspector.TracingModel.NamedObject._sort(Object.values(this._threads)); |
+ }, |
+ |
+ __proto__: WebInspector.TracingModel.NamedObject.prototype |
+} |
+ |
+/** |
+ * @constructor |
+ * @extends {WebInspector.TracingModel.NamedObject} |
+ * @param {number} id |
+ */ |
+WebInspector.TracingModel.Thread = function(id) |
+{ |
+ WebInspector.TracingModel.NamedObject.call(this); |
+ this._setName("Thread " + id); |
+ this._events = []; |
+ this._stack = []; |
+ this._maxStackDepth = 0; |
+} |
+ |
+WebInspector.TracingModel.Thread.prototype = { |
+ /** |
+ * @param {!WebInspector.TracingAgent.Event} payload |
+ */ |
+ addEvent: function(payload) |
+ { |
+ for (var top = this._stack.peekLast(); top && top.endTime && top.endTime <= payload.ts;) { |
+ this._stack.pop(); |
+ top = this._stack.peekLast(); |
+ } |
+ if (payload.ph === WebInspector.TracingAgent.Phase.End) { |
+ var openEvent = this._stack.pop(); |
+ // Quietly ignore unbalanced close events, they're legit (we could have missed start one). |
+ if (openEvent) |
+ openEvent._complete(payload); |
+ return; |
+ } |
+ |
+ var event = new WebInspector.TracingModel.Event(payload, this._stack.length); |
+ if (payload.ph === WebInspector.TracingAgent.Phase.Begin || payload.ph === WebInspector.TracingAgent.Phase.Complete) { |
+ if (payload.ph === WebInspector.TracingAgent.Phase.Complete) |
+ event._setDuration(payload.dur); |
+ this._stack.push(event); |
+ if (this._maxStackDepth < this._stack.length) |
+ this._maxStackDepth = this._stack.length; |
+ } |
+ if (this._events.length && this._events.peekLast().startTime > event.startTime) |
+ console.assert(false, "Event is our of order: " + event.name); |
+ this._events.push(event); |
+ }, |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TracingModel.Event>} |
+ */ |
+ events: function() |
+ { |
+ return this._events; |
+ }, |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ maxStackDepth: function() |
+ { |
+ // Reserve one for non-container events. |
+ return this._maxStackDepth + 1; |
+ }, |
+ |
+ __proto__: WebInspector.TracingModel.NamedObject.prototype |
+} |