1<!DOCTYPE html> 2<!-- 3Copyright (c) 2015 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/base/iteration_helpers.html"> 9<link rel="import" href="/tracing/value/numeric.html"> 10<link rel="import" href="/tracing/value/unit.html"> 11 12<script> 13'use strict'; 14 15/** 16 * @fileoverview Provides the MemoryAllocatorDump class. 17 */ 18tr.exportTo('tr.model', function() { 19 /** 20 * @constructor 21 */ 22 function MemoryAllocatorDump(containerMemoryDump, fullName, opt_guid) { 23 this.fullName = fullName; 24 this.parent = undefined; 25 this.children = []; 26 27 // String -> ScalarNumeric. 28 this.numerics = {}; 29 30 // String -> string. 31 this.diagnostics = {}; 32 33 // The associated container memory dump. 34 this.containerMemoryDump = containerMemoryDump; 35 36 // Ownership relationship between memory allocator dumps. 37 this.owns = undefined; 38 this.ownedBy = []; 39 40 // Map from sibling dumps (other children of this dump's parent) to the 41 // proportion of this dump's size which they (or their descendants) own. 42 this.ownedBySiblingSizes = new Map(); 43 44 // Retention relationship between memory allocator dumps. 45 this.retains = []; 46 this.retainedBy = []; 47 48 // Weak memory allocator dumps are removed from the model after import in 49 // tr.model.GlobalMemoryDump.removeWeakDumps(). See 50 // base::trace_event::MemoryAllocatorDump::Flags::WEAK in the Chromium 51 // codebase. 52 this.weak = false; 53 54 // A list of information about the memory allocator dump (e.g. about how 55 // its fields were calculated). Each item should be an object with 56 // a mandatory 'type' property and type-specific extra arguments (see 57 // MemoryAllocatorDumpInfoType). 58 this.infos = []; 59 60 // For debugging purposes. 61 this.guid = opt_guid; 62 }; 63 64 /** 65 * Size numeric names. Please refer to the Memory Dump Graph Metric 66 * Calculation design document for more details (https://goo.gl/fKg0dt). 67 */ 68 MemoryAllocatorDump.SIZE_NUMERIC_NAME = 'size'; 69 MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME = 'effective_size'; 70 MemoryAllocatorDump.RESIDENT_SIZE_NUMERIC_NAME = 'resident_size'; 71 MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME = 72 MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME; 73 74 MemoryAllocatorDump.prototype = { 75 get name() { 76 return this.fullName.substring(this.fullName.lastIndexOf('/') + 1); 77 }, 78 79 get quantifiedName() { 80 return '\'' + this.fullName + '\' in ' + 81 this.containerMemoryDump.containerName; 82 }, 83 84 isDescendantOf: function(otherDump) { 85 var dump = this; 86 while (dump !== undefined) { 87 if (dump === otherDump) 88 return true; 89 dump = dump.parent; 90 } 91 return false; 92 }, 93 94 addNumeric: function(name, numeric) { 95 if (!(numeric instanceof tr.v.ScalarNumeric)) 96 throw new Error('Numeric value must be an instance of ScalarNumeric.'); 97 if (name in this.numerics) 98 throw new Error('Duplicate numeric name: ' + name + '.'); 99 this.numerics[name] = numeric; 100 }, 101 102 addDiagnostic: function(name, text) { 103 if (typeof text !== 'string') 104 throw new Error('Diagnostic text must be a string.'); 105 if (name in this.diagnostics) 106 throw new Error('Duplicate diagnostic name: ' + name + '.'); 107 this.diagnostics[name] = text; 108 }, 109 110 aggregateNumericsRecursively: function(opt_model) { 111 var numericNames = new Set(); 112 113 // Aggregate descendants's numerics recursively and gather children's 114 // numeric names. 115 this.children.forEach(function(child) { 116 child.aggregateNumericsRecursively(opt_model); 117 tr.b.iterItems(child.numerics, numericNames.add, numericNames); 118 }, this); 119 120 // Aggregate children's numerics. 121 numericNames.forEach(function(numericName) { 122 if (numericName === MemoryAllocatorDump.SIZE_NUMERIC_NAME || 123 numericName === MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME || 124 this.numerics[numericName] !== undefined) { 125 // Don't aggregate size and effective size numerics. These are 126 // calculated in GlobalMemoryDump.prototype.calculateSizes() and 127 // GlobalMemoryDump.prototype.calculateEffectiveSizes respectively. 128 // Also don't aggregate numerics that the parent already has. 129 return; 130 } 131 132 this.numerics[numericName] = MemoryAllocatorDump.aggregateNumerics( 133 this.children.map(function(child) { 134 return child.numerics[numericName]; 135 }), opt_model); 136 }, this); 137 } 138 }; 139 140 // TODO(petrcermak): Consider moving this to tr.v.Numeric. 141 MemoryAllocatorDump.aggregateNumerics = function(numerics, opt_model) { 142 var shouldLogWarning = !!opt_model; 143 var aggregatedUnit = undefined; 144 var aggregatedValue = 0; 145 146 // Aggregate the units and sum up the values of the numerics. 147 numerics.forEach(function(numeric) { 148 if (numeric === undefined) 149 return; 150 151 var unit = numeric.unit; 152 if (aggregatedUnit === undefined) { 153 aggregatedUnit = unit; 154 } else if (aggregatedUnit !== unit) { 155 if (shouldLogWarning) { 156 opt_model.importWarning({ 157 type: 'numeric_parse_error', 158 message: 'Multiple units provided for numeric: \'' + 159 aggregatedUnit.unitName + '\' and \'' + unit.unitName + '\'.' 160 }); 161 shouldLogWarning = false; // Don't log multiple warnings. 162 } 163 // Use the most generic unit when the numerics don't agree (best 164 // effort). 165 aggregatedUnit = tr.v.Unit.byName.unitlessNumber_smallerIsBetter; 166 } 167 168 aggregatedValue += numeric.value; 169 }, this); 170 171 if (aggregatedUnit === undefined) 172 return undefined; 173 174 return new tr.v.ScalarNumeric(aggregatedUnit, aggregatedValue); 175 }; 176 177 /** 178 * @constructor 179 */ 180 function MemoryAllocatorDumpLink(source, target, opt_importance) { 181 this.source = source; 182 this.target = target; 183 this.importance = opt_importance; 184 this.size = undefined; 185 } 186 187 /** 188 * Types of size numeric information. 189 * 190 * @enum 191 */ 192 var MemoryAllocatorDumpInfoType = { 193 // The provided size of a MemoryAllocatorDump was less than the aggregated 194 // size of its children. 195 // 196 // Mandatory extra args: 197 // * providedSize: The inconsistent provided size. 198 // * dependencySize: The aggregated size of the children. 199 PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN: 0, 200 201 // The provided size of a MemoryAllocatorDump was less than the size of its 202 // largest owner. 203 // 204 // Mandatory extra args: 205 // * providedSize: The inconsistent provided size. 206 // * dependencySize: The size of the largest owner. 207 PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER: 1 208 }; 209 210 return { 211 MemoryAllocatorDump: MemoryAllocatorDump, 212 MemoryAllocatorDumpLink: MemoryAllocatorDumpLink, 213 MemoryAllocatorDumpInfoType: MemoryAllocatorDumpInfoType 214 }; 215}); 216</script> 217