Title: [105877] trunk/Source/WebCore
Revision
105877
Author
[email protected]
Date
2012-01-25 07:10:31 -0800 (Wed, 25 Jan 2012)

Log Message

Web Inspector: show memory counter graphs in timeline panel
https://bugs.webkit.org/show_bug.cgi?id=76843

Timeline panel is extended with several graphs depicting total node count,
number of DOM groups and event listeners. This feature is hidden behind
experimental setting.

Reviewed by Pavel Feldman.

* English.lproj/localizedStrings.js:
* inspector/Inspector.json:
* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
* inspector/InspectorTimelineAgent.cpp:
(WebCore::InspectorTimelineAgent::setDomCountersEnabled):
(WebCore::InspectorTimelineAgent::didCallFunction):
(WebCore::InspectorTimelineAgent::didDispatchEvent):
(WebCore::InspectorTimelineAgent::didWriteHTML):
(WebCore::InspectorTimelineAgent::didFireTimer):
(WebCore::InspectorTimelineAgent::didEvaluateScript):
(WebCore::InspectorTimelineAgent::setHeapSizeStatistic):
(WebCore::InspectorTimelineAgent::collectDomCounters):
(WebCore::InspectorTimelineAgent::InspectorTimelineAgent):
* inspector/InspectorTimelineAgent.h:
(WebCore::InspectorTimelineAgent::create):
* inspector/TimelineRecordFactory.cpp:
* inspector/front-end/Settings.js:
(WebInspector.ExperimentsSettings):
* inspector/front-end/TimelinePanel.js:
(WebInspector.TimelinePanel):
(WebInspector.MemoryStatistics):
(WebInspector.MemoryStatistics.prototype.setTopPosition):
(WebInspector.MemoryStatistics.prototype.setSidebarWidth):
(WebInspector.MemoryStatistics.prototype._sidebarResized):
(WebInspector.MemoryStatistics.prototype._updateSize):
(WebInspector.MemoryStatistics.prototype._updateSidebarSize):
(WebInspector.MemoryStatistics.prototype._createCounterSidebarElement):
(WebInspector.MemoryStatistics.prototype.addTimlineEvent):
(WebInspector.MemoryStatistics.prototype._draw.getGroupCount):
(WebInspector.MemoryStatistics.prototype._draw.getNodeCount):
(WebInspector.MemoryStatistics.prototype._draw.getListenerCount):
(WebInspector.MemoryStatistics.prototype._draw):
(WebInspector.MemoryStatistics.prototype._calculateVisibleIndexes):
(WebInspector.MemoryStatistics.prototype._onMouseOver):
(WebInspector.MemoryStatistics.prototype._refreshCurrentValues):
(WebInspector.MemoryStatistics.prototype.visible):
(WebInspector.MemoryStatistics.prototype.show):
(WebInspector.MemoryStatistics.prototype.refresh):
(WebInspector.MemoryStatistics.prototype.hide):
(WebInspector.MemoryStatistics.prototype._setVerticalClip):
(WebInspector.MemoryStatistics.prototype._calculateXValues):
(WebInspector.MemoryStatistics.prototype._drawPolyline):
(WebInspector.MemoryStatistics.prototype._drawBottomBound):
(WebInspector.MemoryStatistics.prototype._clear):
(WebInspector.TimelinePanel.prototype._startSplitterDragging):
(WebInspector.TimelinePanel.prototype._splitterDragging):
(WebInspector.TimelinePanel.prototype._endSplitterDragging):
(WebInspector.TimelinePanel.prototype._setSplitterPosition):
(WebInspector.TimelinePanel.prototype.get statusBarItems):
(WebInspector.TimelinePanel.prototype._createStatusbarButtons):
(WebInspector.TimelinePanel.prototype._toggleMemoryStatistics):
(WebInspector.TimelinePanel.prototype._onTimelineEventRecorded):
(WebInspector.TimelinePanel.prototype.sidebarResized):
(WebInspector.TimelinePanel.prototype._refresh):
* inspector/front-end/timelinePanel.css:
(#timeline-memory-splitter):
(#memory-counters-graph):
(#memory-graphs-container):
(#memory-graphs-container .split-view-contents):
(.timeline-marker):
(.memory-counter-sidebar-info):
(.memory-counter-sidebar-info.bottom-border-visible):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (105876 => 105877)


--- trunk/Source/WebCore/ChangeLog	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/ChangeLog	2012-01-25 15:10:31 UTC (rev 105877)
@@ -1,3 +1,78 @@
+2012-01-23  Yury Semikhatsky  <[email protected]>
+
+        Web Inspector: show memory counter graphs in timeline panel
+        https://bugs.webkit.org/show_bug.cgi?id=76843
+
+        Timeline panel is extended with several graphs depicting total node count,
+        number of DOM groups and event listeners. This feature is hidden behind
+        experimental setting.
+
+        Reviewed by Pavel Feldman.
+
+        * English.lproj/localizedStrings.js:
+        * inspector/Inspector.json:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        * inspector/InspectorTimelineAgent.cpp:
+        (WebCore::InspectorTimelineAgent::setDomCountersEnabled):
+        (WebCore::InspectorTimelineAgent::didCallFunction):
+        (WebCore::InspectorTimelineAgent::didDispatchEvent):
+        (WebCore::InspectorTimelineAgent::didWriteHTML):
+        (WebCore::InspectorTimelineAgent::didFireTimer):
+        (WebCore::InspectorTimelineAgent::didEvaluateScript):
+        (WebCore::InspectorTimelineAgent::setHeapSizeStatistic):
+        (WebCore::InspectorTimelineAgent::collectDomCounters):
+        (WebCore::InspectorTimelineAgent::InspectorTimelineAgent):
+        * inspector/InspectorTimelineAgent.h:
+        (WebCore::InspectorTimelineAgent::create):
+        * inspector/TimelineRecordFactory.cpp:
+        * inspector/front-end/Settings.js:
+        (WebInspector.ExperimentsSettings):
+        * inspector/front-end/TimelinePanel.js:
+        (WebInspector.TimelinePanel):
+        (WebInspector.MemoryStatistics):
+        (WebInspector.MemoryStatistics.prototype.setTopPosition):
+        (WebInspector.MemoryStatistics.prototype.setSidebarWidth):
+        (WebInspector.MemoryStatistics.prototype._sidebarResized):
+        (WebInspector.MemoryStatistics.prototype._updateSize):
+        (WebInspector.MemoryStatistics.prototype._updateSidebarSize):
+        (WebInspector.MemoryStatistics.prototype._createCounterSidebarElement):
+        (WebInspector.MemoryStatistics.prototype.addTimlineEvent):
+        (WebInspector.MemoryStatistics.prototype._draw.getGroupCount):
+        (WebInspector.MemoryStatistics.prototype._draw.getNodeCount):
+        (WebInspector.MemoryStatistics.prototype._draw.getListenerCount):
+        (WebInspector.MemoryStatistics.prototype._draw):
+        (WebInspector.MemoryStatistics.prototype._calculateVisibleIndexes):
+        (WebInspector.MemoryStatistics.prototype._onMouseOver):
+        (WebInspector.MemoryStatistics.prototype._refreshCurrentValues):
+        (WebInspector.MemoryStatistics.prototype.visible):
+        (WebInspector.MemoryStatistics.prototype.show):
+        (WebInspector.MemoryStatistics.prototype.refresh):
+        (WebInspector.MemoryStatistics.prototype.hide):
+        (WebInspector.MemoryStatistics.prototype._setVerticalClip):
+        (WebInspector.MemoryStatistics.prototype._calculateXValues):
+        (WebInspector.MemoryStatistics.prototype._drawPolyline):
+        (WebInspector.MemoryStatistics.prototype._drawBottomBound):
+        (WebInspector.MemoryStatistics.prototype._clear):
+        (WebInspector.TimelinePanel.prototype._startSplitterDragging):
+        (WebInspector.TimelinePanel.prototype._splitterDragging):
+        (WebInspector.TimelinePanel.prototype._endSplitterDragging):
+        (WebInspector.TimelinePanel.prototype._setSplitterPosition):
+        (WebInspector.TimelinePanel.prototype.get statusBarItems):
+        (WebInspector.TimelinePanel.prototype._createStatusbarButtons):
+        (WebInspector.TimelinePanel.prototype._toggleMemoryStatistics):
+        (WebInspector.TimelinePanel.prototype._onTimelineEventRecorded):
+        (WebInspector.TimelinePanel.prototype.sidebarResized):
+        (WebInspector.TimelinePanel.prototype._refresh):
+        * inspector/front-end/timelinePanel.css:
+        (#timeline-memory-splitter):
+        (#memory-counters-graph):
+        (#memory-graphs-container):
+        (#memory-graphs-container .split-view-contents):
+        (.timeline-marker):
+        (.memory-counter-sidebar-info):
+        (.memory-counter-sidebar-info.bottom-border-visible):
+
 2012-01-25  Joseph Pecoraro  <[email protected]>
 
         <http://webkit.org/b/76941> Web Inspector: Remove Unused InspectorFrontendHost.search Stub

Modified: trunk/Source/WebCore/English.lproj/localizedStrings.js


(Binary files differ)

Modified: trunk/Source/WebCore/WebCore.gypi (105876 => 105877)


--- trunk/Source/WebCore/WebCore.gypi	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/WebCore.gypi	2012-01-25 15:10:31 UTC (rev 105877)
@@ -6112,6 +6112,7 @@
             'inspector/front-end/_javascript_Formatter.js',
             'inspector/front-end/_javascript_SourceFrame.js',
             'inspector/front-end/KeyboardShortcut.js',
+            'inspector/front-end/MemoryStatistics.js',
             'inspector/front-end/MetricsSidebarPane.js',
             'inspector/front-end/NetworkItemView.js',
             'inspector/front-end/NetworkManager.js',

Modified: trunk/Source/WebCore/inspector/Inspector.json (105876 => 105877)


--- trunk/Source/WebCore/inspector/Inspector.json	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/Inspector.json	2012-01-25 15:10:31 UTC (rev 105877)
@@ -1931,6 +1931,14 @@
             {
                 "name": "stop",
                 "description": "Stops capturing instrumentation events."
+            },
+            {
+                "name": "setIncludeMemoryDetails",
+                "parameters": [
+                    { "name": "enabled", "type": "boolean", "description": "True to start collecting DOM counters." }
+                ],
+                "hidden": true,
+                "description": "Starts calculating various DOM statistics and sending them as part of timeline events."
             }
         ],
         "events": [

Modified: trunk/Source/WebCore/inspector/InspectorController.cpp (105876 => 105877)


--- trunk/Source/WebCore/inspector/InspectorController.cpp	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/InspectorController.cpp	2012-01-25 15:10:31 UTC (rev 105877)
@@ -110,7 +110,12 @@
     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
     m_agents.append(domStorageAgentPtr.release());
 
-    m_agents.append(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get()));
+
+    OwnPtr<InspectorMemoryAgent>memoryAgentPtr = InspectorMemoryAgent::create(m_instrumentingAgents.get(), m_state.get(), m_page, m_domAgent);
+    InspectorMemoryAgent* memoryAgent = memoryAgentPtr.get();
+    m_agents.append(memoryAgentPtr.release());
+
+    m_agents.append(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get(), memoryAgent));
     m_agents.append(InspectorApplicationCacheAgent::create(m_instrumentingAgents.get(), m_state.get(), pageAgent));
 
     OwnPtr<InspectorResourceAgent> resourceAgentPtr(InspectorResourceAgent::create(m_instrumentingAgents.get(), pageAgent, inspectorClient, m_state.get()));
@@ -141,8 +146,6 @@
     m_agents.append(InspectorWorkerAgent::create(m_instrumentingAgents.get(), m_state.get()));
 #endif
 
-    m_agents.append(InspectorMemoryAgent::create(m_instrumentingAgents.get(), m_state.get(), m_page, m_domAgent));
-
     ASSERT_ARG(inspectorClient, inspectorClient);
     m_injectedScriptManager->injectedScriptHost()->init(m_inspectorAgent
         , consoleAgent

Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp (105876 => 105877)


--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp	2012-01-25 15:10:31 UTC (rev 105877)
@@ -36,6 +36,7 @@
 #include "Event.h"
 #include "IdentifiersFactory.h"
 #include "InspectorFrontend.h"
+#include "InspectorMemoryAgent.h"
 #include "InspectorState.h"
 #include "InstrumentingAgents.h"
 #include "IntRect.h"
@@ -50,6 +51,7 @@
 namespace TimelineAgentState {
 static const char timelineAgentEnabled[] = "timelineAgentEnabled";
 static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth";
+static const char includeMemoryDetails[] = "includeMemoryDetails";
 }
 
 // Must be kept in sync with TimelineAgent.js
@@ -163,6 +165,11 @@
     m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false);
 }
 
+void InspectorTimelineAgent::setIncludeMemoryDetails(ErrorString*, bool value)
+{
+    m_state->setBoolean(TimelineAgentState::includeMemoryDetails, value);
+}
+
 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine)
 {
     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true);
@@ -170,6 +177,7 @@
 
 void InspectorTimelineAgent::didCallFunction()
 {
+    collectDomCounters();
     didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
 }
 
@@ -180,6 +188,7 @@
 
 void InspectorTimelineAgent::didDispatchEvent()
 {
+    collectDomCounters();
     didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
 }
 
@@ -223,6 +232,7 @@
     if (!m_recordStack.isEmpty()) {
         TimelineRecordEntry entry = m_recordStack.last();
         entry.data->setNumber("endLine", endLine);
+        collectDomCounters();
         didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
     }
 }
@@ -244,6 +254,7 @@
 
 void InspectorTimelineAgent::didFireTimer()
 {
+    collectDomCounters();
     didCompleteCurrentRecord(TimelineRecordType::TimerFire);
 }
 
@@ -274,6 +285,7 @@
     
 void InspectorTimelineAgent::didEvaluateScript()
 {
+    collectDomCounters();
     didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
 }
 
@@ -381,8 +393,25 @@
     ScriptGCEvent::getHeapSize(usedHeapSize, totalHeapSize, heapSizeLimit);
     record->setNumber("usedHeapSize", usedHeapSize);
     record->setNumber("totalHeapSize", totalHeapSize);
+
 }
 
+void InspectorTimelineAgent::collectDomCounters()
+{
+    if (!m_state->getBoolean(TimelineAgentState::includeMemoryDetails))
+        return;
+    if (m_recordStack.isEmpty())
+        return;
+
+    String error;
+    RefPtr<InspectorArray> domGroups;
+    RefPtr<InspectorObject> strings;
+    m_memoryAgent->getDOMNodeCount(&error, domGroups, strings);
+
+    if (domGroups)
+        m_recordStack.last().record->setArray("domGroups", domGroups.release());
+}
+
 void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type)
 {
     // An empty stack could merely mean that the timeline agent was turned on in the middle of
@@ -399,11 +428,12 @@
     }
 }
 
-InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state)
+InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state, InspectorMemoryAgent* memoryAgent)
     : InspectorBaseAgent<InspectorTimelineAgent>("Timeline", instrumentingAgents, state)
     , m_frontend(0)
     , m_id(1)
     , m_maxCallStackDepth(5)
+    , m_memoryAgent(memoryAgent)
 {
 }
 

Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.h (105876 => 105877)


--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.h	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.h	2012-01-25 15:10:31 UTC (rev 105877)
@@ -45,6 +45,7 @@
 namespace WebCore {
 class Event;
 class InspectorFrontend;
+class InspectorMemoryAgent;
 class InspectorState;
 class InstrumentingAgents;
 class IntRect;
@@ -56,9 +57,9 @@
 class InspectorTimelineAgent : public InspectorBaseAgent<InspectorTimelineAgent>, ScriptGCEventListener {
     WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent);
 public:
-    static PassOwnPtr<InspectorTimelineAgent> create(InstrumentingAgents* instrumentingAgents, InspectorState* state)
+    static PassOwnPtr<InspectorTimelineAgent> create(InstrumentingAgents* instrumentingAgents, InspectorState* state, InspectorMemoryAgent* memoryAgent)
     {
-        return adoptPtr(new InspectorTimelineAgent(instrumentingAgents, state));
+        return adoptPtr(new InspectorTimelineAgent(instrumentingAgents, state, memoryAgent));
     }
 
     ~InspectorTimelineAgent();
@@ -69,6 +70,7 @@
 
     void start(ErrorString*, int* maxCallStackDepth);
     void stop(ErrorString*);
+    void setIncludeMemoryDetails(ErrorString*, bool);
 
     int id() const { return m_id; }
 
@@ -139,10 +141,11 @@
         String type;
     };
         
