/**
* @constructor
- * @extends {WebInspector.TargetAwareObject}
*/
-WebInspector.TracingModel = function(target)
+WebInspector.TracingModel = function()
{
- WebInspector.TargetAwareObject.call(this, target);
this.reset();
- this._active = false;
- InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispatcher(this));
}
-WebInspector.TracingModel.Events = {
- "BufferUsage": "BufferUsage"
-}
-
-/** @typedef {!{
- cat: string,
- pid: number,
- tid: number,
- ts: number,
- ph: string,
- name: string,
- args: !Object,
- dur: number,
- id: number,
- s: string
- }}
- */
-WebInspector.TracingModel.EventPayload;
-
/**
* @enum {string}
*/
Begin: "B",
End: "E",
Complete: "X",
- Instant: "i",
+ Instant: "I",
AsyncBegin: "S",
AsyncStepInto: "T",
AsyncStepPast: "p",
AsyncEnd: "F",
+ NestableAsyncBegin: "b",
+ NestableAsyncEnd: "e",
+ NestableAsyncInstant: "i",
FlowBegin: "s",
FlowStep: "t",
FlowEnd: "f",
WebInspector.TracingModel.DevToolsMetadataEventCategory = "disabled-by-default-devtools.timeline";
+WebInspector.TracingModel.ConsoleEventCategory = "blink.console";
+
WebInspector.TracingModel.FrameLifecycleEventCategory = "cc,devtools";
WebInspector.TracingModel.DevToolsMetadataEvent = {
TracingStartedInPage: "TracingStartedInPage",
+ TracingSessionIdForWorker: "TracingSessionIdForWorker",
};
+WebInspector.TracingModel._nestableAsyncEventsString =
+ WebInspector.TracingModel.Phase.NestableAsyncBegin +
+ WebInspector.TracingModel.Phase.NestableAsyncEnd +
+ WebInspector.TracingModel.Phase.NestableAsyncInstant;
+
+WebInspector.TracingModel._legacyAsyncEventsString =
+ WebInspector.TracingModel.Phase.AsyncBegin +
+ WebInspector.TracingModel.Phase.AsyncEnd +
+ WebInspector.TracingModel.Phase.AsyncStepInto +
+ WebInspector.TracingModel.Phase.AsyncStepPast;
+
+WebInspector.TracingModel._asyncEventsString = WebInspector.TracingModel._nestableAsyncEventsString + WebInspector.TracingModel._legacyAsyncEventsString;
+
+/**
+ * @param {string} phase
+ * @return {boolean}
+ */
+WebInspector.TracingModel.isNestableAsyncPhase = function(phase)
+{
+ return WebInspector.TracingModel._nestableAsyncEventsString.indexOf(phase) >= 0;
+}
+
+/**
+ * @param {string} phase
+ * @return {boolean}
+ */
+WebInspector.TracingModel.isAsyncBeginPhase = function(phase)
+{
+ return phase === WebInspector.TracingModel.Phase.AsyncBegin || phase === WebInspector.TracingModel.Phase.NestableAsyncBegin;
+}
+
+/**
+ * @param {string} phase
+ * @return {boolean}
+ */
+WebInspector.TracingModel.isAsyncPhase = function(phase)
+{
+ return WebInspector.TracingModel._asyncEventsString.indexOf(phase) >= 0;
+}
+
WebInspector.TracingModel.prototype = {
/**
* @return {!Array.<!WebInspector.TracingModel.Event>}
*/
- devtoolsMetadataEvents: function()
+ devtoolsPageMetadataEvents: function()
{
- return this._devtoolsMetadataEvents;
+ return this._devtoolsPageMetadataEvents;
},
/**
- * @param {string} categoryFilter
- * @param {string} options
- * @param {function(?string)=} callback
- */
- start: function(categoryFilter, options, callback)
- {
- this.reset();
- var bufferUsageReportingIntervalMs = 500;
- /**
- * @param {?string} error
- * @param {string} sessionId
- * @this {WebInspector.TracingModel}
- */
- function callbackWrapper(error, sessionId)
- {
- this._sessionId = sessionId;
- if (callback)
- callback(error);
- }
- TracingAgent.start(categoryFilter, options, bufferUsageReportingIntervalMs, callbackWrapper.bind(this));
- this._active = true;
- },
-
- /**
- * @param {function()} callback
+ * @return {!Array.<!WebInspector.TracingModel.Event>}
*/
- stop: function(callback)
+ devtoolsWorkerMetadataEvents: function()
{
- if (!this._active) {
- callback();
- return;
- }
- this._pendingStopCallback = callback;
- TracingAgent.end();
+ return this._devtoolsWorkerMetadataEvents;
},
/**
},
/**
- * @param {string} sessionId
- * @param {!Array.<!WebInspector.TracingModel.EventPayload>} events
+ * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events
*/
- setEventsForTest: function(sessionId, events)
+ setEventsForTest: function(events)
{
this.reset();
- this._sessionId = sessionId;
- this._eventsCollected(events);
- this._tracingComplete();
+ this.addEvents(events);
+ this.tracingComplete();
},
/**
- * @param {number} usage
+ * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events
*/
- _bufferUsage: function(usage)
- {
- this.dispatchEventToListeners(WebInspector.TracingModel.Events.BufferUsage, usage);
- },
-
- /**
- * @param {!Array.<!WebInspector.TracingModel.EventPayload>} events
- */
- _eventsCollected: function(events)
+ addEvents: function(events)
{
for (var i = 0; i < events.length; ++i)
this._addEvent(events[i]);
},
- _tracingComplete: function()
+ tracingComplete: function()
{
- this._active = false;
- if (!this._pendingStopCallback)
- return;
- this._pendingStopCallback();
- this._pendingStopCallback = null;
+ this._processMetadataEvents();
+ for (var process in this._processById)
+ this._processById[process]._tracingComplete(this._maximumRecordTime);
+ this._backingStorage.finishWriting(function() {});
},
reset: function()
this._minimumRecordTime = 0;
this._maximumRecordTime = 0;
this._sessionId = null;
- this._devtoolsMetadataEvents = [];
+ this._devtoolsPageMetadataEvents = [];
+ this._devtoolsWorkerMetadataEvents = [];
+ if (this._backingStorage)
+ this._backingStorage.remove();
+ this._backingStorage = new WebInspector.DeferredTempFile("tracing", String(Date.now()));
+ this._storageOffset = 0;
},
/**
- * @param {!WebInspector.TracingModel.EventPayload} payload
+ * @param {!WebInspector.OutputStream} outputStream
+ * @param {!WebInspector.OutputStreamDelegate} delegate
+ */
+ writeToStream: function(outputStream, delegate)
+ {
+ this._backingStorage.writeToOutputStream(outputStream, delegate);
+ },
+
+ /**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
*/
_addEvent: function(payload)
{
process = new WebInspector.TracingModel.Process(payload.pid);
this._processById[payload.pid] = process;
}
- var thread = process.threadById(payload.tid);
+
+ var stringPayload = JSON.stringify(payload);
+ var startOffset = this._storageOffset;
+ if (startOffset) {
+ var recordDelimiter = ",\n";
+ stringPayload = recordDelimiter + stringPayload;
+ startOffset += recordDelimiter.length;
+ }
+ var blob = new Blob([stringPayload]);
+ this._storageOffset += blob.size;
+ this._backingStorage.write([stringPayload]);
+
if (payload.ph !== WebInspector.TracingModel.Phase.Metadata) {
var timestamp = payload.ts / 1000;
// 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;
- var event = thread.addEvent(payload);
- if (payload.ph === WebInspector.TracingModel.Phase.SnapshotObject)
- process.addObject(event);
- if (event && event.name === WebInspector.TracingModel.DevToolsMetadataEvent.TracingStartedInPage &&
- event.category === WebInspector.TracingModel.DevToolsMetadataEventCategory &&
- event.args["sessionId"] === this._sessionId)
- this._devtoolsMetadataEvents.push(event);
+ var endTimeStamp = (payload.ts + (payload.dur || 0)) / 1000;
+ this._maximumRecordTime = Math.max(this._maximumRecordTime, endTimeStamp);
+ var event = process._addEvent(payload);
+ if (!event)
+ return;
+ event._setBackingStorage(this._backingStorage, startOffset, this._storageOffset);
+ if (event.name === WebInspector.TracingModel.DevToolsMetadataEvent.TracingStartedInPage &&
+ event.category === WebInspector.TracingModel.DevToolsMetadataEventCategory) {
+ this._devtoolsPageMetadataEvents.push(event);
+ }
+ if (event.name === WebInspector.TracingModel.DevToolsMetadataEvent.TracingSessionIdForWorker &&
+ event.category === WebInspector.TracingModel.DevToolsMetadataEventCategory) {
+ this._devtoolsWorkerMetadataEvents.push(event);
+ }
return;
}
switch (payload.name) {
process._setName(payload.args["name"]);
break;
case WebInspector.TracingModel.MetadataEvent.ThreadSortIndex:
- thread._setSortIndex(payload.args["sort_index"]);
+ process.threadById(payload.tid)._setSortIndex(payload.args["sort_index"]);
break;
case WebInspector.TracingModel.MetadataEvent.ThreadName:
- thread._setName(payload.args["name"]);
+ process.threadById(payload.tid)._setName(payload.args["name"]);
break;
}
},
+ _processMetadataEvents: function()
+ {
+ this._devtoolsPageMetadataEvents.sort(WebInspector.TracingModel.Event.compareStartTime);
+ if (!this._devtoolsPageMetadataEvents.length) {
+ WebInspector.console.error(WebInspector.TracingModel.DevToolsMetadataEvent.TracingStartedInPage + " event not found.");
+ return;
+ }
+ var sessionId = this._devtoolsPageMetadataEvents[0].args["sessionId"];
+ this._sessionId = sessionId;
+
+ var mismatchingIds = {};
+ function checkSessionId(event)
+ {
+ var args = event.args;
+ // FIXME: put sessionId into args["data"] for TracingStartedInPage event.
+ if (args["data"])
+ args = args["data"];
+ var id = args["sessionId"];
+ if (id === sessionId)
+ return true;
+ mismatchingIds[id] = true;
+ return false;
+ }
+ this._devtoolsPageMetadataEvents = this._devtoolsPageMetadataEvents.filter(checkSessionId);
+ this._devtoolsWorkerMetadataEvents = this._devtoolsWorkerMetadataEvents.filter(checkSessionId);
+
+ var idList = Object.keys(mismatchingIds);
+ if (idList.length)
+ WebInspector.console.error("Timeline recording was started in more than one page simulaniously. Session id mismatch: " + this._sessionId + " and " + idList + ".");
+ },
+
/**
* @return {number}
*/
sortedProcesses: function()
{
return WebInspector.TracingModel.NamedObject._sort(Object.values(this._processById));
- },
-
- __proto__: WebInspector.TargetAwareObject.prototype
+ }
}
+
/**
* @constructor
- * @param {!WebInspector.TracingModel.EventPayload} payload
- * @param {number} level
- * @param {?WebInspector.TracingModel.Thread} thread
+ * @param {!WebInspector.TracingModel} tracingModel
*/
-WebInspector.TracingModel.Event = function(payload, level, thread)
+WebInspector.TracingModel.Loader = function(tracingModel)
{
- this.name = payload.name;
- this.category = payload.cat;
- this.startTime = payload.ts / 1000;
- this.args = payload.args;
- this.phase = payload.ph;
- this.level = level;
+ this._tracingModel = tracingModel;
+ this._firstChunkReceived = false;
+}
- if (payload.dur)
- this._setEndTime((payload.ts + payload.dur) / 1000);
+WebInspector.TracingModel.Loader.prototype = {
+ /**
+ * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events
+ */
+ loadNextChunk: function(events)
+ {
+ if (!this._firstChunkReceived) {
+ this._tracingModel.reset();
+ this._firstChunkReceived = true;
+ }
+ this._tracingModel.addEvents(events);
+ },
- if (payload.id)
- this.id = payload.id;
+ finish: function()
+ {
+ this._tracingModel.tracingComplete();
+ }
+}
+
+/**
+ * @constructor
+ * @param {string} category
+ * @param {string} name
+ * @param {!WebInspector.TracingModel.Phase} phase
+ * @param {number} startTime
+ * @param {!WebInspector.TracingModel.Thread} thread
+ */
+WebInspector.TracingModel.Event = function(category, name, phase, startTime, thread)
+{
+ /** @type {string} */
+ this.category = category;
+ /** @type {string} */
+ this.name = name;
+ /** @type {!WebInspector.TracingModel.Phase} */
+ this.phase = phase;
+ /** @type {number} */
+ this.startTime = startTime;
+ /** @type {!WebInspector.TracingModel.Thread} */
this.thread = thread;
+ this.args = {};
/** @type {?string} */
this.warning = null;
this.selfTime = 0;
}
+/**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
+ * @param {!WebInspector.TracingModel.Thread} thread
+ * @return {!WebInspector.TracingModel.Event}
+ */
+WebInspector.TracingModel.Event.fromPayload = function(payload, thread)
+{
+ var event = new WebInspector.TracingModel.Event(payload.cat, payload.name, /** @type {!WebInspector.TracingModel.Phase} */ (payload.ph), payload.ts / 1000, thread);
+ if (payload.args)
+ event.addArgs(payload.args);
+ else
+ console.error("Missing mandatory event argument 'args' at " + payload.ts / 1000);
+ if (typeof payload.dur === "number")
+ event.setEndTime((payload.ts + payload.dur) / 1000);
+ if (payload.id)
+ event.id = payload.id;
+ return event;
+}
+
WebInspector.TracingModel.Event.prototype = {
/**
* @param {number} endTime
*/
- _setEndTime: function(endTime)
+ setEndTime: function(endTime)
{
if (endTime < this.startTime) {
console.assert(false, "Event out of order: " + this.name);
},
/**
- * @param {!WebInspector.TracingModel.EventPayload} payload
+ * @param {!Object} args
*/
- _complete: function(payload)
+ addArgs: function(args)
{
- if (this.name !== payload.name) {
- console.assert(false, "Open/close event mismatch: " + this.name + " vs. " + payload.name);
- return;
- }
- if (payload.args) {
- for (var name in payload.args) {
- if (name in this.args)
- console.error("Same argument name (" + name + ") is used for begin and end phases of " + this.name);
- this.args[name] = payload.args[name];
- }
+ // Shallow copy args to avoid modifying original payload which may be saved to file.
+ for (var name in args) {
+ if (name in this.args)
+ console.error("Same argument name (" + name + ") is used for begin and end phases of " + this.name);
+ this.args[name] = args[name];
}
- this._setEndTime(payload.ts / 1000);
+ },
+
+ /**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
+ */
+ _complete: function(payload)
+ {
+ if (payload.args)
+ this.addArgs(payload.args);
+ else
+ console.error("Missing mandatory event argument 'args' at " + payload.ts / 1000);
+ this.setEndTime(payload.ts / 1000);
+ },
+
+ /**
+ * @param {!WebInspector.DeferredTempFile} backingFile
+ * @param {number} startOffset
+ * @param {number} endOffset
+ */
+ _setBackingStorage: function(backingFile, startOffset, endOffset)
+ {
}
}
}
/**
+ * @param {!WebInspector.TracingModel.Event} a
+ * @param {!WebInspector.TracingModel.Event} b
+ * @return {number}
+ */
+WebInspector.TracingModel.Event.orderedCompareStartTime = function (a, b)
+{
+ // Array.mergeOrdered coalesces objects if comparator returns 0.
+ // To change this behavior this comparator return -1 in the case events
+ // startTime's are equal, so both events got placed into the result array.
+ return a.startTime - b.startTime || -1;
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.TracingModel.Event}
+ * @param {string} category
+ * @param {string} name
+ * @param {number} startTime
+ * @param {!WebInspector.TracingModel.Thread} thread
+ */
+WebInspector.TracingModel.ObjectSnapshot = function(category, name, startTime, thread)
+{
+ WebInspector.TracingModel.Event.call(this, category, name, WebInspector.TracingModel.Phase.SnapshotObject, startTime, thread);
+}
+
+/**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
+ * @param {!WebInspector.TracingModel.Thread} thread
+ * @return {!WebInspector.TracingModel.ObjectSnapshot}
+ */
+WebInspector.TracingModel.ObjectSnapshot.fromPayload = function(payload, thread)
+{
+ var snapshot = new WebInspector.TracingModel.ObjectSnapshot(payload.cat, payload.name, payload.ts / 1000, thread);
+ if (payload.id)
+ snapshot.id = payload.id;
+ if (!payload.args || !payload.args["snapshot"]) {
+ console.error("Missing mandatory 'snapshot' argument at " + payload.ts / 1000);
+ return snapshot;
+ }
+ if (payload.args)
+ snapshot.addArgs(payload.args);
+ return snapshot;
+}
+
+WebInspector.TracingModel.ObjectSnapshot.prototype = {
+ /**
+ * @param {function(?Object)} callback
+ */
+ requestObject: function(callback)
+ {
+ var snapshot = this.args["snapshot"];
+ if (snapshot) {
+ callback(snapshot);
+ return;
+ }
+ this._file.readRange(this._startOffset, this._endOffset, onRead);
+ /**
+ * @param {?string} result
+ */
+ function onRead(result)
+ {
+ if (!result) {
+ callback(null);
+ return;
+ }
+ var snapshot;
+ try {
+ var payload = JSON.parse(result);
+ snapshot = payload["args"]["snapshot"];
+ } catch (e) {
+ WebInspector.console.error("Malformed event data in backing storage");
+ }
+ callback(snapshot);
+ }
+ },
+
+ /**
+ * @param {!WebInspector.DeferredTempFile} backingFile
+ * @param {number} startOffset
+ * @param {number} endOffset
+ * @override
+ */
+ _setBackingStorage: function(backingFile, startOffset, endOffset)
+ {
+ if (endOffset - startOffset < 10000)
+ return;
+ this._file = backingFile;
+ this._startOffset = startOffset;
+ this._endOffset = endOffset;
+ this.args = {};
+ },
+
+ __proto__: WebInspector.TracingModel.Event.prototype
+}
+
+
+/**
* @constructor
*/
WebInspector.TracingModel.NamedObject = function()
{
WebInspector.TracingModel.NamedObject.call(this);
this._setName("Process " + id);
+ this._id = id;
this._threads = {};
this._objects = {};
+ /** @type {!Array.<!WebInspector.TracingModel.Event>} */
+ this._asyncEvents = [];
+ /** @type {!Object.<string, ?Array.<!WebInspector.TracingModel.Event>>} */
+ this._openAsyncEvents = {};
+ /** @type {!Object.<string, !Array.<!WebInspector.TracingModel.Event>>} */
+ this._openNestableAsyncEvents = {};
}
WebInspector.TracingModel.Process.prototype = {
/**
+ * @return {number}
+ */
+ id: function()
+ {
+ return this._id;
+ },
+
+ /**
* @param {number} id
* @return {!WebInspector.TracingModel.Thread}
*/
},
/**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
+ * @return {?WebInspector.TracingModel.Event} event
+ */
+ _addEvent: function(payload)
+ {
+ var phase = WebInspector.TracingModel.Phase;
+
+ var event = this.threadById(payload.tid)._addEvent(payload);
+ if (!event)
+ return null;
+ // Build async event when we've got events from all threads, so we can sort them and process in the chronological order.
+ // However, also add individual async events to the thread flow (above), so we can easily display them on the same chart as
+ // other events, should we choose so.
+ if (WebInspector.TracingModel.isAsyncPhase(payload.ph))
+ this._asyncEvents.push(event);
+ if (payload.ph === phase.SnapshotObject)
+ this.objectsByName(event.name).push(event);
+ return event;
+ },
+
+ /**
+ * @param {!number} lastEventTimeMs
+ */
+ _tracingComplete: function(lastEventTimeMs)
+ {
+ this._asyncEvents.sort(WebInspector.TracingModel.Event.compareStartTime);
+ for (var i = 0; i < this._asyncEvents.length; ++i) {
+ var event = this._asyncEvents[i];
+ if (WebInspector.TracingModel.isNestableAsyncPhase(event.phase))
+ this._addNestableAsyncEvent(event);
+ else
+ this._addAsyncEvent(event);
+ }
+
+ for (var key in this._openAsyncEvents) {
+ var steps = this._openAsyncEvents[key];
+ if (!steps)
+ continue;
+ var startEvent = steps[0];
+ var syntheticEndEvent = new WebInspector.TracingModel.Event(startEvent.category, startEvent.name, WebInspector.TracingModel.Phase.AsyncEnd, lastEventTimeMs, startEvent.thread);
+ steps.push(syntheticEndEvent);
+ startEvent.setEndTime(lastEventTimeMs)
+ }
+ for (var key in this._openNestableAsyncEvents) {
+ var openEvents = this._openNestableAsyncEvents[key];
+ while (openEvents.length)
+ openEvents.pop().setEndTime(lastEventTimeMs);
+ }
+ this._asyncEvents = [];
+ this._openAsyncEvents = {};
+ this._openNestableAsyncEvents = {};
+ },
+
+ /**
+ * @param {!WebInspector.TracingModel.Event} event
+ */
+ _addNestableAsyncEvent: function(event)
+ {
+ var phase = WebInspector.TracingModel.Phase;
+ var key = event.category + "." + event.id;
+ var openEventsStack = this._openNestableAsyncEvents[key];
+
+ switch (event.phase) {
+ case phase.NestableAsyncBegin:
+ if (!openEventsStack) {
+ openEventsStack = [];
+ this._openNestableAsyncEvents[key] = openEventsStack;
+ }
+ openEventsStack.push(event);
+ // fall-through intended
+ case phase.NestableAsyncInstant:
+ event.thread._addAsyncEventSteps([event]);
+ break;
+ case phase.NestableAsyncEnd:
+ if (!openEventsStack)
+ break;
+ var top = openEventsStack.pop();
+ if (top.name !== event.name) {
+ console.error("Begin/end event mismatch for nestable async event, " + top.name + " vs. " + event.name);
+ break;
+ }
+ top.setEndTime(event.startTime);
+ }
+ },
+
+ /**
* @param {!WebInspector.TracingModel.Event} event
*/
- addObject: function(event)
+ _addAsyncEvent: function(event)
{
- this.objectsByName(event.name).push(event);
+ var phase = WebInspector.TracingModel.Phase;
+ var key = event.category + "." + event.name + "." + event.id;
+ var steps = this._openAsyncEvents[key];
+
+ if (event.phase === phase.AsyncBegin) {
+ if (steps) {
+ console.error("Event " + event.name + " has already been started");
+ return;
+ }
+ steps = [event];
+ this._openAsyncEvents[key] = steps;
+ event.thread._addAsyncEventSteps(steps);
+ return;
+ }
+ if (!steps) {
+ console.error("Unexpected async event " + event.name + ", phase " + event.phase);
+ return;
+ }
+ if (event.phase === phase.AsyncEnd) {
+ steps.push(event);
+ steps[0].setEndTime(event.startTime);
+ delete this._openAsyncEvents[key];
+ } else if (event.phase === phase.AsyncStepInto || event.phase === phase.AsyncStepPast) {
+ var lastPhase = steps.peekLast().phase;
+ if (lastPhase !== phase.AsyncBegin && lastPhase !== event.phase) {
+ console.assert(false, "Async event step phase mismatch: " + lastPhase + " at " + steps.peekLast().startTime + " vs. " + event.phase + " at " + event.startTime);
+ return;
+ }
+ steps.push(event);
+ } else {
+ console.assert(false, "Invalid async event phase");
+ }
},
/**
this._process = process;
this._setName("Thread " + id);
this._events = [];
+ this._asyncEvents = [];
+ this._id = id;
+
this._stack = [];
- this._maxStackDepth = 0;
}
WebInspector.TracingModel.Thread.prototype = {
/**
- * @param {!WebInspector.TracingModel.EventPayload} payload
+ * @return {?WebInspector.Target}
+ */
+ target: function()
+ {
+ //FIXME: correctly specify target
+ return WebInspector.targetManager.targets()[0] || null;
+ },
+
+ /**
+ * @param {!WebInspector.TracingManager.EventPayload} payload
* @return {?WebInspector.TracingModel.Event} event
*/
- addEvent: function(payload)
+ _addEvent: function(payload)
{
- for (var top = this._stack.peekLast(); top && top.endTime && top.endTime <= payload.ts / 1000;) {
- this._stack.pop();
- top = this._stack.peekLast();
- }
+ var timestamp = payload.ts / 1000;
if (payload.ph === WebInspector.TracingModel.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);
+ if (!this._stack.length)
+ return null;
+ var top = this._stack.pop();
+ if (top.name !== payload.name || top.category !== payload.cat)
+ console.error("B/E events mismatch at " + top.startTime + " (" + top.name + ") vs. " + timestamp + " (" + payload.name + ")");
+ else
+ top._complete(payload);
return null;
}
-
- var event = new WebInspector.TracingModel.Event(payload, this._stack.length, this);
- if (payload.ph === WebInspector.TracingModel.Phase.Begin || payload.ph === WebInspector.TracingModel.Phase.Complete) {
+ var event = payload.ph === WebInspector.TracingModel.Phase.SnapshotObject
+ ? WebInspector.TracingModel.ObjectSnapshot.fromPayload(payload, this)
+ : WebInspector.TracingModel.Event.fromPayload(payload, this);
+ if (payload.ph === WebInspector.TracingModel.Phase.Begin)
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);
+ console.assert(false, "Event is out of order: " + event.name);
this._events.push(event);
return event;
},
/**
- * @return {!WebInspector.TracingModel.Process}
+ * @param {!Array.<!WebInspector.TracingModel.Event>} eventSteps
*/
- process: function()
+ _addAsyncEventSteps: function(eventSteps)
{
- return this._process;
+ this._asyncEvents.push(eventSteps);
},
/**
- * @return {!Array.<!WebInspector.TracingModel.Event>}
+ * @return {number}
*/
- events: function()
+ id: function()
{
- return this._events;
+ return this._id;
},
/**
- * @return {number}
+ * @return {!WebInspector.TracingModel.Process}
*/
- maxStackDepth: function()
+ process: function()
{
- // Reserve one for non-container events.
- return this._maxStackDepth + 1;
+ return this._process;
},
- __proto__: WebInspector.TracingModel.NamedObject.prototype
-}
-
-
-/**
- * @constructor
- * @implements {TracingAgent.Dispatcher}
- * @param {!WebInspector.TracingModel} tracingModel
- */
-WebInspector.TracingDispatcher = function(tracingModel)
-{
- this._tracingModel = tracingModel;
-}
-
-WebInspector.TracingDispatcher.prototype = {
/**
- * @param {number} usage
+ * @return {!Array.<!WebInspector.TracingModel.Event>}
*/
- bufferUsage: function(usage)
+ events: function()
{
- this._tracingModel._bufferUsage(usage);
+ return this._events;
},
/**
- * @param {!Array.<!WebInspector.TracingModel.EventPayload>} data
+ * @return {!Array.<!WebInspector.TracingModel.Event>}
*/
- dataCollected: function(data)
+ asyncEvents: function()
{
- this._tracingModel._eventsCollected(data);
+ return this._asyncEvents;
},
- tracingComplete: function()
- {
- this._tracingModel._tracingComplete();
- }
+ __proto__: WebInspector.TracingModel.NamedObject.prototype
}