From e34e91910fdd5c8bdcd7e871f84b27ec1ac488c6 Mon Sep 17 00:00:00 2001 From: "caseq@chromium.org" Date: Tue, 3 Jul 2012 15:27:06 +0000 Subject: [PATCH] Web Inspector: Forward message loop instrumentation data to frontend. https://bugs.webkit.org/show_bug.cgi?id=89584 Patch by Eugene Klyuchnikov on 2012-07-03 Reviewed by Yury Semikhatsky. Transmit collected message loop tasks to inspector frontend. Now "Program" should be a top-level event on browsers that support message loop instrumentation. Frontend was changed so that user will not see any changes. Source/WebCore: * inspector/InspectorTimelineAgent.cpp: (TimelineRecordType): Added new event type - "Program" (WebCore::InspectorTimelineAgent::willProcessTask): Begin "Program" event. (WebCore::InspectorTimelineAgent::didProcessTask): Finish "Program" event. (WebCore::InspectorTimelineAgent::setHeapSizeStatistic): Do not add counters to "Program" events. (WebCore): (WebCore::InspectorTimelineAgent::innerSetHeapSizeStatistic): Renamed from "setHeapSizeStatistic" * inspector/InspectorTimelineAgent.h: (InspectorTimelineAgent): * inspector/front-end/MemoryStatistics.js: (WebInspector.MemoryStatistics.prototype._onRecordAdded): Unwraps "Program" events. (WebInspector.MemoryStatistics.prototype._innerRecordAdded): Renamed from "_onRecordAdded" * inspector/front-end/TimelineFrameController.js: (WebInspector.TimelineFrameController.prototype._addRecord): Unwraps "Program" events. (WebInspector.TimelineFrameController.prototype._innerAddRecord): Renamed from "_addRecord" * inspector/front-end/TimelineModel.js: * inspector/front-end/TimelineOverviewPane.js: (WebInspector.TimelineCategoryStrips.prototype.update.appendRecord): Filter out "Program" category. (WebInspector.TimelineCategoryStrips.prototype.update): * inspector/front-end/TimelinePanel.js: (WebInspector.TimelinePanel.prototype._createStatusbarButtons): Filter out "Program" category. (WebInspector.TimelinePanel.prototype._innerAddRecordToTimeline): Unwraps "Program" events. * inspector/front-end/TimelinePresentationModel.js: (WebInspector.TimelinePresentationModel.categories): Added "Program" category. (WebInspector.TimelinePresentationModel.recordStyle): Ditto. (WebInspector.TimelinePresentationModel.prototype.addRecord): Unwraps "Program" events. (WebInspector.TimelinePresentationModel.prototype._addRecord): Renamed from "addRecord" LayoutTests: * inspector/timeline/timeline-enum-stability-expected.txt: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121767 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 14 ++++++ LayoutTests/inspector/timeline-dfs-expected.txt | 34 +++++++++++++ LayoutTests/inspector/timeline-dfs.html | 50 +++++++++++++++++++ .../timeline/timeline-enum-stability-expected.txt | 1 + Source/WebCore/ChangeLog | 56 ++++++++++++++++++++++ .../WebCore/inspector/InspectorTimelineAgent.cpp | 16 +++++-- Source/WebCore/inspector/InspectorTimelineAgent.h | 4 +- .../inspector/front-end/MemoryStatistics.js | 23 +++++---- .../inspector/front-end/TimelineFrameController.js | 10 ++++ .../WebCore/inspector/front-end/TimelineModel.js | 1 + .../inspector/front-end/TimelineOverviewPane.js | 2 + .../WebCore/inspector/front-end/TimelinePanel.js | 14 ++++-- .../front-end/TimelinePresentationModel.js | 45 +++++++++++++---- 13 files changed, 241 insertions(+), 29 deletions(-) create mode 100644 LayoutTests/inspector/timeline-dfs-expected.txt create mode 100644 LayoutTests/inspector/timeline-dfs.html diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 7f10002..7aa5c99 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,17 @@ +2012-07-03 Eugene Klyuchnikov + + Web Inspector: Forward message loop instrumentation data to frontend. + https://bugs.webkit.org/show_bug.cgi?id=89584 + + Reviewed by Yury Semikhatsky. + + Transmit collected message loop tasks to inspector frontend. + Now "Program" should be a top-level event on browsers that + support message loop instrumentation. + Frontend was changed so that user will not see any changes. + + * inspector/timeline/timeline-enum-stability-expected.txt: + 2012-07-03 Vsevolod Vlasov inspector/debugger/script-snippet-model.html fails diff --git a/LayoutTests/inspector/timeline-dfs-expected.txt b/LayoutTests/inspector/timeline-dfs-expected.txt new file mode 100644 index 0000000..13a6c1f --- /dev/null +++ b/LayoutTests/inspector/timeline-dfs-expected.txt @@ -0,0 +1,34 @@ +Tests TimelinePresentationModel.forAllRecords function. + +DFS preorder: +a +aa +aaa +aab +ab +aba +abb +b +ba +baa +bab +bb +bba +bbb + +DFS postorder: +aaa +aab +aa +aba +abb +ab +a +baa +bab +ba +bba +bbb +bb +b + diff --git a/LayoutTests/inspector/timeline-dfs.html b/LayoutTests/inspector/timeline-dfs.html new file mode 100644 index 0000000..d5e4316 --- /dev/null +++ b/LayoutTests/inspector/timeline-dfs.html @@ -0,0 +1,50 @@ + + + + + + +