-    InspectorTimelineAgent(InstrumentingAgents*, InspectorState*);
+    InspectorTimelineAgent(InstrumentingAgents*, InspectorState*, InspectorMemoryAgent*);
 
     void pushCurrentRecord(PassRefPtr<InspectorObject>, const String& type, bool captureCallStack);
     void setHeapSizeStatistic(InspectorObject* record);
+    void collectDomCounters();
         
     void didCompleteCurrentRecord(const String& type);
     void appendRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack);
@@ -169,6 +172,7 @@
     typedef Vector<GCEvent> GCEvents;
     GCEvents m_gcEvents;
     int m_maxCallStackDepth;
+    InspectorMemoryAgent* m_memoryAgent;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp (105876 => 105877)


--- trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp	2012-01-25 15:10:31 UTC (rev 105877)
@@ -40,6 +40,7 @@
 #include "ResourceResponse.h"
 #include "ScriptCallStack.h"
 #include "ScriptCallStackFactory.h"
+#include <wtf/CurrentTime.h>
 
 namespace WebCore {
 

Modified: trunk/Source/WebCore/inspector/compile-front-end.sh (105876 => 105877)


--- trunk/Source/WebCore/inspector/compile-front-end.sh	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/compile-front-end.sh	2012-01-25 15:10:31 UTC (rev 105877)
@@ -166,7 +166,8 @@
     --module jsmodule_console:2:jsmodule_components \
         --js Source/WebCore/inspector/front-end/ConsoleView.js \
         --js Source/WebCore/inspector/front-end/ConsolePanel.js \
-    --module jsmodule_timeline:2:jsmodule_components \
+    --module jsmodule_timeline:3:jsmodule_components \
+        --js Source/WebCore/inspector/front-end/MemoryStatistics.js \
         --js Source/WebCore/inspector/front-end/TimelineOverviewPane.js \
         --js Source/WebCore/inspector/front-end/TimelinePanel.js \
     --module jsmodule_audits:6:jsmodule_components \

Added: trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js (0 => 105877)


--- trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js	                        (rev 0)
+++ trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js	2012-01-25 15:10:31 UTC (rev 105877)
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @param {WebInspector.TimelinePanel} timelinePanel
+ * @param {number} sidebarWidth
+ * @constructor
+ */
+WebInspector.MemoryStatistics = function(timelinePanel, sidebarWidth)
+{
+    this._timelinePanel = timelinePanel;
+    this._counters = [];
+
+    this._containerAnchor = timelinePanel.element.lastChild;
+    this._memorySplitView = new WebInspector.SplitView(WebInspector.SplitView.SidebarPosition.Left, undefined, sidebarWidth);
+    this._memorySplitView.sidebarElement.addStyleClass("sidebar");
+    this._memorySplitView.element.id = "memory-graphs-container";
+
+    this._memorySplitView.addEventListener(WebInspector.SplitView.EventTypes.Resized, this._sidebarResized.bind(this));
+
+    this._canvasContainer = this._memorySplitView.mainElement;
+    this._canvas = this._canvasContainer.createChild("canvas", "fill");
+    this._canvas.id = "memory-counters-graph";
+    this._memoryMarker = this._canvasContainer.createChild("div", "timeline-marker");
+
+    this._canvasContainer.addEventListener("mouseover", this._onMouseOver.bind(this), true);
+    this._canvasContainer.addEventListener("mousemove", this._onMouseOver.bind(this), true);
+
+    // Populate sidebar
+    this._counterSidebarElements = [];
+    this._domGroups = this._createCounterSidebarElement(WebInspector.UIString("DOM group count:"), true);
+    this._domNodes = this._createCounterSidebarElement(WebInspector.UIString("DOM node count:"), true);
+    this._listeners = this._createCounterSidebarElement(WebInspector.UIString("Event listener count:"), false);
+
+    TimelineAgent.setIncludeMemoryDetails(true);
+}
+
+WebInspector.MemoryStatistics.prototype = {
+    setTopPosition: function(top)
+    {
+        this._memorySplitView.element.style.top = top + "px";
+        this._updateSize();
+    },
+
+    setSidebarWidth: function(width)
+    {
+        if (this._ignoreSidebarResize)
+            return;
+        this._ignoreSidebarResize = true;
+        this._memorySplitView.setSidebarWidth(width);
+        this._ignoreSidebarResize = false;
+    },
+
+    _sidebarResized: function(event)
+    {
+        if (this._ignoreSidebarResize)
+            return;
+        this._ignoreSidebarResize = true;
+        this._timelinePanel.splitView.setSidebarWidth(event.data);
+        this._ignoreSidebarResize = false;
+    },
+
+    _updateSize: function()
+    {
+        var height = this._canvasContainer.offsetHeight;
+        this._canvas.width = this._canvasContainer.offsetWidth;
+        this._canvas.height = height;
+        this._updateSidebarSize(height);
+    },
+
+    _updateSidebarSize: function(height)
+    {
+        var length = this._counterSidebarElements.length;
+        var graphHeight =  Math.round(height / length);
+        var top = 0;
+        for (var i = 0; i < length; i++) {
+            var element = this._counterSidebarElements[i];
+            element.style.top = top + "px";
+            element.style.height = graphHeight + "px";
+            top += graphHeight;
+        }
+    },
+
+    _createCounterSidebarElement: function(title, showBottomBorder)
+    {
+        var container = this._memorySplitView.sidebarElement.createChild("div", "memory-counter-sidebar-info");
+        var value = container.createChild("p");
+        value.textContent = title;
+        container._value = value.createChild("span");
+        if (showBottomBorder)
+            container.addStyleClass("bottom-border-visible");
+        this._counterSidebarElements.push(container);
+        return container;
+    },
+
+    addTimlineEvent: function(event)
+    {
+        var time = event.data.endTime;
+        var domGroups = event.data["domGroups"];
+
+        var nodeCount = 0;
+        for (var i = 0; i < domGroups.length; i++) {
+            var counters = domGroups[i].nodeCount;
+            for (var j = 0; j < counters.length; j++)
+                nodeCount += counters[j].count;
+        }
+
+        var listenerCount = 0;
+        for (var i = 0; i < domGroups.length; i++) {
+            var counters = domGroups[i].listenerCount;
+            for (var j = 0; j < counters.length; j++)
+                listenerCount += counters[j].count;
+        }
+
+        this._counters.push({
+            time: time,
+            domGroupCount: domGroups.length,
+            nodeCount: nodeCount,
+            listenerCount: listenerCount
+        });
+    },
+
+    _draw: function()
+    {
+        this._calculateVisibleIndexes();
+        this._calculateXValues();
+        this._clear();
+        var graphHeight = Math.round(this._canvas.height / 3);
+
+        function getGroupCount(entry)
+        {
+            return entry.domGroupCount;
+        }
+        this._setVerticalClip(0 * graphHeight + 2, graphHeight - 4);
+        this._drawPolyline(getGroupCount, "rgba(100,0,0,0.8)");
+        this._drawBottomBound("rgba(20,20,20,0.8)");
+
+
+        function getNodeCount(entry)
+        {
+            return entry.nodeCount;
+        }
+        this._setVerticalClip(1 * graphHeight + 2, graphHeight - 4);
+        this._drawPolyline(getNodeCount, "rgba(0,100,0,0.8)");
+        this._drawBottomBound("rgba(20,20,20,0.8)");
+
+        function getListenerCount(entry)
+        {
+            return entry.listenerCount;
+        }
+        this._setVerticalClip(2 * graphHeight + 2, graphHeight - 4);
+        this._drawPolyline(getListenerCount, "rgba(0,0,100,0.8)");
+    },
+
+    _calculateVisibleIndexes: function()
+    {
+        var calculator = this._timelinePanel.calculator;
+        var start = calculator.minimumBoundary * 1000;
+        var end = calculator.maximumBoundary * 1000;
+        var firstIndex;
+        var lastIndex;
+        for (var i = 0; i < this._counters.length; i++) {
+            var time = this._counters[i].time;
+            if (start <= time && time <= end) {
+                if (firstIndex === undefined)
+                    firstIndex = i;
+                lastIndex = i;
+            }
+        }
+        this._minimumIndex = firstIndex;
+        this._maximumIndex = lastIndex;
+    },
+
+    _onMouseOver: function(event)
+    {
+        var x = event.x - event.target.offsetParent.offsetLeft
+        this._memoryMarker.style.left = x + "px";
+        this._refreshCurrentValues(x);
+    },
+
+    _refreshCurrentValues: function(x)
+    {
+        if (!this._counters.length)
+            return;
+        var i;
+        for (i = this._minimumIndex + 1; i <= this._maximumIndex; i++) {
+            var statX = this._counters[i].x;
+            if (x < statX)
+                break;
+        }
+        i--;
+        this._domGroups._value.textContent = this._counters[i].domGroupCount;
+        this._domNodes._value.textContent = this._counters[i].nodeCount;
+        this._listeners._value.textContent = this._counters[i].listenerCount;
+    },
+
+    visible: function()
+    {
+        return this._memorySplitView.isShowing();
+    },
+
+    show: function()
+    {
+        var anchor = /** @type {Element|null} */ this._containerAnchor.nextSibling;
+        this._memorySplitView.show(this._timelinePanel.element, anchor);
+        this._updateSize();
+        setTimeout(this._draw.bind(this), 0);
+    },
+
+    refresh: function()
+    {
+        this._updateSize();
+        this._draw();
+        this._refreshCurrentValues(this._memoryMarker.offsetLeft);
+    },
+
+    hide: function()
+    {
+        this._memorySplitView.detach();
+    },
+
+    _setVerticalClip: function(originY, height)
+    {
+        this._originY = originY;
+        this._clippedHeight = height;
+    },
+
+    _calculateXValues: function()
+    {
+        if (!this._counters.length)
+            return;
+
+        var minTime = this._counters[this._minimumIndex].time;
+        var maxTime = this._counters[this._maximumIndex].time;
+
+        var width = this._canvas.width;
+        var xFactor = width / (maxTime - minTime);
+
+        this._counters[this._minimumIndex].x = 0;
+        for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++)
+             this._counters[i].x = xFactor * (this._counters[i].time - minTime);
+        this._counters[this._maximumIndex].x = width;
+    },
+
+    _drawPolyline: function(valueGetter, color)
+    {
+        var canvas = this._canvas;
+        var ctx = canvas.getContext("2d");
+        var width = canvas.width;
+        var height = this._clippedHeight;
+        var originY = this._originY;
+
+        // Draw originalValue level
+        ctx.beginPath();
+        ctx.moveTo(0, originY + height / 2 + 0.5);
+        ctx.lineTo(width, originY + height / 2 + 0.5);
+        ctx.lineWidth = 0.1;
+        ctx.strokeStyle = "rgb(100, 100, 100)";
+        ctx.stroke();
+        ctx.closePath();
+
+        if (!this._counters.length)
+            return;
+
+        var maxValue;
+        var minValue;
+        for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+            var value = valueGetter(this._counters[i]);
+            if (minValue === undefined || value < minValue)
+                minValue = value;
+            if (maxValue === undefined || value > maxValue)
+                maxValue = value;
+        }
+
+        var originalValue = valueGetter(this._counters[this._minimumIndex]);
+
+        var yFactor = height / (2 * Math.max(maxValue - originalValue, originalValue - minValue));
+
+        ctx.beginPath();
+        ctx.moveTo(0, originY + height / 2);
+        for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+             var x = this._counters[i].x;
+             var y = originY + (height / 2 - (valueGetter(this._counters[i])- originalValue) * yFactor);
+             ctx.lineTo(x, y);
+        }
+        ctx.lineTo(width, originY + (height / 2 - (valueGetter(this._counters[this._maximumIndex]) - originalValue) * yFactor));
+        ctx.lineWidth = 1;
+        ctx.strokeStyle = color;
+        ctx.stroke();
+        ctx.closePath();
+    },
+
+    _drawBottomBound: function(color)
+    {
+        var canvas = this._canvas;
+        var width = canvas.width;
+        var y = this._originY + this._clippedHeight + 1.5;
+
+        var ctx = canvas.getContext("2d");
+        ctx.beginPath();
+        ctx.moveTo(0, y);
+        ctx.lineTo(width, y);
+        ctx.lineWidth = 0.5;
+        ctx.strokeStyle = color;
+        ctx.stroke();
+        ctx.closePath();
+    },
+
+    _clear: function() {
+        var ctx = this._canvas.getContext("2d");
+        ctx.fillStyle = "rgb(255,255,255)";
+        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+        ctx.fill();
+    }
+}
+
Property changes on: trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js
___________________________________________________________________

