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;
+}