blob: 08ae1ec9f6d0c755191ef87802b5a2ff95073033 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="stylesheet" href="/ui/extras/tcmalloc/heap_instance_track.css">
<link rel="import" href="/base/sorted_array_utils.html">
<link rel="import" href="/ui/tracks/stacked_bars_track.html">
<link rel="import" href="/ui/tracks/object_instance_track.html">
<link rel="import" href="/ui/base/event_presenter.html">
<link rel="import" href="/ui/base/ui.html">
<script>
'use strict';
tr.exportTo('tr.ui.e.tcmalloc', function() {
var EventPresenter = tr.ui.b.EventPresenter;
/**
* A track that displays heap memory data.
* @constructor
* @extends {StackedBarsTrack}
*/
var HeapInstanceTrack = tr.ui.b.define(
'tr-ui-e-tcmalloc-heap-instance-track', tr.ui.tracks.StackedBarsTrack);
HeapInstanceTrack.prototype = {
__proto__: tr.ui.tracks.StackedBarsTrack.prototype,
decorate: function(viewport) {
tr.ui.tracks.StackedBarsTrack.prototype.decorate.call(this, viewport);
this.classList.add('tr-ui-e-tcmalloc-heap-instance-track');
this.objectInstance_ = null;
},
set objectInstances(objectInstances) {
if (!objectInstances) {
this.objectInstance_ = [];
return;
}
if (objectInstances.length != 1)
throw new Error('Bad object instance count.');
this.objectInstance_ = objectInstances[0];
this.maxBytes_ = this.computeMaxBytes_(
this.objectInstance_.snapshots);
},
computeMaxBytes_: function(snapshots) {
var maxBytes = 0;
for (var i = 0; i < snapshots.length; i++) {
var snapshot = snapshots[i];
// Sum all the current allocations in this snapshot.
var traceNames = Object.keys(snapshot.heap_.children);
var sumBytes = 0;
for (var j = 0; j < traceNames.length; j++) {
sumBytes += snapshot.heap_.children[traceNames[j]].currentBytes;
}
// Keep track of the maximum across all snapshots.
if (sumBytes > maxBytes)
maxBytes = sumBytes;
}
return maxBytes;
},
get height() {
return window.getComputedStyle(this).height;
},
set height(height) {
this.style.height = height;
},
draw: function(type, viewLWorld, viewRWorld) {
switch (type) {
case tr.ui.tracks.DrawType.GENERAL_EVENT:
this.drawEvents_(viewLWorld, viewRWorld);
break;
}
},
drawEvents_: function(viewLWorld, viewRWorld) {
var ctx = this.context();
var pixelRatio = window.devicePixelRatio || 1;
var bounds = this.getBoundingClientRect();
var width = bounds.width * pixelRatio;
var height = bounds.height * pixelRatio;
// Culling parameters.
var dt = this.viewport.currentDisplayTransform;
// Scale by the size of the largest snapshot.
var maxBytes = this.maxBytes_;
var objectSnapshots = this.objectInstance_.snapshots;
var lowIndex = tr.b.findLowIndexInSortedArray(
objectSnapshots,
function(snapshot) {
return snapshot.ts;
},
viewLWorld);
// Assure that the stack with the left edge off screen still gets drawn
if (lowIndex > 0)
lowIndex -= 1;
for (var i = lowIndex; i < objectSnapshots.length; ++i) {
var snapshot = objectSnapshots[i];
var left = snapshot.ts;
if (left > viewRWorld)
break;
var leftView = dt.xWorldToView(left);
if (leftView < 0)
leftView = 0;
// Compute the edges for the column graph bar.
var right;
if (i != objectSnapshots.length - 1) {
right = objectSnapshots[i + 1].ts;
} else {
// If this is the last snaphot of multiple snapshots, use the width of
// the previous snapshot for the width.
if (objectSnapshots.length > 1)
right = objectSnapshots[i].ts + (objectSnapshots[i].ts -
objectSnapshots[i - 1].ts);
else
// If there's only one snapshot, use max bounds as the width.
right = this.objectInstance_.parent.model.bounds.max;
}
var rightView = dt.xWorldToView(right);
if (rightView > width)
rightView = width;
// Floor the bounds to avoid a small gap between stacks.
leftView = Math.floor(leftView);
rightView = Math.floor(rightView);
// Draw a stacked bar graph. Largest item is stored first in the
// heap data structure, so iterate backwards. Likewise draw from
// the bottom of the bar upwards.
var currentY = height;
var keys = Object.keys(snapshot.heap_.children);
for (var k = keys.length - 1; k >= 0; k--) {
var trace = snapshot.heap_.children[keys[k]];
if (this.objectInstance_.selectedTraces &&
this.objectInstance_.selectedTraces.length > 0 &&
this.objectInstance_.selectedTraces[0] == keys[k]) {
// A trace selected in the analysis view is bright yellow.
ctx.fillStyle = 'rgb(239, 248, 206)';
} else
ctx.fillStyle = EventPresenter.getBarSnapshotColor(snapshot, k);
var barHeight = height * trace.currentBytes / maxBytes;
ctx.fillRect(leftView, currentY - barHeight,
Math.max(rightView - leftView, 1), barHeight);
currentY -= barHeight;
}
}
ctx.lineWidth = 1;
}
};
tr.ui.tracks.ObjectInstanceTrack.register(
HeapInstanceTrack,
{typeName: 'memory::Heap'});
return {
HeapInstanceTrack: HeapInstanceTrack
};
});
</script>