Added: svn:eol-style

Modified: trunk/Source/WebCore/inspector/front-end/Settings.js (105876 => 105877)


--- trunk/Source/WebCore/inspector/front-end/Settings.js	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/front-end/Settings.js	2012-01-25 15:10:31 UTC (rev 105877)
@@ -171,6 +171,7 @@
     this.useScriptsNavigator = this._createExperiment("useScriptsNavigator", "Use file navigator and tabbed editor container in scripts panel");
     this.sourceFrameAlwaysEditable = this._createExperiment("sourceFrameAlwaysEditable", "Make resources always editable");
     this.freeFlowDOMEditing = this._createExperiment("freeFlowDOMEditing", "Enable free flow DOM editing");
+    this.showMemoryCounters = this._createExperiment("showMemoryCounters", "Show memory counters in Timeline panel");
 
     this._cleanUpSetting();
 }

Modified: trunk/Source/WebCore/inspector/front-end/TimelinePanel.js (105876 => 105877)


--- trunk/Source/WebCore/inspector/front-end/TimelinePanel.js	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/front-end/TimelinePanel.js	2012-01-25 15:10:31 UTC (rev 105877)
@@ -50,6 +50,14 @@
     this._containerElement.id = "timeline-container";
     this._containerElement.addEventListener("scroll", this._onScroll.bind(this), false);
 
