NativeMemoryGraph.js [plain text]
WebInspector.NativeMemoryGraph = function(timelinePanel, model, sidebarWidth)
{
WebInspector.MemoryStatistics.call(this, timelinePanel, model, sidebarWidth);
}
WebInspector.NativeMemoryGraph.Counter = function(time, nativeCounters)
{
WebInspector.MemoryStatistics.Counter.call(this, time);
this.nativeCounters = nativeCounters;
}
WebInspector.NativeMemoryCounterUI = function(memoryCountersPane, title, hsl, valueGetter)
{
var swatchColor = this._hslToString(hsl);
WebInspector.CounterUIBase.call(this, memoryCountersPane, title, swatchColor, valueGetter);
this._value = this._swatch.element.createChild("span", "memory-category-value");
const borderLightnessDifference = 3;
hsl[2] -= borderLightnessDifference;
this.strokeColor = this._hslToString(hsl);
this.graphYValues = [];
}
WebInspector.NativeMemoryCounterUI.prototype = {
_hslToString: function(hsl)
{
return "hsl(" + hsl[0] + "," + hsl[1] + "%," + hsl[2] + "%)";
},
updateCurrentValue: function(countersEntry)
{
var bytes = this.valueGetter(countersEntry);
var megabytes = bytes / (1024 * 1024);
this._value.textContent = WebInspector.UIString("%.1f\u2009MB", megabytes);
},
clearCurrentValueAndMarker: function(ctx)
{
this._value.textContent = "";
},
__proto__: WebInspector.CounterUIBase.prototype
}
WebInspector.NativeMemoryGraph.prototype = {
_createCurrentValuesBar: function()
{
},
_createCounterUIList: function()
{
var nativeCounters = [
"JSExternalResources",
"CSS",
"GlyphCache",
"Image",
"Resources",
"DOM",
"Rendering",
"Audio",
"WebInspector",
"JSHeap.Used",
"JSHeap.Unused",
"MallocWaste",
"Other",
"PrivateBytes",
];
function getCounterValue(name, entry)
{
return (entry.nativeCounters && entry.nativeCounters[name]) || 0;
}
var list = [];
for (var i = nativeCounters.length - 1; i >= 0; i--) {
var name = nativeCounters[i];
if ("PrivateBytes" === name) {
var counterUI = new WebInspector.NativeMemoryCounterUI(this, "Total", [0, 0, 0], getCounterValue.bind(this, name))
this._privateBytesCounter = counterUI;
} else {
var counterUI = new WebInspector.NativeMemoryCounterUI(this, name, [i * 20, 65, 63], getCounterValue.bind(this, name))
list.push(counterUI);
}
}
return list.reverse();
},
_canvasHeight: function()
{
return this._canvasContainer.offsetHeight;
},
_onRecordAdded: function(event)
{
var statistics = this._counters;
function addStatistics(record)
{
var nativeCounters = record["nativeHeapStatistics"];
if (!nativeCounters)
return;
var knownSize = 0;
for (var name in nativeCounters) {
if (name === "PrivateBytes")
continue;
knownSize += nativeCounters[name];
}
nativeCounters["Other"] = nativeCounters["PrivateBytes"] - knownSize;
statistics.push(new WebInspector.NativeMemoryGraph.Counter(
record.endTime || record.startTime,
nativeCounters
));
}
WebInspector.TimelinePresentationModel.forAllRecords([event.data], null, addStatistics);
},
_draw: function()
{
WebInspector.MemoryStatistics.prototype._draw.call(this);
var maxValue = this._maxCounterValue();
this._resetTotalValues();
var previousCounterUI;
for (var i = 0; i < this._counterUI.length; i++) {
this._drawGraph(this._counterUI[i], previousCounterUI, maxValue);
if (this._counterUI[i].visible)
previousCounterUI = this._counterUI[i];
}
},
_clearCurrentValueAndMarker: function(ctx)
{
WebInspector.MemoryStatistics.prototype._clearCurrentValueAndMarker.call(this, ctx);
this._privateBytesCounter.clearCurrentValueAndMarker(ctx);
},
_updateCurrentValue: function(counterEntry)
{
WebInspector.MemoryStatistics.prototype._updateCurrentValue.call(this, counterEntry);
this._privateBytesCounter.updateCurrentValue(counterEntry);
},
_restoreImageUnderMarker: function(ctx)
{
if (this._imageUnderMarker)
ctx.putImageData(this._imageUnderMarker.imageData, this._imageUnderMarker.x, this._imageUnderMarker.y);
this._discardImageUnderMarker();
},
_saveImageUnderMarker: function(ctx, left, top, right, bottom)
{
var imageData = ctx.getImageData(left, top, right, bottom);
this._imageUnderMarker = {
x: left,
y: top,
imageData: imageData
};
},
_drawMarker: function(ctx, x, index)
{
var left = this._counters[index].x;
var right = index + 1 < this._counters.length ? this._counters[index + 1].x : left;
var top = this._originY;
top = 0;
var bottom = top + this._clippedHeight;
bottom += this._originY;
this._saveImageUnderMarker(ctx, left, top, right, bottom);
ctx.beginPath();
ctx.moveTo(left, top);
ctx.lineTo(right, top);
ctx.lineTo(right, bottom);
ctx.lineTo(left, bottom);
ctx.lineWidth = 1;
ctx.closePath();
ctx.fillStyle = "rgba(220,220,220,0.3)";
ctx.fill();
},
_maxCounterValue: function()
{
if (!this._counters.length)
return 0;
var valueGetter = this._privateBytesCounter.valueGetter;
var result = 0;
for (var i = this._minimumIndex; i < this._maximumIndex; i++) {
var counter = this._counters[i];
var value = valueGetter(counter);
if (value > result)
result = value;
}
return result;
},
_resetTotalValues: function()
{
for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
var counter = this._counters[i];
counter.total = 0;
}
},
_drawGraph: function(counterUI, previousCounterUI, maxTotalValue)
{
var canvas = this._canvas;
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = this._clippedHeight;
var originY = this._originY;
var valueGetter = counterUI.valueGetter;
if (!this._counters.length)
return;
if (!counterUI.visible)
return;
for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
var counter = this._counters[i];
var value = valueGetter(counter);
counter.total += value;
}
var yValues = counterUI.graphYValues;
yValues.length = this._counters.length;
var maxYRange = maxTotalValue;
var yFactor = maxYRange ? height / (maxYRange) : 1;
ctx.beginPath();
if (previousCounterUI) {
var prevYValues = previousCounterUI.graphYValues;
var currentY = prevYValues[this._maximumIndex];
ctx.moveTo(width, currentY);
var currentX = width;
for (var i = this._maximumIndex - 1; i >= this._minimumIndex; i--) {
currentY = prevYValues[i];
currentX = this._counters[i].x;
ctx.lineTo(currentX, currentY);
}
} else {
var lastY = originY + height;
ctx.moveTo(width, lastY);
ctx.lineTo(0, lastY);
}
var currentY = originY + (height - this._counters[this._minimumIndex].total * yFactor);
ctx.lineTo(0, currentY);
for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
var counter = this._counters[i];
var x = counter.x;
currentY = originY + (height - counter.total * yFactor);
ctx.lineTo(x, currentY);
yValues[i] = currentY;
}
ctx.lineTo(width, currentY);
ctx.closePath();
ctx.lineWidth = 1;
ctx.strokeStyle = counterUI.strokeColor;
ctx.fillStyle = counterUI.graphColor;
ctx.fill();
ctx.stroke();
},
_discardImageUnderMarker: function()
{
delete this._imageUnderMarker;
},
__proto__: WebInspector.MemoryStatistics.prototype
}