process_memory_dump.html revision 46b43bff003ceda46cf9a5d40a47f7674996d2e0
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/units/time_stamp.html"> 9<link rel="import" href="/tracing/model/attribute.html"> 10<link rel="import" href="/tracing/model/container_memory_dump.html"> 11<link rel="import" href="/tracing/model/memory_allocator_dump.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 /** 26 * The ProcessMemoryDump represents a memory dump of a single process. 27 * @constructor 28 */ 29 function ProcessMemoryDump(globalMemoryDump, process, start) { 30 tr.model.ContainerMemoryDump.call(this, start); 31 this.process = process; 32 this.globalMemoryDump = globalMemoryDump; 33 34 this.totalResidentBytes = undefined; 35 this.vmRegions_ = undefined; 36 37 this.tracingMemoryDiscounted_ = false; 38 }; 39 40 ProcessMemoryDump.prototype = { 41 __proto__: tr.model.ContainerMemoryDump.prototype, 42 43 get userFriendlyName() { 44 return 'Process memory dump at ' + 45 tr.b.u.TimeStamp.format(this.start); 46 }, 47 48 get containerName() { 49 return this.process.userFriendlyName; 50 }, 51 52 get vmRegions() { 53 throw new Error( 54 'VM regions must be accessed through the mostRecentVmRegions field'); 55 }, 56 57 set vmRegions(vmRegions) { 58 this.vmRegions_ = vmRegions; 59 }, 60 61 get hasOwnVmRegions() { 62 return this.vmRegions_ !== undefined; 63 }, 64 65 getMostRecentTotalVmRegionStat: function(statName) { 66 if (this.mostRecentVmRegions === undefined) 67 return undefined; 68 69 var total = 0; 70 this.mostRecentVmRegions.forEach(function(vmRegion) { 71 var statValue = vmRegion.byteStats[statName]; 72 if (statValue === undefined) 73 return; 74 total += statValue; 75 }); 76 return total; 77 }, 78 79 discountTracingOverhead: function(opt_model) { 80 // Make sure that calling this method twice won't lead to 81 // 'double-discounting'. 82 if (this.tracingMemoryDiscounted_) 83 return; 84 this.tracingMemoryDiscounted_ = true; 85 86 var tracingDump = this.getMemoryAllocatorDumpByFullName('tracing'); 87 if (tracingDump === undefined) 88 return; 89 90 function getDiscountedSize(sizeAttrName) { 91 var sizeAttr = tracingDump.getValidSizeAttributeOrUndefined( 92 sizeAttrName, opt_model); 93 if (sizeAttr === undefined) 94 return 0; 95 return sizeAttr.value; 96 } 97 98 var discountedSize = getDiscountedSize('size'); 99 var discountedEffectiveSize = getDiscountedSize('effective_size'); 100 var discountedResidentSize = getDiscountedSize('resident_size'); 101 102 // Subtract 'resident_size' from totals and VM regions stats. 103 if (discountedResidentSize > 0) { 104 // Subtract the tracing size from the total. 105 if (this.totalResidentBytes !== undefined) 106 this.totalResidentBytes -= discountedResidentSize; 107 108 // Subtract the tracing size from VM regions. 109 if (this.vmRegions_ !== undefined) { 110 this.vmRegions_.push(VMRegion.fromDict({ 111 mappedFile: '[discounted tracing overhead]', 112 byteStats: { 113 privateDirtyResident: -discountedResidentSize, 114 proportionalResident: -discountedResidentSize 115 } 116 })); 117 } 118 } 119 120 // Subtract 'size' and 'effective_size' from the 'winheap' or 'malloc' 121 // MemoryAllocatorDump. 122 if (discountedSize > 0 || discountedEffectiveSize > 0) { 123 function discountSizeAndEffectiveSize(dump) { 124 var dumpSizeAttr = dump.getValidSizeAttributeOrUndefined( 125 'size', opt_model); 126 if (dumpSizeAttr !== undefined) 127 dumpSizeAttr.value -= discountedSize; 128 129 var dumpEffectiveSizeAttr = dump.getValidSizeAttributeOrUndefined( 130 'effective_size', opt_model); 131 if (dumpEffectiveSizeAttr !== undefined) 132 dumpEffectiveSizeAttr.value -= discountedEffectiveSize; 133 } 134 135 var hasDiscountedFromAllocatorDumps = DISCOUNTED_ALLOCATOR_NAMES.some( 136 function(allocatorName) { 137 // Discount 'size' and 'effective_size' from the allocator root. 138 var allocatorDump = this.getMemoryAllocatorDumpByFullName( 139 allocatorName); 140 if (allocatorDump === undefined) 141 return false; // Allocator doesn't exist, try another one. 142 discountSizeAndEffectiveSize(allocatorDump); 143 144 // Discount 'size' and 'effective_size' from allocated objects of the 145 // allocator ('<ALLOCATOR>/allocated_objects'). 146 var allocatedObjectsDumpName = allocatorName + '/allocated_objects'; 147 var allocatedObjectsDump = this.getMemoryAllocatorDumpByFullName( 148 allocatedObjectsDumpName); 149 if (allocatedObjectsDump === undefined) 150 return true; // Allocator has unexpected structure, good enough. 151 discountSizeAndEffectiveSize(allocatedObjectsDump); 152 153 // Add a child MAD representing the discounted tracing overhead 154 // ('<ALLOCATOR>/allocated_objects/discounted_tracing_overhead'). 155 var discountDumpName = 156 allocatedObjectsDumpName + '/discounted_tracing_overhead'; 157 var discountDump = new tr.model.MemoryAllocatorDump( 158 this, discountDumpName); 159 discountDump.parent = allocatedObjectsDump; 160 discountDump.addAttribute('size', 161 new tr.model.ScalarAttribute('bytes', -discountedSize)); 162 discountDump.addAttribute('effective_size', 163 new tr.model.ScalarAttribute('bytes', -discountedEffectiveSize)); 164 allocatedObjectsDump.children.push(discountDump); 165 166 return true; 167 }, this); 168 169 // Force rebuilding the memory allocator dump index (if we've just added 170 // a new memory allocator dump). 171 if (hasDiscountedFromAllocatorDumps) 172 this.memoryAllocatorDumps = this.memoryAllocatorDumps; 173 } 174 } 175 }; 176 177 ProcessMemoryDump.hookUpMostRecentVmRegionsLinks = function(processDumps) { 178 var mostRecentVmRegions = undefined; 179 180 processDumps.forEach(function(processDump) { 181 // Update the most recent VM regions from the current dump. 182 if (processDump.vmRegions_ !== undefined) 183 mostRecentVmRegions = processDump.vmRegions_; 184 185 // Set the most recent VM regions of the current dump. 186 processDump.mostRecentVmRegions = mostRecentVmRegions; 187 }); 188 }; 189 190 /** 191 * @constructor 192 */ 193 function VMRegion(startAddress, sizeInBytes, protectionFlags, 194 mappedFile, byteStats) { 195 this.startAddress = startAddress; 196 this.sizeInBytes = sizeInBytes; 197 this.protectionFlags = protectionFlags; 198 this.mappedFile = mappedFile; 199 this.byteStats = byteStats; 200 }; 201 202 VMRegion.PROTECTION_FLAG_READ = 4; 203 VMRegion.PROTECTION_FLAG_WRITE = 2; 204 VMRegion.PROTECTION_FLAG_EXECUTE = 1; 205 206 VMRegion.prototype = { 207 get protectionFlagsToString() { 208 if (this.protectionFlags === undefined) 209 return undefined; 210 return ( 211 (this.protectionFlags & VMRegion.PROTECTION_FLAG_READ ? 'r' : '-') + 212 (this.protectionFlags & VMRegion.PROTECTION_FLAG_WRITE ? 'w' : '-') + 213 (this.protectionFlags & VMRegion.PROTECTION_FLAG_EXECUTE ? 'x' : '-') 214 ); 215 } 216 }; 217 218 VMRegion.fromDict = function(dict) { 219 return new VMRegion( 220 dict.startAddress, 221 dict.sizeInBytes, 222 dict.protectionFlags, 223 dict.mappedFile, 224 VMRegionByteStats.fromDict(dict.byteStats)); 225 }; 226 227 /** 228 * @constructor 229 */ 230 function VMRegionByteStats(privateCleanResident, privateDirtyResident, 231 sharedCleanResident, sharedDirtyResident, 232 proportionalResident, swapped) { 233 this.privateCleanResident = privateCleanResident; 234 this.privateDirtyResident = privateDirtyResident; 235 this.sharedCleanResident = sharedCleanResident; 236 this.sharedDirtyResident = sharedDirtyResident; 237 this.proportionalResident = proportionalResident; 238 this.swapped = swapped; 239 } 240 241 VMRegionByteStats.fromDict = function(dict) { 242 return new VMRegionByteStats( 243 dict.privateCleanResident, 244 dict.privateDirtyResident, 245 dict.sharedCleanResident, 246 dict.sharedDirtyResident, 247 dict.proportionalResident, 248 dict.swapped); 249 } 250 251 tr.model.EventRegistry.register( 252 ProcessMemoryDump, 253 { 254 name: 'processMemoryDump', 255 pluralName: 'processMemoryDumps', 256 singleViewElementName: 'tr-ui-a-single-process-memory-dump-sub-view', 257 multiViewElementName: 'tr-ui-a-multi-process-memory-dump-sub-view' 258 }); 259 260 return { 261 ProcessMemoryDump: ProcessMemoryDump, 262 VMRegion: VMRegion, 263 VMRegionByteStats: VMRegionByteStats 264 }; 265}); 266</script> 267