+    if (WebInspector.experimentsSettings.showMemoryCounters.isEnabled()) {
+        this._timelineMemorySplitter = this.element.createChild("div");
+        this._timelineMemorySplitter.id = "timeline-memory-splitter";
+        this._timelineMemorySplitter.addEventListener("mousedown", this._startSplitterDragging.bind(this), false);
+        this._timelineMemorySplitter.addStyleClass("hidden");
+        this._memoryStatistics = new WebInspector.MemoryStatistics(this, this.splitView.preferredSidebarWidth());
+    }
+
     var itemsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RECORDS"), {}, true);
     this.sidebarTree.appendChild(itemsTreeElement);
 
@@ -119,6 +127,47 @@
 WebInspector.TimelinePanel.shortRecordThreshold = 0.015;
 
 WebInspector.TimelinePanel.prototype = {
+    /**
+     * @param {Event} event
+     */
+    _startSplitterDragging: function(event)
+    {
+        this._dragOffset = this._timelineMemorySplitter.offsetTop + 2 - event.pageY;
+        WebInspector.elementDragStart(this._timelineMemorySplitter, this._splitterDragging.bind(this), this._endSplitterDragging.bind(this), event, "ns-resize");
+    },
+
+    /**
+     * @param {Event} event
+     */
+    _splitterDragging: function(event)
+    {
+        var top = event.pageY + this._dragOffset
+        this._setSplitterPosition(top);
+        event.preventDefault();
+    },
+
+    /**
+     * @param {Event} event
+     */
+    _endSplitterDragging: function(event)
+    {
+        delete this._dragOffset;
+        WebInspector.elementDragEnd(event);
+        if (this._memoryStatistics)
+            this._memoryStatistics.show();
+    },
+
+    _setSplitterPosition: function(top)
+    {
+        const overviewHeight = 90;
+        const sectionMinHeight = 100;
+        top = Number.constrain(top, overviewHeight + sectionMinHeight, this.element.offsetHeight - sectionMinHeight);
+
+        this.splitView.element.style.height = (top - overviewHeight) + "px";
+        this._timelineMemorySplitter.style.top = (top - 2) + "px";
+        this._memoryStatistics.setTopPosition(top);
+    },
+
     _linkifyLocation: function(url, lineNumber, columnNumber)
     {
         // FIXME(62725): stack trace line/column numbers are one-based.
@@ -165,6 +214,11 @@
         return topPaneElement;
     },
 
+    get calculator()
+    {
+        return this._calculator;
+    },
+
     get toolbarItemLabel()
     {
         return WebInspector.UIString("Timeline");
@@ -172,7 +226,11 @@
 
     get statusBarItems()
     {
-        return [this.toggleFilterButton.element, this.toggleTimelineButton.element, this.garbageCollectButton.element, this.clearButton.element, this._overviewPane.statusBarFilters];
+        var result = [this.toggleFilterButton.element, this.toggleTimelineButton.element, this.garbageCollectButton.element, this.clearButton.element];
+        if (this._memoryStatisticsButton)
+            result.push(this._memoryStatisticsButton.element);
+        result.push(this._overviewPane.statusBarFilters);
+        return result;
     },
 
     get categories()
@@ -240,6 +298,11 @@
         this.garbageCollectButton = new WebInspector.StatusBarButton(WebInspector.UIString("Collect Garbage"), "garbage-collect-status-bar-item");
         this.garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
 
+        if (WebInspector.experimentsSettings.showMemoryCounters.isEnabled()) {
+            this._memoryStatisticsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Toggle DOM counters graphs"), "dom-counters-status-bar-item");
+            this._memoryStatisticsButton.addEventListener("click", this._toggleMemoryStatistics, this);
+        }
+
         this.recordsCounter = document.createElement("span");
         this.recordsCounter.className = "timeline-records-counter";
     },
@@ -379,10 +442,30 @@
         ProfilerAgent.collectGarbage();
     },
 