Tests TimelinePresentationModel.forAllRecords function.

+ + diff --git a/LayoutTests/inspector/timeline/timeline-enum-stability-expected.txt b/LayoutTests/inspector/timeline/timeline-enum-stability-expected.txt index f15e89a..3ea73ba 100644 --- a/LayoutTests/inspector/timeline/timeline-enum-stability-expected.txt +++ b/LayoutTests/inspector/timeline/timeline-enum-stability-expected.txt @@ -4,6 +4,7 @@ Applications outside of WebKit depend on the stability of the mapping of these t { Root : "Root" + Program : "Program" EventDispatch : "EventDispatch" BeginFrame : "BeginFrame" Layout : "Layout" diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index f6fcfcd..56481e9 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,59 @@ +2012-07-03 Eugene Klyuchnikov + + Web Inspector: Forward message loop instrumentation data to frontend. + https://bugs.webkit.org/show_bug.cgi?id=89584 + + Reviewed by Yury Semikhatsky. + + Transmit collected message loop tasks to inspector frontend. + Now "Program" should be a top-level event on browsers that + support message loop instrumentation. + Frontend was changed so that user will not see any changes. + + * inspector/InspectorTimelineAgent.cpp: + (TimelineRecordType): + Added new event type - "Program" + (WebCore::InspectorTimelineAgent::willProcessTask): + Begin "Program" event. + (WebCore::InspectorTimelineAgent::didProcessTask): + Finish "Program" event. + (WebCore::InspectorTimelineAgent::setHeapSizeStatistic): + Do not add counters to "Program" events. + (WebCore): + (WebCore::InspectorTimelineAgent::innerSetHeapSizeStatistic): + Renamed from "setHeapSizeStatistic" + * inspector/InspectorTimelineAgent.h: + (InspectorTimelineAgent): + * inspector/front-end/MemoryStatistics.js: + (WebInspector.MemoryStatistics.prototype._onRecordAdded): + Unwraps "Program" events. + (WebInspector.MemoryStatistics.prototype._innerRecordAdded): + Renamed from "_onRecordAdded" + * inspector/front-end/TimelineFrameController.js: + (WebInspector.TimelineFrameController.prototype._addRecord): + Unwraps "Program" events. + (WebInspector.TimelineFrameController.prototype._innerAddRecord): + Renamed from "_addRecord" + * inspector/front-end/TimelineModel.js: + * inspector/front-end/TimelineOverviewPane.js: + (WebInspector.TimelineCategoryStrips.prototype.update.appendRecord): + Filter out "Program" category. + (WebInspector.TimelineCategoryStrips.prototype.update): + * inspector/front-end/TimelinePanel.js: + (WebInspector.TimelinePanel.prototype._createStatusbarButtons): + Filter out "Program" category. + (WebInspector.TimelinePanel.prototype._innerAddRecordToTimeline): + Unwraps "Program" events. + * inspector/front-end/TimelinePresentationModel.js: + (WebInspector.TimelinePresentationModel.categories): + Added "Program" category. + (WebInspector.TimelinePresentationModel.recordStyle): + Ditto. + (WebInspector.TimelinePresentationModel.prototype.addRecord): + Unwraps "Program" events. + (WebInspector.TimelinePresentationModel.prototype._addRecord): + Renamed from "addRecord" + 2012-07-03 Tor Arne Vestbø [Qt] Make use of .qmake.cache for caching features diff --git a/Source/WebCore/inspector/InspectorTimelineAgent.cpp b/Source/WebCore/inspector/InspectorTimelineAgent.cpp index 30ed7cd..a956ab2 100644 --- a/Source/WebCore/inspector/InspectorTimelineAgent.cpp +++ b/Source/WebCore/inspector/InspectorTimelineAgent.cpp @@ -60,6 +60,8 @@ static const char includeMemoryDetails[] = "includeMemoryDetails"; // Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js namespace TimelineRecordType { +static const char Program[] = "Program"; + static const char EventDispatch[] = "EventDispatch"; static const char BeginFrame[] = "BeginFrame"; static const char Layout[] = "Layout"; @@ -342,7 +344,7 @@ void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, c String frameId(m_pageAgent->frameId(frame)); recordRaw->setString("frameId", frameId); } - setHeapSizeStatistic(recordRaw.get()); + setHeapSizeStatistics(recordRaw.get()); // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now. RefPtr record = TypeBuilder::Timeline::TimelineEvent::runtimeCast(recordRaw.release()); m_frontend->eventRecorded(record.release()); @@ -427,12 +429,12 @@ void InspectorTimelineAgent::didFireAnimationFrame() void InspectorTimelineAgent::willProcessTask() { - // TODO: Record task processing start time. + pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Program, false, 0); } void InspectorTimelineAgent::didProcessTask() { - // TODO: Record task processing end time. + didCompleteCurrentRecord(TimelineRecordType::Program); } void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr record, const String& type, const String& frameId) @@ -443,11 +445,15 @@ void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr rec void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr prpRecord, const String& type, const String& frameId) { + DEFINE_STATIC_LOCAL(String, program, (TimelineRecordType::Program)); + RefPtr record(prpRecord); record->setString("type", type); if (!frameId.isEmpty()) record->setString("frameId", frameId); - setHeapSizeStatistic(record.get()); + if (type != program) + setHeapSizeStatistics(record.get()); + if (m_recordStack.isEmpty()) { // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now. RefPtr recordChecked = TypeBuilder::Timeline::TimelineEvent::runtimeCast(record.release()); @@ -458,7 +464,7 @@ void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr, const String& type, bool captureCallStack, Frame*); - void setHeapSizeStatistic(InspectorObject* record); - + void setHeapSizeStatistics(InspectorObject* record); + void didCompleteCurrentRecord(const String& type); void appendRecord(PassRefPtr data, const String& type, bool captureCallStack, Frame*); void pushCancelableRecord(PassRefPtr, const String& type, Frame*); diff --git a/Source/WebCore/inspector/front-end/MemoryStatistics.js b/Source/WebCore/inspector/front-end/MemoryStatistics.js index c915ce7..aa52e22 100644 --- a/Source/WebCore/inspector/front-end/MemoryStatistics.js +++ b/Source/WebCore/inspector/front-end/MemoryStatistics.js @@ -257,15 +257,20 @@ WebInspector.MemoryStatistics.prototype = { _onRecordAdded: function(event) { - var counters = event.data["counters"]; - if (!counters) - return; - this._counters.push({ - time: event.data.endTime || event.data.startTime, - documentCount: counters["documents"], - nodeCount: counters["nodes"], - listenerCount: counters["jsEventListeners"] - }); + var statistics = this._counters; + function addStatistics(record) + { + var counters = record["counters"]; + if (!counters) + return; + statistics.push({ + time: record.endTime || record.startTime, + documentCount: counters["documents"], + nodeCount: counters["nodes"], + listenerCount: counters["jsEventListeners"] + }); + } + WebInspector.TimelinePresentationModel.forAllRecords([event.data], null, addStatistics); }, _draw: function() diff --git a/Source/WebCore/inspector/front-end/TimelineFrameController.js b/Source/WebCore/inspector/front-end/TimelineFrameController.js index 4e41e24..0638096 100644 --- a/Source/WebCore/inspector/front-end/TimelineFrameController.js +++ b/Source/WebCore/inspector/front-end/TimelineFrameController.js @@ -61,6 +61,16 @@ WebInspector.TimelineFrameController.prototype = { _addRecord: function(record) { + var records; + if (record.type === WebInspector.TimelineModel.RecordType.Program) + records = record["children"] || []; + else + records = [record]; + records.forEach(this._innerAddRecord, this); + }, + + _innerAddRecord: function(record) + { if (record.type === WebInspector.TimelineModel.RecordType.BeginFrame && this._lastFrame) this._flushFrame(record); else { diff --git a/Source/WebCore/inspector/front-end/TimelineModel.js b/Source/WebCore/inspector/front-end/TimelineModel.js index a5fab15..b3b6a66 100644 --- a/Source/WebCore/inspector/front-end/TimelineModel.js +++ b/Source/WebCore/inspector/front-end/TimelineModel.js @@ -44,6 +44,7 @@ WebInspector.TimelineModel = function() WebInspector.TimelineModel.RecordType = { Root: "Root", + Program: "Program", EventDispatch: "EventDispatch", BeginFrame: "BeginFrame", diff --git a/Source/WebCore/inspector/front-end/TimelineOverviewPane.js b/Source/WebCore/inspector/front-end/TimelineOverviewPane.js index 4e4891e..0a28c3b 100644 --- a/Source/WebCore/inspector/front-end/TimelineOverviewPane.js +++ b/Source/WebCore/inspector/front-end/TimelineOverviewPane.js @@ -885,6 +885,8 @@ WebInspector.TimelineCategoryStrips.prototype = { var recordStart = Math.floor((WebInspector.TimelineModel.startTimeInSeconds(record) - timeOffset) * scale); var recordEnd = Math.ceil((WebInspector.TimelineModel.endTimeInSeconds(record) - timeOffset) * scale); var category = WebInspector.TimelinePresentationModel.categoryForRecord(record); + if (category.overviewStripGroupIndex < 0) + return; var bar = lastBarByGroup[category.overviewStripGroupIndex]; // This bar may be merged with previous -- so just adjust the previous bar. const barsMergeThreshold = 2; diff --git a/Source/WebCore/inspector/front-end/TimelinePanel.js b/Source/WebCore/inspector/front-end/TimelinePanel.js index 83f5e53..a266738 100644 --- a/Source/WebCore/inspector/front-end/TimelinePanel.js +++ b/Source/WebCore/inspector/front-end/TimelinePanel.js @@ -232,6 +232,8 @@ WebInspector.TimelinePanel.prototype = { var categories = WebInspector.TimelinePresentationModel.categories(); for (var categoryName in categories) { var category = categories[categoryName]; + if (category.overviewStripGroupIndex < 0) + continue; this.statusBarFilters.appendChild(this._createTimelineCategoryStatusBarCheckbox(category, this._onCategoryCheckboxClicked.bind(this, category))); } }, @@ -495,8 +497,8 @@ WebInspector.TimelinePanel.prototype = { _innerAddRecordToTimeline: function(record, parentRecord) { - var formattedRecord = this._presentationModel.addRecord(record, parentRecord); - ++this._allRecordsCount; + var records = this._presentationModel.addRecord(record, parentRecord); + this._allRecordsCount += records.length; var recordTypes = WebInspector.TimelineModel.RecordType; var timeStampRecords = this._timeStampRecords; var hasVisibleRecords = false; @@ -507,10 +509,14 @@ WebInspector.TimelinePanel.prototype = { timeStampRecords.push(record); hasVisibleRecords |= presentationModel.isVisible(record); } - var records = [ formattedRecord ]; WebInspector.TimelinePresentationModel.forAllRecords(records, processRecord); + + function isAdoptedRecord(record) + { + return record.parent !== presentationModel.rootRecord; + } // Tell caller update is necessary either if we added a visible record or if we re-parented a record. - return hasVisibleRecords || formattedRecord.parent !== this._presentationModel.rootRecord; + return hasVisibleRecords || records.some(isAdoptedRecord); }, sidebarResized: function(event) diff --git a/Source/WebCore/inspector/front-end/TimelinePresentationModel.js b/Source/WebCore/inspector/front-end/TimelinePresentationModel.js index 2a2e6a2..7ba1b05 100644 --- a/Source/WebCore/inspector/front-end/TimelinePresentationModel.js +++ b/Source/WebCore/inspector/front-end/TimelinePresentationModel.js @@ -47,6 +47,7 @@ WebInspector.TimelinePresentationModel.categories = function() if (WebInspector.TimelinePresentationModel._categories) return WebInspector.TimelinePresentationModel._categories; WebInspector.TimelinePresentationModel._categories = { + program: new WebInspector.TimelineCategory("program", WebInspector.UIString("Program"), -1, "#BBBBBB", "#DDDDDD", "#FFFFFF"), loading: new WebInspector.TimelineCategory("loading", WebInspector.UIString("Loading"), 0, "#5A8BCC", "#8EB6E9", "#70A2E3"), scripting: new WebInspector.TimelineCategory("scripting", WebInspector.UIString("Scripting"), 1, "#D8AA34", "#F3D07A", "#F1C453"), rendering: new WebInspector.TimelineCategory("rendering", WebInspector.UIString("Rendering"), 2, "#8266CC", "#AF9AEB", "#9A7EE6"), @@ -68,6 +69,7 @@ WebInspector.TimelinePresentationModel.recordStyle = function(record) var recordStyles = {}; recordStyles[recordTypes.Root] = { title: "#root", category: categories["loading"] }; + recordStyles[recordTypes.Program] = { title: WebInspector.UIString("Program"), category: categories["program"] }; recordStyles[recordTypes.EventDispatch] = { title: WebInspector.UIString("Event"), category: categories["scripting"] }; recordStyles[recordTypes.BeginFrame] = { title: WebInspector.UIString("Frame Start"), category: categories["rendering"] }; recordStyles[recordTypes.Layout] = { title: WebInspector.UIString("Layout"), category: categories["rendering"] }; @@ -103,7 +105,7 @@ WebInspector.TimelinePresentationModel.recordStyle = function(record) WebInspector.TimelinePresentationModel.categoryForRecord = function(record) { - return WebInspector.TimelinePresentationModel.recordStyle(record).category; + return WebInspector.TimelinePresentationModel.recordStyle(record).category; } WebInspector.TimelinePresentationModel.isEventDivider = function(record) @@ -117,7 +119,12 @@ WebInspector.TimelinePresentationModel.isEventDivider = function(record) return false; } -WebInspector.TimelinePresentationModel.forAllRecords = function(recordsArray, callback) +/** + * @param {Array} recordsArray + * @param {?function(*)} preOrderCallback + * @param {function(*)=} postOrderCallback + */ +WebInspector.TimelinePresentationModel.forAllRecords = function(recordsArray, preOrderCallback, postOrderCallback) { if (!recordsArray) return; @@ -127,13 +134,18 @@ WebInspector.TimelinePresentationModel.forAllRecords = function(recordsArray, ca var records = entry.array; if (entry.index < records.length) { var record = records[entry.index]; - if (callback(record)) + if (preOrderCallback && preOrderCallback(record)) return; if (record.children) - stack.push({array: record.children, index: 0}); + stack.push({array: record.children, index: 0, record: record}); + else if (postOrderCallback && postOrderCallback(record)) + return; ++entry.index; - } else + } else { + if (entry.record && postOrderCallback && postOrderCallback(entry.record)) + return; stack.pop(); + } } } @@ -205,12 +217,27 @@ WebInspector.TimelinePresentationModel.prototype = { addRecord: function(record, parentRecord) { - var connectedToOldRecord = false; - var recordTypes = WebInspector.TimelineModel.RecordType; - if (this._minimumRecordTime === -1 || record.startTime < this._minimumRecordTime) this._minimumRecordTime = WebInspector.TimelineModel.startTimeInSeconds(record); + var records; + if (record.type === WebInspector.TimelineModel.RecordType.Program) + records = record.children; + else + records = [record]; + + var formattedRecords = []; + var recordsCount = records.length; + for (var i = 0; i < recordsCount; ++i) + formattedRecords.push(this._innerAddRecord(records[i], parentRecord)); + return formattedRecords; + }, + + _innerAddRecord: function(record, parentRecord) + { + var connectedToOldRecord = false; + var recordTypes = WebInspector.TimelineModel.RecordType; + switch (record.type) { // No bar entry for load events. case recordTypes.MarkDOMContent: @@ -257,7 +284,7 @@ WebInspector.TimelinePresentationModel.prototype = { var childrenCount = children ? children.length : 0; for (var i = 0; i < childrenCount; ++i) - this.addRecord(children[i], formattedRecord); + this._innerAddRecord(children[i], formattedRecord); formattedRecord.calculateAggregatedStats(WebInspector.TimelinePresentationModel.categories()); -- 2.7.4