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/model/container_memory_dump.html"> 9<link rel="import" href="/tracing/model/memory_allocator_dump.html"> 10<link rel="import" href="/tracing/model/vm_region.html"> 11<link rel="import" href="/tracing/value/unit.html"> 12 13<script> 14'use strict'; 15 16/** 17 * @fileoverview Provides the ProcessMemoryDump class. 18 */ 19tr.exportTo('tr.model', function() { 20 21 // Names of MemoryAllocatorDump(s) from which tracing overhead should be 22 // discounted. 23 var DISCOUNTED_ALLOCATOR_NAMES = ['winheap', 'malloc']; 24 25 // The path to where the tracing overhead dump should be added to the 26 // winheap/malloc allocator dump tree. 27 var TRACING_OVERHEAD_PATH = ['allocated_objects', 'tracing_overhead']; 28 29 var SIZE_NUMERIC_NAME = tr.model.MemoryAllocatorDump.SIZE_NUMERIC_NAME; 30 var RESIDENT_SIZE_NUMERIC_NAME = 31 tr.model.MemoryAllocatorDump.RESIDENT_SIZE_NUMERIC_NAME; 32 33 function getSizeNumericValue(dump, sizeNumericName) { 34 var sizeNumeric = dump.numerics[sizeNumericName]; 35 if (sizeNumeric === undefined) 36 return 0; 37 return sizeNumeric.value; 38 } 39 40 /** 41 * The ProcessMemoryDump represents a memory dump of a single process. 42 * @constructor 43 */ 44 function ProcessMemoryDump(globalMemoryDump, process, start) { 45 tr.model.ContainerMemoryDump.call(this, start); 46 this.process = process; 47 this.globalMemoryDump = globalMemoryDump; 48 49 // Process memory totals (optional object) with the following fields (also 50 // optional): 51 // - residentBytes: Total resident bytes (number) 52 // - peakResidentBytes: Peak resident bytes (number) 53 // - arePeakResidentBytesResettable: Flag whether peak resident bytes are 54 // resettable (boolean) 55 // - platformSpecific: Map from OS-specific total names (string) to sizes 56 // (number) 57 this.totals = undefined; 58 59 this.vmRegions = undefined; 60 61 // Map from allocator names to heap dumps. 62 this.heapDumps = undefined; 63 64 this.tracingOverheadOwnershipSetUp_ = false; 65 this.tracingOverheadDiscountedFromVmRegions_ = false; 66 }; 67 68 ProcessMemoryDump.prototype = { 69 __proto__: tr.model.ContainerMemoryDump.prototype, 70 71 get userFriendlyName() { 72 return 'Process memory dump at ' + 73 tr.v.Unit.byName.timeStampInMs.format(this.start); 74 }, 75 76 get containerName() { 77 return this.process.userFriendlyName; 78 }, 79 80 get processMemoryDumps() { 81 var dumps = {}; 82 dumps[this.process.pid] = this; 83 return dumps; 84 }, 85 86 get hasOwnVmRegions() { 87 return this.vmRegions !== undefined; 88 }, 89 90 setUpTracingOverheadOwnership: function(opt_model) { 91 // Make sure that calling this method twice won't lead to 92 // 'double-discounting'. 93 if (this.tracingOverheadOwnershipSetUp_) 94 return; 95 this.tracingOverheadOwnershipSetUp_ = true; 96 97 var tracingDump = this.getMemoryAllocatorDumpByFullName('tracing'); 98 if (tracingDump === undefined || tracingDump.owns !== undefined) { 99 // The tracing dump either doesn't exist, or it already owns another 100 // dump. 101 return; 102 } 103 104 if (tracingDump.owns !== undefined) 105 return; 106 107 // Add an ownership link from tracing to 108 // malloc/allocated_objects/tracing_overhead or 109 // winheap/allocated_objects/tracing_overhead. 110 var hasDiscountedFromAllocatorDumps = DISCOUNTED_ALLOCATOR_NAMES.some( 111 function(allocatorName) { 112 // First check if the allocator root exists. 113 var allocatorDump = this.getMemoryAllocatorDumpByFullName( 114 allocatorName); 115 if (allocatorDump === undefined) 116 return false; // Allocator doesn't exist, try another one. 117 118 var nextPathIndex = 0; 119 var currentDump = allocatorDump; 120 var currentFullName = allocatorName; 121 122 // Descend from the root towards tracing_overhead as long as the dumps 123 // on the path exist. 124 for (; nextPathIndex < TRACING_OVERHEAD_PATH.length; nextPathIndex++) { 125 var childFullName = currentFullName + '/' + 126 TRACING_OVERHEAD_PATH[nextPathIndex]; 127 var childDump = this.getMemoryAllocatorDumpByFullName( 128 childFullName); 129 if (childDump === undefined) 130 break; 131 132 currentDump = childDump; 133 currentFullName = childFullName; 134 } 135 136 // Create the missing descendant dumps on the path from the root 137 // towards tracing_overhead. 138 for (; nextPathIndex < TRACING_OVERHEAD_PATH.length; nextPathIndex++) { 139 var childFullName = currentFullName + '/' + 140 TRACING_OVERHEAD_PATH[nextPathIndex]; 141 var childDump = new tr.model.MemoryAllocatorDump( 142 currentDump.containerMemoryDump, childFullName); 143 childDump.parent = currentDump; 144 currentDump.children.push(childDump); 145 146 currentFullName = childFullName; 147 currentDump = childDump; 148 } 149 150 // Add the ownership link. 151 var ownershipLink = 152 new tr.model.MemoryAllocatorDumpLink(tracingDump, currentDump); 153 tracingDump.owns = ownershipLink; 154 currentDump.ownedBy.push(ownershipLink); 155 return true; 156 }, this); 157 158 // Force rebuilding the memory allocator dump index (if we've just added 159 // a new memory allocator dump). 160 if (hasDiscountedFromAllocatorDumps) 161 this.forceRebuildingMemoryAllocatorDumpByFullNameIndex(); 162 }, 163 164 discountTracingOverheadFromVmRegions: function(opt_model) { 165 // Make sure that calling this method twice won't lead to 166 // 'double-discounting'. 167 if (this.tracingOverheadDiscountedFromVmRegions_) 168 return; 169 this.tracingOverheadDiscountedFromVmRegions_ = true; 170 171 var tracingDump = this.getMemoryAllocatorDumpByFullName('tracing'); 172 if (tracingDump === undefined) 173 return; 174 175 var discountedSize = 176 getSizeNumericValue(tracingDump, SIZE_NUMERIC_NAME); 177 var discountedResidentSize = 178 getSizeNumericValue(tracingDump, RESIDENT_SIZE_NUMERIC_NAME); 179 180 if (discountedSize <= 0 && discountedResidentSize <= 0) 181 return; 182 183 // Subtract the tracing size from the totals. 184 if (this.totals !== undefined) { 185 if (this.totals.residentBytes !== undefined) 186 this.totals.residentBytes -= discountedResidentSize; 187 if (this.totals.peakResidentBytes !== undefined) 188 this.totals.peakResidentBytes -= discountedResidentSize; 189 } 190 191 // Subtract the tracing size from VM regions. More precisely, subtract 192 // tracing resident_size from byte stats (private dirty and PSS) and 193 // tracing size from virtual size by injecting a fake VM region with 194 // negative values. 195 if (this.vmRegions !== undefined) { 196 var hasSizeInBytes = this.vmRegions.sizeInBytes !== undefined; 197 var hasPrivateDirtyResident = 198 this.vmRegions.byteStats.privateDirtyResident !== undefined; 199 var hasProportionalResident = 200 this.vmRegions.byteStats.proportionalResident !== undefined; 201 202 if ((hasSizeInBytes && discountedSize > 0) || 203 ((hasPrivateDirtyResident || hasProportionalResident) && 204 discountedResidentSize > 0)) { 205 var byteStats = {}; 206 if (hasPrivateDirtyResident) 207 byteStats.privateDirtyResident = -discountedResidentSize; 208 if (hasProportionalResident) 209 byteStats.proportionalResident = -discountedResidentSize; 210 this.vmRegions.addRegion(tr.model.VMRegion.fromDict({ 211 mappedFile: '[discounted tracing overhead]', 212 sizeInBytes: hasSizeInBytes ? -discountedSize : undefined, 213 byteStats: byteStats 214 })); 215 } 216 } 217 } 218 }; 219 220 ProcessMemoryDump.hookUpMostRecentVmRegionsLinks = function(processDumps) { 221 var mostRecentVmRegions = undefined; 222 223 processDumps.forEach(function(processDump) { 224 // Update the most recent VM regions from the current dump. 225 if (processDump.vmRegions !== undefined) 226 mostRecentVmRegions = processDump.vmRegions; 227 228 // Set the most recent VM regions of the current dump. 229 processDump.mostRecentVmRegions = mostRecentVmRegions; 230 }); 231 }; 232 233 tr.model.EventRegistry.register( 234 ProcessMemoryDump, 235 { 236 name: 'processMemoryDump', 237 pluralName: 'processMemoryDumps', 238 singleViewElementName: 'tr-ui-a-container-memory-dump-sub-view', 239 multiViewElementName: 'tr-ui-a-container-memory-dump-sub-view' 240 }); 241 242 return { 243 ProcessMemoryDump: ProcessMemoryDump 244 }; 245}); 246</script> 247