+    _toggleMemoryStatistics: function()
+    {
+        if (this._memoryStatistics.visible()) {
+            this._timelineMemorySplitter.addStyleClass("hidden");
+            this._memoryStatistics.hide();
+            this.splitView.element.style.height = "auto";
+            this.splitView.element.style.bottom = "0";
+            this.onResize();
+        } else {
+            this._timelineMemorySplitter.removeStyleClass("hidden");
+            this._memoryStatistics.show();
+            this.splitView.element.style.bottom = "auto";
+            this._setSplitterPosition(600);
+        }
+    },
+
     _onTimelineEventRecorded: function(event)
     {
-        if (this.toggleTimelineButton.toggled)
+        if (this.toggleTimelineButton.toggled) {
             this._addRecordToTimeline(event.data);
+
+            if (this._memoryStatistics && event.data["domGroups"])
+                this._memoryStatistics.addTimlineEvent(event);
+        }
     },
 
     _addRecordToTimeline: function(record)
@@ -493,6 +576,8 @@
         this._topPaneSidebarElement.style.width = width + "px";
         this._scheduleRefresh(false);
         this._overviewPane.sidebarResized(width);
+        if (this._memoryStatistics)
+            this._memoryStatistics.setSidebarWidth(width);
     },
 
     onResize: function()
