process_memory_dump_test.html revision 972bd9a9d2c6597a0145a675cbfa527d0510b048
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/core/test_utils.html"> 9<link rel="import" href="/tracing/model/attribute.html"> 10<link rel="import" href="/tracing/model/model.html"> 11<link rel="import" href="/tracing/model/global_memory_dump.html"> 12<link rel="import" href="/tracing/model/memory_allocator_dump.html"> 13<link rel="import" href="/tracing/model/process_memory_dump.html"> 14 15<script> 16'use strict'; 17 18tr.b.unittest.testSuite(function() { 19 var GlobalMemoryDump = tr.model.GlobalMemoryDump; 20 var ProcessMemoryDump = tr.model.ProcessMemoryDump; 21 var MemoryAllocatorDump = tr.model.MemoryAllocatorDump; 22 var MemoryAllocatorDumpLink = tr.model.MemoryAllocatorDumpLink; 23 var VMRegion = tr.model.VMRegion; 24 var ScalarAttribute = tr.model.ScalarAttribute; 25 26 var createProcessMemoryDump = function(timestamp, model) { 27 var gmd = new GlobalMemoryDump(model, timestamp); 28 model.globalMemoryDumps.push(gmd); 29 var p = model.getOrCreateProcess(123); 30 var pmd = new ProcessMemoryDump(gmd, p, timestamp + 1); 31 gmd.processMemoryDumps[123] = pmd; 32 p.memoryDumps.push(pmd); 33 return pmd; 34 } 35 36 var createFinalizedProcessMemoryDump = function(timestamp, createdCallback) { 37 return createFinalizedProcessMemoryDumps([timestamp], function(pmds) { 38 createdCallback(pmds[0]); 39 })[0]; 40 } 41 42 function createFinalizedProcessMemoryDumps(timestamps, createdCallback) { 43 var model = tr.c.TestUtils.newModel(function(model) { 44 var pmds = timestamps.map(function(timestamp) { 45 return createProcessMemoryDump(timestamp, model); 46 }); 47 createdCallback(pmds); 48 }); 49 var pmds = model.getProcess(123).memoryDumps; 50 assert.lengthOf(pmds, timestamps.length); 51 return pmds; 52 } 53 54 function checkProtectionFlagsToString(protectionFlags, expectedString) { 55 var vmRegion = VMRegion.fromDict({ 56 startAddress: 256, 57 sizeInBytes: 336, 58 protectionFlags: protectionFlags, 59 mappedFile: '[stack:20310]', 60 byteStats: { 61 privateDirtyResident: 96, 62 swapped: 144, 63 proportionalResident: 158 64 } 65 }); 66 assert.strictEqual(vmRegion.protectionFlagsToString, expectedString); 67 } 68 69 test('totalResidentSizeInBytes_undefinedVmRegions', function() { 70 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {}); 71 assert.isUndefined(pmd.mostRecentTotalProportionalResidentSizeInBytes); 72 assert.isUndefined( 73 pmd.getMostRecentTotalVmRegionStat('privateDirtyResident')); 74 assert.isUndefined( 75 pmd.getMostRecentTotalVmRegionStat('privateCleanResident')); 76 }); 77 78 test('totalResidentSizeInBytes_zeroVmRegions', function() { 79 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 80 pmd.vmRegions = []; 81 }); 82 assert.equal(pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 0); 83 assert.equal(pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 0); 84 assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0); 85 }); 86 87 test('totalResidentSizeInBytes_oneVmRegion', function() { 88 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 89 pmd.vmRegions = [ 90 VMRegion.fromDict({ 91 startAddress: 256, 92 sizeInBytes: 336, 93 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 94 VMRegion.PROTECTION_FLAG_WRITE, 95 mappedFile: '[stack:20310]', 96 byteStats: { 97 privateDirtyResident: 96, 98 swapped: 144, 99 proportionalResident: 158 100 } 101 }) 102 ]; 103 }); 104 assert.equal( 105 pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 158); 106 assert.equal( 107 pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 96); 108 assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0); 109 }); 110 111 test('totalResidentSizeInBytes_twoVmRegions', function() { 112 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 113 pmd.vmRegions = [ 114 VMRegion.fromDict({ 115 startAddress: 256, 116 sizeInBytes: 336, 117 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 118 VMRegion.PROTECTION_FLAG_WRITE, 119 mappedFile: '[stack:20310]', 120 byteStats: { 121 privateDirtyResident: 96, 122 swapped: 144, 123 proportionalResident: 158 124 } 125 }), 126 VMRegion.fromDict({ 127 startAddress: 848, 128 sizeInBytes: 592, 129 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 130 VMRegion.PROTECTION_FLAG_EXECUTE, 131 mappedFile: '/dev/ashmem/dalvik', 132 byteStats: { 133 privateDirtyResident: 205, 134 privateCleanResident: 0, 135 proportionalResident: 205 136 } 137 }) 138 ]; 139 }); 140 assert.equal( 141 pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 363); 142 assert.equal( 143 pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 301); 144 assert.equal(pmd.getMostRecentTotalVmRegionStat('swapped'), 144); 145 assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0); 146 assert.equal(pmd.getMostRecentTotalVmRegionStat('sharedCleanResident'), 0); 147 }); 148 149 test('hookUpMostRecentVmRegionsLinks_emptyArray', function() { 150 var dumps = []; 151 ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(dumps); 152 assert.lengthOf(dumps, 0); 153 }); 154 155 test('hookUpMostRecentVmRegionsLinks_nonEmptyArray', function() { 156 var m = new tr.Model(); 157 158 // A dump with no VM regions or allocator dumps. 159 var dump1 = createProcessMemoryDump(1, m); 160 161 // A dump with VM regions and malloc and Oilpan allocator dumps. 162 var dump2 = createProcessMemoryDump(2, m); 163 dump2.vmRegions = []; 164 dump2.memoryAllocatorDumps = (function() { 165 var oilpanDump = new MemoryAllocatorDump('oilpan'); 166 oilpanDump.addAttribute('size', new ScalarAttribute('bytes', 1024)); 167 oilpanDump.addAttribute('objects_count', 168 new ScalarAttribute('objects', 7)); 169 oilpanDump.addAttribute('inner_size', new ScalarAttribute('bytes', 768)); 170 171 var v8Dump = new MemoryAllocatorDump('v8'); 172 v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048)); 173 v8Dump.addAttribute('objects_count', new ScalarAttribute('objects', 15)); 174 v8Dump.addAttribute('inner_size', new ScalarAttribute('bytes', 1999)); 175 176 return [oilpanDump. v8Dump]; 177 })(); 178 179 // A dump with malloc and V8 allocator dumps. 180 var dump3 = createProcessMemoryDump(3, m); 181 dump3.memoryAllocatorDumps = (function() { 182 var mallocDump = new MemoryAllocatorDump('malloc'); 183 mallocDump.addAttribute('size', new ScalarAttribute('bytes', 1024)); 184 mallocDump.addAttribute('objects_count', 185 new ScalarAttribute('objects', 7)); 186 mallocDump.addAttribute('inner_size', new ScalarAttribute('bytes', 768)); 187 188 var v8Dump = new MemoryAllocatorDump('v8'); 189 v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048)); 190 v8Dump.addAttribute('objects_count', new ScalarAttribute('objects', 15)); 191 v8Dump.addAttribute('inner_size', new ScalarAttribute('bytes', 1999)); 192 193 return [mallocDump. v8Dump]; 194 })(); 195 196 // A dump with VM regions. 197 var dump4 = createProcessMemoryDump(4, m); 198 dump4.vmRegions = [ 199 VMRegion.fromDict({ 200 startAddress: 256, 201 sizeInBytes: 336, 202 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 203 VMRegion.PROTECTION_FLAG_WRITE, 204 mappedFile: '[stack:20310]', 205 byteStats: { 206 privateResident: 96, 207 sharedResident: 144, 208 proportionalResident: 158 209 } 210 }) 211 ]; 212 213 var dumps = [dump1, dump2, dump3, dump4]; 214 ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(dumps); 215 216 assert.lengthOf(dumps, 4); 217 218 assert.equal(dumps[0], dump1); 219 assert.isUndefined(dump1.mostRecentVmRegions); 220 221 assert.equal(dumps[1], dump2); 222 assert.equal(dump2.mostRecentVmRegions, dump2.vmRegions_); 223 224 assert.equal(dumps[2], dump3); 225 assert.equal(dump3.mostRecentVmRegions, dump2.vmRegions_); 226 227 assert.equal(dumps[3], dump4); 228 assert.equal(dump4.mostRecentVmRegions, dump4.vmRegions_); 229 }); 230 231 test('vmRegion_protectionFlagsToString', function() { 232 checkProtectionFlagsToString(undefined, undefined); 233 checkProtectionFlagsToString(0, '---'); 234 checkProtectionFlagsToString(VMRegion.PROTECTION_FLAG_READ, 'r--'); 235 checkProtectionFlagsToString( 236 VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_EXECUTE, 237 'r-x'); 238 checkProtectionFlagsToString( 239 VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE, 240 'rw-'); 241 }); 242 243 test('checkDiscountTracingOverhead_undefinedFields', function() { 244 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 245 var v8Dump = new MemoryAllocatorDump(pmd, 'v8'); 246 v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048)); 247 248 var tracingDump = new MemoryAllocatorDump(pmd, 'tracing'); 249 tracingDump.addAttribute('size', new ScalarAttribute('bytes', 1024)); 250 251 pmd.memoryAllocatorDumps = [v8Dump, tracingDump]; 252 }); 253 254 assert.isUndefined(pmd.totals); 255 assert.isUndefined( 256 pmd.getMostRecentTotalVmRegionStat('proportionalResident')); 257 258 var v8Dump = pmd.getMemoryAllocatorDumpByFullName('v8'); 259 assert.equal(v8Dump.attributes['size'].value, 2048); 260 261 var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing'); 262 assert.equal(tracingDump.attributes['size'].value, 1024); 263 }); 264 265 test('checkDiscountTracingOverhead_definedFields', function() { 266 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 267 pmd.totals = { residentBytes: 10240 }; 268 269 pmd.vmRegions = [ 270 VMRegion.fromDict({ 271 startAddress: 256, 272 sizeInBytes: 6000, 273 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 274 VMRegion.PROTECTION_FLAG_WRITE, 275 mappedFile: '[stack:20310]', 276 byteStats: { 277 privateDirtyResident: 4096, 278 swapped: 1536, 279 proportionalResident: 5120 280 } 281 }) 282 ]; 283 284 var mallocDump = new MemoryAllocatorDump(pmd, 'malloc'); 285 mallocDump.addAttribute('size', new ScalarAttribute('bytes', 3072)); 286 var allocatedObjectsDump = new MemoryAllocatorDump( 287 pmd, 'malloc/allocated_objects'); 288 allocatedObjectsDump.addAttribute( 289 'size', new ScalarAttribute('bytes', 2560)); 290 allocatedObjectsDump.parent = mallocDump; 291 mallocDump.children.push(allocatedObjectsDump); 292 293 var tracingDump = new MemoryAllocatorDump(pmd, 'tracing'); 294 tracingDump.addAttribute('size', new ScalarAttribute('bytes', 1024)); 295 tracingDump.addAttribute( 296 'resident_size', new ScalarAttribute('bytes', 1000)); 297 298 // We need to inject a fake owner of the 'tracing' dump so that we alter 299 // its effective size. 300 var ownerDump = new MemoryAllocatorDump(pmd, 'owner'); 301 ownerDump.addAttribute('size', new ScalarAttribute('bytes', 256)); 302 var ownershipLink = new MemoryAllocatorDumpLink(ownerDump, tracingDump); 303 ownerDump.owns = ownershipLink; 304 tracingDump.ownedBy.push(ownershipLink); 305 306 pmd.memoryAllocatorDumps = [mallocDump, tracingDump, ownerDump]; 307 }); 308 309 assert.equal(pmd.totals.residentBytes, 9240); 310 assert.isUndefined(pmd.totals.peakResidentBytes); 311 312 assert.equal( 313 pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 3096); 314 assert.equal(pmd.getMostRecentTotalVmRegionStat('swapped'), 1536); 315 assert.equal( 316 pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 4120); 317 318 var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc'); 319 assert.equal(mallocDump.attributes['size'].value, 2048); 320 assert.equal(mallocDump.attributes['effective_size'].value, 2304); 321 assert.lengthOf( 322 mallocDump.children, 2 /* 'allocated_objects' and '<unspecified>' */); 323 324 var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName( 325 'malloc/allocated_objects'); 326 assert.equal(allocatedObjectsDump.attributes['size'].value, 1536); 327 assert.equal(allocatedObjectsDump.attributes['effective_size'].value, 1792); 328 assert.lengthOf( 329 allocatedObjectsDump.children, 1 /* 'discounted_tracing_overhead' */); 330 331 var discountDump = pmd.getMemoryAllocatorDumpByFullName( 332 'malloc/allocated_objects/discounted_tracing_overhead'); 333 assert.strictEqual(discountDump.parent, allocatedObjectsDump); 334 assert.include(allocatedObjectsDump.children, discountDump); 335 assert.equal(discountDump.attributes['size'].value, -1024); 336 assert.equal(discountDump.attributes['effective_size'].value, -768); 337 338 var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing'); 339 assert.equal(tracingDump.attributes['size'].value, 1024); 340 assert.equal(tracingDump.attributes['effective_size'].value, 768); 341 assert.equal(tracingDump.attributes['resident_size'].value, 1000); 342 }); 343 344 test('checkDiscountTracingOverhead_winheap', function() { 345 var pmd = createFinalizedProcessMemoryDump(42, function(pmd) { 346 var winheapDump = new MemoryAllocatorDump(pmd, 'winheap'); 347 winheapDump.addAttribute('size', new ScalarAttribute('bytes', 5120)); 348 349 var tracingDump = new MemoryAllocatorDump(pmd, 'tracing'); 350 tracingDump.addAttribute('size', new ScalarAttribute('bytes', 2048)); 351 352 pmd.memoryAllocatorDumps = [tracingDump, winheapDump]; 353 }); 354 355 assert.isUndefined(pmd.totals); 356 357 assert.isUndefined( 358 pmd.getMostRecentTotalVmRegionStat('privateDirtyResident')); 359 assert.isUndefined(pmd.getMostRecentTotalVmRegionStat('swapped')); 360 assert.isUndefined( 361 pmd.getMostRecentTotalVmRegionStat('proportionalResident')); 362 363 var winheapDump = pmd.getMemoryAllocatorDumpByFullName('winheap'); 364 assert.equal(winheapDump.attributes['size'].value, 3072); 365 assert.equal(winheapDump.attributes['effective_size'].value, 3072); 366 assert.lengthOf(winheapDump.children, 0); 367 368 var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing'); 369 assert.equal(tracingDump.attributes['size'].value, 2048); 370 assert.equal(tracingDump.attributes['effective_size'].value, 2048); 371 }); 372 373 test('checkDiscountTracingOverhead_withMostRecentVmRegionsLinks', function() { 374 var pmds = createFinalizedProcessMemoryDumps([42, 90], function(pmds) { 375 pmds[0].totals = { residentBytes: 1000, peakResidentBytes: 2000 }; 376 pmds[0].vmRegions = [ 377 VMRegion.fromDict({ 378 startAddress: 256, 379 sizeInBytes: 6000, 380 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 381 VMRegion.PROTECTION_FLAG_WRITE, 382 mappedFile: '[stack:20310]', 383 byteStats: { 384 privateDirtyResident: 4096 385 } 386 }) 387 ]; 388 pmds[0].memoryAllocatorDumps = (function() { 389 var tracingDump = new MemoryAllocatorDump(pmds[0], 'tracing'); 390 tracingDump.addAttribute( 391 'resident_size', new ScalarAttribute('bytes', 100)); 392 return [tracingDump]; 393 })(); 394 395 pmds[1].totals = { peakResidentBytes: 3000 }; 396 pmds[1].memoryAllocatorDumps = (function() { 397 var tracingDump = new MemoryAllocatorDump(pmds[0], 'tracing'); 398 tracingDump.addAttribute( 399 'resident_size', new ScalarAttribute('bytes', 200)); 400 return [tracingDump]; 401 })(); 402 }); 403 404 // First PMD: Both total resident and private dirty resident size should be 405 // reduced by 100. 406 assert.equal(pmds[0].totals.residentBytes, 900); 407 assert.equal(pmds[0].totals.peakResidentBytes, 1900); 408 assert.equal( 409 pmds[0].getMostRecentTotalVmRegionStat('privateDirtyResident'), 3996); 410 411 // Second PMD: Total resident size should be reduced by 200, whereas private 412 // dirty resident size should be reduced by 100 (because it comes from 413 // the VM regions in the first dump). 414 assert.isUndefined(pmds[1].totals.residentBytes); 415 assert.equal(pmds[1].totals.peakResidentBytes, 2800); 416 assert.equal( 417 pmds[1].getMostRecentTotalVmRegionStat('privateDirtyResident'), 3996); 418 }); 419}); 420</script> 421