process_memory_dump_test.html revision 8d2b206a675ec20ea07100c35df34e65ee1e45e8
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  function createProcessMemoryDump(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  function createFinalizedProcessMemoryDump(timestamp, opt_createdCallback) {
37    return createFinalizedProcessMemoryDumps([timestamp], function(pmds) {
38      if (opt_createdCallback !== undefined)
39        opt_createdCallback(pmds[0]);
40    })[0];
41  }
42
43  function createFinalizedProcessMemoryDumps(timestamps, createdCallback) {
44    var model = tr.c.TestUtils.newModel(function(model) {
45      var pmds = timestamps.map(function(timestamp) {
46        return createProcessMemoryDump(timestamp, model);
47      });
48      createdCallback(pmds);
49    });
50    var pmds = model.getProcess(123).memoryDumps;
51    assert.lengthOf(pmds, timestamps.length);
52    return pmds;
53  }
54
55  function checkProtectionFlagsToString(protectionFlags, expectedString) {
56    var vmRegion = VMRegion.fromDict({
57      startAddress: 256,
58      sizeInBytes: 336,
59      protectionFlags: protectionFlags,
60      mappedFile: '[stack:20310]',
61      byteStats: {
62        privateDirtyResident: 96,
63        swapped: 144,
64        proportionalResident: 158
65      }
66    });
67    assert.strictEqual(vmRegion.protectionFlagsToString, expectedString);
68  }
69
70  test('processMemoryDumps', function() {
71    var pmd = createFinalizedProcessMemoryDump(42);
72    var pmds = pmd.processMemoryDumps;
73    assert.lengthOf(Object.keys(pmds), 1);
74    assert.strictEqual(pmds[123], pmd);
75  });
76
77  test('totalResidentSizeInBytes_undefinedVmRegions', function() {
78    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {});
79    assert.isUndefined(pmd.mostRecentTotalProportionalResidentSizeInBytes);
80    assert.isUndefined(
81        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'));
82    assert.isUndefined(
83        pmd.getMostRecentTotalVmRegionStat('privateCleanResident'));
84  });
85
86  test('totalResidentSizeInBytes_zeroVmRegions', function() {
87    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
88      pmd.vmRegions = [];
89    });
90    assert.equal(pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 0);
91    assert.equal(pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 0);
92    assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0);
93  });
94
95  test('totalResidentSizeInBytes_oneVmRegion', function() {
96    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
97      pmd.vmRegions = [
98        VMRegion.fromDict({
99          startAddress: 256,
100          sizeInBytes: 336,
101          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
102              VMRegion.PROTECTION_FLAG_WRITE,
103          mappedFile: '[stack:20310]',
104          byteStats: {
105            privateDirtyResident: 96,
106            swapped: 144,
107            proportionalResident: 158
108          }
109        })
110      ];
111    });
112    assert.equal(
113        pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 158);
114    assert.equal(
115        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 96);
116    assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0);
117  });
118
119  test('totalResidentSizeInBytes_twoVmRegions', function() {
120    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
121      pmd.vmRegions = [
122        VMRegion.fromDict({
123          startAddress: 256,
124          sizeInBytes: 336,
125          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
126              VMRegion.PROTECTION_FLAG_WRITE,
127          mappedFile: '[stack:20310]',
128          byteStats: {
129            privateDirtyResident: 96,
130            swapped: 144,
131            proportionalResident: 158
132          }
133        }),
134        VMRegion.fromDict({
135          startAddress: 848,
136          sizeInBytes: 592,
137          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
138              VMRegion.PROTECTION_FLAG_EXECUTE,
139          mappedFile: '/dev/ashmem/dalvik',
140          byteStats: {
141            privateDirtyResident: 205,
142            privateCleanResident: 0,
143            proportionalResident: 205
144          }
145        })
146      ];
147    });
148    assert.equal(
149        pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 363);
150    assert.equal(
151        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 301);
152    assert.equal(pmd.getMostRecentTotalVmRegionStat('swapped'), 144);
153    assert.equal(pmd.getMostRecentTotalVmRegionStat('privateCleanResident'), 0);
154    assert.equal(pmd.getMostRecentTotalVmRegionStat('sharedCleanResident'), 0);
155  });
156
157  test('hookUpMostRecentVmRegionsLinks_emptyArray', function() {
158    var dumps = [];
159    ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(dumps);
160    assert.lengthOf(dumps, 0);
161  });
162
163  test('hookUpMostRecentVmRegionsLinks_nonEmptyArray', function() {
164    var m = new tr.Model();
165
166    // A dump with no VM regions or allocator dumps.
167    var dump1 = createProcessMemoryDump(1, m);
168
169    // A dump with VM regions and malloc and Oilpan allocator dumps.
170    var dump2 = createProcessMemoryDump(2, m);
171    dump2.vmRegions = [];
172    dump2.memoryAllocatorDumps = (function() {
173      var oilpanDump = new MemoryAllocatorDump('oilpan');
174      oilpanDump.addAttribute('size', new ScalarAttribute('bytes', 1024));
175      oilpanDump.addAttribute('objects_count',
176          new ScalarAttribute('objects', 7));
177      oilpanDump.addAttribute('inner_size', new ScalarAttribute('bytes', 768));
178
179      var v8Dump = new MemoryAllocatorDump('v8');
180      v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048));
181      v8Dump.addAttribute('objects_count', new ScalarAttribute('objects', 15));
182      v8Dump.addAttribute('inner_size', new ScalarAttribute('bytes', 1999));
183
184      return [oilpanDump. v8Dump];
185    })();
186
187    // A dump with malloc and V8 allocator dumps.
188    var dump3 = createProcessMemoryDump(3, m);
189    dump3.memoryAllocatorDumps = (function() {
190      var mallocDump = new MemoryAllocatorDump('malloc');
191      mallocDump.addAttribute('size', new ScalarAttribute('bytes', 1024));
192      mallocDump.addAttribute('objects_count',
193          new ScalarAttribute('objects', 7));
194      mallocDump.addAttribute('inner_size', new ScalarAttribute('bytes', 768));
195
196      var v8Dump = new MemoryAllocatorDump('v8');
197      v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048));
198      v8Dump.addAttribute('objects_count', new ScalarAttribute('objects', 15));
199      v8Dump.addAttribute('inner_size', new ScalarAttribute('bytes', 1999));
200
201      return [mallocDump. v8Dump];
202    })();
203
204    // A dump with VM regions.
205    var dump4 = createProcessMemoryDump(4, m);
206    dump4.vmRegions = [
207      VMRegion.fromDict({
208        startAddress: 256,
209        sizeInBytes: 336,
210        protectionFlags: VMRegion.PROTECTION_FLAG_READ |
211            VMRegion.PROTECTION_FLAG_WRITE,
212        mappedFile: '[stack:20310]',
213        byteStats: {
214          privateResident: 96,
215          sharedResident: 144,
216          proportionalResident: 158
217        }
218      })
219    ];
220
221    var dumps = [dump1, dump2, dump3, dump4];
222    ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(dumps);
223
224    assert.lengthOf(dumps, 4);
225
226    assert.equal(dumps[0], dump1);
227    assert.isUndefined(dump1.mostRecentVmRegions);
228
229    assert.equal(dumps[1], dump2);
230    assert.equal(dump2.mostRecentVmRegions, dump2.vmRegions_);
231
232    assert.equal(dumps[2], dump3);
233    assert.equal(dump3.mostRecentVmRegions, dump2.vmRegions_);
234
235    assert.equal(dumps[3], dump4);
236    assert.equal(dump4.mostRecentVmRegions, dump4.vmRegions_);
237  });
238
239  test('vmRegion_protectionFlagsToString', function() {
240    checkProtectionFlagsToString(undefined, undefined);
241    checkProtectionFlagsToString(0, '---');
242    checkProtectionFlagsToString(VMRegion.PROTECTION_FLAG_READ, 'r--');
243    checkProtectionFlagsToString(
244        VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_EXECUTE,
245        'r-x');
246    checkProtectionFlagsToString(
247        VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE,
248        'rw-');
249  });
250
251  test('checkDiscountTracingOverhead_undefinedFields', function() {
252    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
253      var v8Dump = new MemoryAllocatorDump(pmd, 'v8');
254      v8Dump.addAttribute('size', new ScalarAttribute('bytes', 2048));
255
256      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
257      tracingDump.addAttribute('size', new ScalarAttribute('bytes', 1024));
258
259      pmd.memoryAllocatorDumps = [v8Dump, tracingDump];
260    });
261
262    assert.isUndefined(pmd.totals);
263    assert.isUndefined(
264        pmd.getMostRecentTotalVmRegionStat('proportionalResident'));
265
266    var v8Dump = pmd.getMemoryAllocatorDumpByFullName('v8');
267    assert.equal(v8Dump.attributes['size'].value, 2048);
268
269    var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
270    assert.equal(tracingDump.attributes['size'].value, 1024);
271  });
272
273  test('checkDiscountTracingOverhead_definedFields', function() {
274    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
275      pmd.totals = { residentBytes: 10240 };
276
277      pmd.vmRegions = [
278        VMRegion.fromDict({
279          startAddress: 256,
280          sizeInBytes: 6000,
281          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
282              VMRegion.PROTECTION_FLAG_WRITE,
283          mappedFile: '[stack:20310]',
284          byteStats: {
285            privateDirtyResident: 4096,
286            swapped: 1536,
287            proportionalResident: 5120
288          }
289        })
290      ];
291
292      var mallocDump = new MemoryAllocatorDump(pmd, 'malloc');
293      mallocDump.addAttribute('size', new ScalarAttribute('bytes', 3072));
294      var allocatedObjectsDump = new MemoryAllocatorDump(
295          pmd, 'malloc/allocated_objects');
296      allocatedObjectsDump.addAttribute(
297          'size', new ScalarAttribute('bytes', 2560));
298      allocatedObjectsDump.parent = mallocDump;
299      mallocDump.children.push(allocatedObjectsDump);
300
301      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
302      tracingDump.addAttribute('size', new ScalarAttribute('bytes', 1024));
303      tracingDump.addAttribute(
304          'resident_size', new ScalarAttribute('bytes', 1000));
305
306      pmd.memoryAllocatorDumps = [mallocDump, tracingDump];
307    });
308
309    assert.equal(pmd.totals.residentBytes, 9240);
310    assert.isUndefined(pmd.totals.peakResidentBytes);
311
312    var vmRegions = pmd.mostRecentVmRegions;
313    assert.lengthOf(vmRegions, 2);
314    var discountRegion = vmRegions[1];
315    assert.strictEqual(
316        discountRegion.mappedFile, '[discounted tracing overhead]');
317    assert.strictEqual(discountRegion.sizeInBytes, -1024);
318
319    assert.equal(
320        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 3096);
321    assert.equal(pmd.getMostRecentTotalVmRegionStat('swapped'), 1536);
322    assert.equal(
323        pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 4120);
324
325    var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc');
326    assert.equal(mallocDump.attributes['size'].value, 3072);
327    assert.equal(mallocDump.attributes['effective_size'].value, 2048);
328    assert.lengthOf(
329        mallocDump.children, 2 /* 'allocated_objects' and '<unspecified>' */);
330
331    var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName(
332        'malloc/allocated_objects');
333    assert.equal(allocatedObjectsDump.attributes['size'].value, 2560);
334    assert.equal(allocatedObjectsDump.attributes['effective_size'].value, 1536);
335    assert.lengthOf(
336        allocatedObjectsDump.children,
337        2 /* 'tracing_overhead' and '<unspecified>' */);
338
339    var discountDump = pmd.getMemoryAllocatorDumpByFullName(
340        'malloc/allocated_objects/tracing_overhead');
341    assert.strictEqual(discountDump.parent, allocatedObjectsDump);
342    assert.include(allocatedObjectsDump.children, discountDump);
343    assert.equal(discountDump.attributes['size'].value, 1024);
344    assert.equal(discountDump.attributes['effective_size'].value, 0);
345
346    var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
347    assert.equal(tracingDump.attributes['size'].value, 1024);
348    assert.equal(tracingDump.attributes['effective_size'].value, 1024);
349    assert.equal(tracingDump.attributes['resident_size'].value, 1000);
350    assert.strictEqual(tracingDump.owns.target, discountDump);
351  });
352
353  test('checkDiscountTracingOverhead_winheap', function() {
354    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
355      var winheapDump = new MemoryAllocatorDump(pmd, 'winheap');
356      winheapDump.addAttribute('size', new ScalarAttribute('bytes', 5120));
357
358      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
359      tracingDump.addAttribute('size', new ScalarAttribute('bytes', 2048));
360
361      pmd.memoryAllocatorDumps = [tracingDump, winheapDump];
362    });
363
364    assert.isUndefined(pmd.totals);
365
366    assert.isUndefined(
367        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'));
368    assert.isUndefined(pmd.getMostRecentTotalVmRegionStat('swapped'));
369    assert.isUndefined(
370        pmd.getMostRecentTotalVmRegionStat('proportionalResident'));
371
372    var winheapDump = pmd.getMemoryAllocatorDumpByFullName('winheap');
373    assert.equal(winheapDump.attributes['size'].value, 5120);
374    assert.equal(winheapDump.attributes['effective_size'].value, 3072);
375    assert.lengthOf(winheapDump.children,
376        2 /* 'allocated_objects' and '<unspecified>' */);
377
378    var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName(
379        'winheap/allocated_objects');
380    assert.equal(allocatedObjectsDump.attributes['size'].value, 2048);
381    assert.equal(allocatedObjectsDump.attributes['effective_size'].value, 0);
382    assert.lengthOf(
383        allocatedObjectsDump.children, 1 /* 'tracing_overhead' */);
384
385    var discountDump = pmd.getMemoryAllocatorDumpByFullName(
386        'winheap/allocated_objects/tracing_overhead');
387    assert.strictEqual(discountDump.parent, allocatedObjectsDump);
388    assert.include(allocatedObjectsDump.children, discountDump);
389    assert.equal(discountDump.attributes['size'].value, 2048);
390    assert.equal(discountDump.attributes['effective_size'].value, 0);
391
392    var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
393    assert.equal(tracingDump.attributes['size'].value, 2048);
394    assert.equal(tracingDump.attributes['effective_size'].value, 2048);
395    assert.strictEqual(tracingDump.owns.target, discountDump);
396  });
397
398  test('checkDiscountTracingOverhead_withMostRecentVmRegionsLinks', function() {
399    var pmds = createFinalizedProcessMemoryDumps([42, 90], function(pmds) {
400      pmds[0].totals = { residentBytes: 1000, peakResidentBytes: 2000 };
401      pmds[0].vmRegions = [
402        VMRegion.fromDict({
403          startAddress: 256,
404          sizeInBytes: 6000,
405          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
406              VMRegion.PROTECTION_FLAG_WRITE,
407          mappedFile: '[stack:20310]',
408          byteStats: {
409            privateDirtyResident: 4096
410          }
411        })
412      ];
413      pmds[0].memoryAllocatorDumps = (function() {
414        var tracingDump = new MemoryAllocatorDump(pmds[0], 'tracing');
415        tracingDump.addAttribute(
416            'resident_size', new ScalarAttribute('bytes', 100));
417        tracingDump.addAttribute(
418            'size', new ScalarAttribute('bytes', 300));
419        return [tracingDump];
420      })();
421
422      pmds[1].totals = { peakResidentBytes: 3000 };
423      pmds[1].memoryAllocatorDumps = (function() {
424        var tracingDump = new MemoryAllocatorDump(pmds[0], 'tracing');
425        tracingDump.addAttribute(
426            'resident_size', new ScalarAttribute('bytes', 200));
427        return [tracingDump];
428      })();
429    });
430
431    // First PMD: Both total resident and private dirty resident size should be
432    // reduced by 100. Virtual size should be reduced by 300.
433    assert.equal(pmds[0].totals.residentBytes, 900);
434    assert.equal(pmds[0].totals.peakResidentBytes, 1900);
435    assert.equal(pmds[0].mostRecentVmRegions[1].sizeInBytes, -300);
436    assert.equal(
437        pmds[0].getMostRecentTotalVmRegionStat('privateDirtyResident'), 3996);
438
439    // Second PMD: Total resident size should be reduced by 200, whereas private
440    // dirty resident size should be reduced by 100 (because it comes from
441    // the VM regions in the first dump). Similarly, virtual size should be
442    // reduced by 300.
443    assert.isUndefined(pmds[1].totals.residentBytes);
444    assert.equal(pmds[1].totals.peakResidentBytes, 2800);
445    assert.equal(pmds[1].mostRecentVmRegions[1].sizeInBytes, -300);
446    assert.equal(
447        pmds[1].getMostRecentTotalVmRegionStat('privateDirtyResident'), 3996);
448  });
449
450  test('checkDiscountTracingOverhead_allDiscountedVmRegionFields', function() {
451    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
452      pmd.vmRegions = [
453        VMRegion.fromDict({
454          mappedFile: '[stack]',
455          sizeInBytes: 10000,
456          byteStats: {
457            privateDirtyResident: 4096,
458            proportionalResident: 8192,
459            swapped: 1536
460          }
461        })
462      ];
463      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
464      tracingDump.addAttribute(
465          'size', new ScalarAttribute('bytes', 1000));
466      tracingDump.addAttribute(
467          'resident_size', new ScalarAttribute('bytes', 1024));
468      pmd.memoryAllocatorDumps = [tracingDump];
469    });
470
471    var vmRegions = pmd.mostRecentVmRegions;
472    assert.lengthOf(vmRegions, 2);
473
474    var regularRegion = vmRegions[0];
475    assert.equal(regularRegion.mappedFile, '[stack]');
476    assert.equal(regularRegion.sizeInBytes, 10000);
477    assert.equal(regularRegion.byteStats.privateDirtyResident, 4096);
478    assert.equal(regularRegion.byteStats.swapped, 1536);
479    assert.equal(regularRegion.byteStats.proportionalResident, 8192);
480
481    var discountedRegion = vmRegions[1];
482    assert.equal(discountedRegion.mappedFile, '[discounted tracing overhead]');
483    assert.equal(discountedRegion.sizeInBytes, -1000);
484    assert.equal(discountedRegion.byteStats.privateDirtyResident, -1024);
485    assert.isUndefined(discountedRegion.byteStats.swapped);
486    assert.equal(discountedRegion.byteStats.proportionalResident, -1024);
487  });
488
489  test('checkDiscountTracingOverhead_twoDiscountedVmRegionField', function() {
490    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
491      pmd.vmRegions = [
492        VMRegion.fromDict({
493          mappedFile: '[stack]',
494          sizeInBytes: 10000,
495          byteStats: {
496            privateDirtyResident: 4096,
497            swapped: 1536
498          }
499        })
500      ];
501      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
502      tracingDump.addAttribute(
503          'size', new ScalarAttribute('bytes', 1000));
504      tracingDump.addAttribute(
505          'resident_size', new ScalarAttribute('bytes', 1024));
506      pmd.memoryAllocatorDumps = [tracingDump];
507    });
508
509    var vmRegions = pmd.mostRecentVmRegions;
510    assert.lengthOf(vmRegions, 2);
511
512    var regularRegion = vmRegions[0];
513    assert.equal(regularRegion.mappedFile, '[stack]');
514    assert.equal(regularRegion.sizeInBytes, 10000);
515    assert.equal(regularRegion.byteStats.privateDirtyResident, 4096);
516    assert.equal(regularRegion.byteStats.swapped, 1536);
517    assert.isUndefined(regularRegion.byteStats.proportionalResident);
518
519    var discountedRegion = vmRegions[1];
520    assert.equal(discountedRegion.mappedFile, '[discounted tracing overhead]');
521    assert.equal(discountedRegion.sizeInBytes, -1000);
522    assert.equal(discountedRegion.byteStats.privateDirtyResident, -1024);
523    assert.isUndefined(discountedRegion.byteStats.swapped);
524    assert.isUndefined(discountedRegion.byteStats.proportionalResident);
525  });
526
527  test('checkDiscountTracingOverhead_oneDiscountedVmRegionField', function() {
528    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
529      pmd.vmRegions = [
530        VMRegion.fromDict({
531          mappedFile: '[stack]',
532          sizeInBytes: 10000,
533          byteStats: {}
534        })
535      ];
536      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
537      tracingDump.addAttribute(
538          'size', new ScalarAttribute('bytes', 1000));
539      tracingDump.addAttribute(
540          'resident_size', new ScalarAttribute('bytes', 1024));
541      pmd.memoryAllocatorDumps = [tracingDump];
542    });
543
544    var vmRegions = pmd.mostRecentVmRegions;
545    assert.lengthOf(vmRegions, 2);
546
547    var regularRegion = vmRegions[0];
548    assert.equal(regularRegion.mappedFile, '[stack]');
549    assert.equal(regularRegion.sizeInBytes, 10000);
550    assert.isUndefined(regularRegion.byteStats.privateDirtyResident);
551    assert.isUndefined(regularRegion.byteStats.swapped);
552    assert.isUndefined(regularRegion.byteStats.proportionalResident);
553
554    var discountedRegion = vmRegions[1];
555    assert.equal(discountedRegion.mappedFile, '[discounted tracing overhead]');
556    assert.equal(discountedRegion.sizeInBytes, -1000);
557    assert.isUndefined(discountedRegion.byteStats.privateDirtyResident);
558    assert.isUndefined(discountedRegion.byteStats.swapped);
559    assert.isUndefined(discountedRegion.byteStats.proportionalResident);
560  });
561
562  test('checkDiscountTracingOverhead_noDiscountedVmRegionFields', function() {
563    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
564      pmd.vmRegions = [
565        VMRegion.fromDict({
566          mappedFile: '[stack]',
567          byteStats: {
568            swapped: 1536
569          }
570        })
571      ];
572      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
573      tracingDump.addAttribute(
574          'resident_size', new ScalarAttribute('bytes', 1024));
575      pmd.memoryAllocatorDumps = [tracingDump];
576    });
577
578    var vmRegions = pmd.mostRecentVmRegions;
579    assert.lengthOf(vmRegions, 1);
580
581    var regularRegion = vmRegions[0];
582    assert.equal(regularRegion.mappedFile, '[stack]');
583    assert.isUndefined(regularRegion.sizeInBytes);
584    assert.isUndefined(regularRegion.byteStats.privateDirtyResident);
585    assert.equal(regularRegion.byteStats.swapped, 1536);
586    assert.isUndefined(regularRegion.byteStats.proportionalResident);
587  });
588
589  test('checkDiscountTracingOverhead_existingLink', function() {
590    var pmd = createFinalizedProcessMemoryDump(42, function(pmd) {
591      pmd.totals = { residentBytes: 10240 };
592
593      pmd.vmRegions = [
594        VMRegion.fromDict({
595          startAddress: 256,
596          sizeInBytes: 6000,
597          protectionFlags: VMRegion.PROTECTION_FLAG_READ |
598              VMRegion.PROTECTION_FLAG_WRITE,
599          mappedFile: '[stack:20310]',
600          byteStats: {
601            privateDirtyResident: 4096,
602            swapped: 1536,
603            proportionalResident: 5120
604          }
605        })
606      ];
607
608      var mallocDump = new MemoryAllocatorDump(pmd, 'malloc');
609      mallocDump.addAttribute('size', new ScalarAttribute('bytes', 3072));
610
611      var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
612      tracingDump.addAttribute(
613          'size', new ScalarAttribute('bytes', 1024));
614      tracingDump.addAttribute(
615          'resident_size', new ScalarAttribute('bytes', 1000));
616
617      var ownedDump = new MemoryAllocatorDump(pmd, 'owned');
618
619      // The code for discounting tracing overhead should *not* override an
620      // existing ownership.
621      var ownershipLink = new MemoryAllocatorDumpLink(tracingDump, ownedDump);
622      tracingDump.owns = ownershipLink;
623      ownedDump.ownedBy.push(ownershipLink);
624
625      pmd.memoryAllocatorDumps = [mallocDump, tracingDump, ownedDump];
626    });
627
628    assert.equal(pmd.totals.residentBytes, 9240);
629    assert.isUndefined(pmd.totals.peakResidentBytes);
630
631    var vmRegions = pmd.mostRecentVmRegions;
632    assert.lengthOf(vmRegions, 2);
633    var discountRegion = vmRegions[1];
634    assert.strictEqual(
635        discountRegion.mappedFile, '[discounted tracing overhead]');
636    assert.strictEqual(discountRegion.sizeInBytes, -1024);
637
638    assert.equal(
639        pmd.getMostRecentTotalVmRegionStat('privateDirtyResident'), 3096);
640    assert.equal(pmd.getMostRecentTotalVmRegionStat('swapped'), 1536);
641    assert.equal(
642        pmd.getMostRecentTotalVmRegionStat('proportionalResident'), 4120);
643
644    var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc');
645    assert.equal(mallocDump.attributes['size'].value, 3072);
646    assert.equal(mallocDump.attributes['effective_size'].value, 3072);
647    assert.lengthOf(mallocDump.children, 0);
648
649    var ownedDump = pmd.getMemoryAllocatorDumpByFullName('owned');
650    assert.equal(ownedDump.attributes['size'].value, 1024);
651    assert.equal(ownedDump.attributes['effective_size'].value, 0);
652    assert.lengthOf(ownedDump.children, 0);
653
654    var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
655    assert.equal(tracingDump.attributes['size'].value, 1024);
656    assert.equal(tracingDump.attributes['effective_size'].value, 1024);
657    assert.equal(tracingDump.attributes['resident_size'].value, 1000);
658    assert.strictEqual(tracingDump.owns.target, ownedDump);
659  });
660});
661</script>
662