@@ -585,10 +670,13 @@
         }
 
         this._overviewPane.update(this._rootRecord.children, this._calculator._showShortEvents);
+
         this._refreshRecords(!this._boundariesAreValid);
         this._updateRecordsCounter();
         if(!this._boundariesAreValid)
             this._updateEventDividers();
+        if (this._memoryStatistics && this._memoryStatistics.visible())
+            this._memoryStatistics.refresh();
         this._boundariesAreValid = true;
     },
 

Modified: trunk/Source/WebCore/inspector/front-end/WebKit.qrc (105876 => 105877)


--- trunk/Source/WebCore/inspector/front-end/WebKit.qrc	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/front-end/WebKit.qrc	2012-01-25 15:10:31 UTC (rev 105877)
@@ -78,6 +78,7 @@
     <file>_javascript_Formatter.js</file>
     <file>_javascript_SourceFrame.js</file>
     <file>KeyboardShortcut.js</file>
+    <file>MemoryStatistics.js</file>
     <file>MetricsSidebarPane.js</file>
     <file>NetworkItemView.js</file>
     <file>NetworkLog.js</file>

Modified: trunk/Source/WebCore/inspector/front-end/inspector.html (105876 => 105877)


--- trunk/Source/WebCore/inspector/front-end/inspector.html	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/front-end/inspector.html	2012-01-25 15:10:31 UTC (rev 105877)
@@ -191,6 +191,7 @@
     <script type="text/_javascript_" src=""
     <script type="text/_javascript_" src=""
     <script type="text/_javascript_" src=""
