blob: d00fca943961c636e5725c25ac3b290f549d113e [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2015 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="import" href="/tracing/model/memory_allocator_dump.html">
<link rel="import" href="/tracing/ui/tracks/chart_axis.html">
<link rel="import" href="/tracing/ui/tracks/chart_point.html">
<link rel="import" href="/tracing/ui/tracks/chart_series.html">
<link rel="import" href="/tracing/ui/tracks/chart_track.html">
<link rel="import" href="/tracing/ui/tracks/container_track.html">
<link rel="import" href="/tracing/ui/tracks/letter_dot_track.html">
<script>
'use strict';
tr.exportTo('tr.ui.tracks', function() {
var ColorScheme = tr.b.ColorScheme;
var DISPLAYED_SIZE_NUMERIC_NAME =
tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;
/**
* Add numeric values from a source dictionary to the numeric values in
* a destination dictionary. Undefined values are treated as zeros. Note that
* this method modifies the destination dictionary in place.
*
* Example: addDictionary({a: 1, b: 2}, {b: 3, c: 4}) will update the
* destination dictionary (first argument) to {a: 1, b: 5, c: 4}.
*/
function addDictionary(dstDict, srcDict) {
tr.b.iterItems(srcDict, function(key, value) {
var existingValue = dstDict[key];
if (existingValue === undefined)
existingValue = 0;
dstDict[key] = existingValue + value;
});
}
/**
* Get a dictionary mapping root allocator names (e.g. 'v8') to the
* corresponding sizes (e.g. 1024) in a process memory dump.
*/
function getProcessMemoryDumpAllocatorSizes(processMemoryDump) {
var allocatorDumps = processMemoryDump.memoryAllocatorDumps;
if (allocatorDumps === undefined)
return {};
var allocatorSizes = {};
allocatorDumps.forEach(function(allocatorDump) {
// Don't show tracing overhead in the charts.
// TODO(petrcermak): Find a less hacky way to do this.
if (allocatorDump.fullName === 'tracing')
return;
var allocatorSize = allocatorDump.numerics[DISPLAYED_SIZE_NUMERIC_NAME];
if (allocatorSize === undefined)
return;
var allocatorSizeValue = allocatorSize.value;
if (allocatorSizeValue === undefined)
return;
allocatorSizes[allocatorDump.fullName] = allocatorSizeValue;
});
return allocatorSizes;
};
/**
* Get a dictionary mapping root allocator names (e.g. 'v8') to the
* corresponding sizes (e.g. 1024) in a global memory dump (i.e. summed over
* all simultaneous process memory dumps).
*/
function getGlobalMemoryDumpAllocatorSizes(globalMemoryDump) {
var globalAllocatorSizes = {};
tr.b.iterItems(globalMemoryDump.processMemoryDumps,
function(pid, processMemoryDump) {
addDictionary(globalAllocatorSizes,
getProcessMemoryDumpAllocatorSizes(processMemoryDump));
});
return globalAllocatorSizes;
}
/**
* A generic function which converts a list of memory dumps to a list of chart
* series (one per root allocator). Each series represents the evolution of
* the size of a the corresponding root allocator (e.g. 'v8') over time.
*/
function buildAllocatedMemoryChartSeries(memoryDumps,
memoryDumpToAllocatorSizesFn) {
var allocatorNameToPoints = {};
var dumpsData = memoryDumps.map(function(memoryDump) {
var allocatorSizes = memoryDumpToAllocatorSizesFn(memoryDump);
tr.b.iterItems(allocatorSizes, function(allocatorName) {
allocatorNameToPoints[allocatorName] = [];
});
return {dump: memoryDump, sizes: allocatorSizes};
});
// Do not generate any chart series if no process memory dump contains any
// allocator dumps.
if (Object.keys(allocatorNameToPoints).length === 0)
return undefined;
dumpsData.forEach(function(dumpData) {
var memoryDump = dumpData.dump;
var allocatorSizes = dumpData.sizes;
tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) {
var allocatorSize = allocatorSizes[allocatorName] || 0;
points.push(new tr.ui.tracks.ChartPoint(
memoryDump, memoryDump.start, allocatorSize));
});
});
// Create one common axis for all allocated memory chart series.
var axis = new tr.ui.tracks.ChartAxis(0);
// Build a chart series for each allocator.
var series = [];
tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) {
var colorId = ColorScheme.getColorIdForGeneralPurposeString(
allocatorName);
var renderingConfig = {
chartType: tr.ui.tracks.ChartSeriesType.LINE,
colorId: colorId
};
series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig));
});
return series;
}
/**
* Transform a list of memory dumps to a list of letter dots (with letter 'M'
* inside).
*/
function buildMemoryLetterDots(memoryDumps) {
var lightMemoryColorId =
ColorScheme.getColorIdForReservedName('light_memory_dump');
var detailedMemoryColorId =
ColorScheme.getColorIdForReservedName('detailed_memory_dump');
return memoryDumps.map(function(memoryDump) {
var memoryColorId;
switch (memoryDump.levelOfDetail) {
case 'detailed':
memoryColorId = detailedMemoryColorId;
break;
case 'light':
default:
memoryColorId = lightMemoryColorId;
}
return new tr.ui.tracks.LetterDot(
memoryDump, 'M', memoryColorId, memoryDump.start);
});
}
/**
* Convert a list of global memory dumps to a list of chart series (one per
* process). Each series represents the evolution of the memory used by the
* process over time.
*/
function buildGlobalUsedMemoryChartSeries(globalMemoryDumps) {
// Do not generate the chart if no process memory dump contains VM regions.
var containsVmRegions = globalMemoryDumps.some(function(globalDump) {
for (var pid in globalDump.processMemoryDumps)
if (globalDump.processMemoryDumps[pid].mostRecentVmRegions)
return true;
return false;
});
if (!containsVmRegions)
return undefined;
// Find all processes that dump memory at least once.
var pidToProcess = {};
globalMemoryDumps.forEach(function(globalDump) {
tr.b.iterItems(globalDump.processMemoryDumps, function(pid, processDump) {
pidToProcess[pid] = processDump.process;
});
});
// Build one list of points for each instrumented process.
var pidToPoints = {};
tr.b.iterItems(pidToProcess, function(pid, process) {
pidToPoints[pid] = [];
});
// For every timestamp, calculate the total PSS (proportional set size) of
// each process and append it to the corresponding list of points.
globalMemoryDumps.forEach(function(globalDump) {
var pssBase = 0;
tr.b.iterItems(pidToPoints, function(pid, points) {
var processMemoryDump = globalDump.processMemoryDumps[pid];
var cumulativePss = pssBase;
// If no dump was found (probably dead) or it does not provide the
// necessary information (namely most recent VM regions), assume zero.
if (processMemoryDump !== undefined) {
var vmRegions = processMemoryDump.mostRecentVmRegions;
if (vmRegions !== undefined)
cumulativePss += vmRegions.byteStats.proportionalResident || 0;
}
points.push(new tr.ui.tracks.ChartPoint(
globalDump, globalDump.start, cumulativePss, pssBase));
pssBase = cumulativePss;
});
});
// Create one common axis for all used memory chart series.
var axis = new tr.ui.tracks.ChartAxis(0);
// Build a chart series for each instrumented process.
var series = [];
tr.b.iterItems(pidToPoints, function(pid, points) {
var process = pidToProcess[pid];
var colorId = ColorScheme.getColorIdForGeneralPurposeString(
process.userFriendlyName);
var renderingConfig = {
chartType: tr.ui.tracks.ChartSeriesType.AREA,
colorId: colorId,
backgroundOpacity: 0.8
};
series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig));
});
// Show the first series (with the smallest cumulative value) at the top.
series.reverse();
return series;
}
/**
* Convert a list of process memory dumps to a list of chart series (one per
* root allocator). Each series represents the evolution of the size of a the
* corresponding root allocator (e.g. 'v8') over time.
*/
function buildProcessAllocatedMemoryChartSeries(processMemoryDumps) {
return buildAllocatedMemoryChartSeries(processMemoryDumps,
getProcessMemoryDumpAllocatorSizes);
}
/**
* Convert a list of global memory dumps to a list of chart series (one per
* root allocator). Each series represents the evolution of the size of a the
* corresponding root allocator (e.g. 'v8') over time.
*/
function buildGlobalAllocatedMemoryChartSeries(globalMemoryDumps) {
return buildAllocatedMemoryChartSeries(globalMemoryDumps,
getGlobalMemoryDumpAllocatorSizes);
}
return {
buildMemoryLetterDots:
buildMemoryLetterDots,
buildGlobalUsedMemoryChartSeries:
buildGlobalUsedMemoryChartSeries,
buildProcessAllocatedMemoryChartSeries:
buildProcessAllocatedMemoryChartSeries,
buildGlobalAllocatedMemoryChartSeries:
buildGlobalAllocatedMemoryChartSeries
};
});
</script>