+    <script type="text/_javascript_" src=""
 </head>
 <body class="detached" id="-webkit-web-inspector">
     <div id="toolbar">

Modified: trunk/Source/WebCore/inspector/front-end/timelinePanel.css (105876 => 105877)


--- trunk/Source/WebCore/inspector/front-end/timelinePanel.css	2012-01-25 15:03:01 UTC (rev 105876)
+++ trunk/Source/WebCore/inspector/front-end/timelinePanel.css	2012-01-25 15:10:31 UTC (rev 105877)
@@ -502,3 +502,43 @@
     color: rgb(50%, 50%, 50%);
     white-space: nowrap;
 }
+
+#timeline-memory-splitter {
+    position: absolute;
+    z-index: 5;
+    left: 0;
+    right: 0;
+    height: 5px;
+    cursor: ns-resize;
+}
+
+#memory-counters-graph {
+    overflow: hidden;
+}
+
+#memory-graphs-container {
+    border-top: 1px solid #AAA;
+}
+
+#memory-graphs-container .split-view-contents {
+    overflow: hidden;
+}
+
+.timeline-marker {
+    position: absolute;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    border-left: 1px solid #AAA;
+}
+
+.memory-counter-sidebar-info {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+}
+
+.memory-counter-sidebar-info.bottom-border-visible {
+    border-bottom: 1px solid #AAA;
+}
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to