| <!DOCTYPE html> |
| <!-- |
| Copyright 2016 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/core/test_utils.html"> |
| <link rel="import" href="/tracing/model/memory_dump_test_utils.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| var VMRegion = tr.model.VMRegion; |
| var VMRegionClassificationNode = tr.model.VMRegionClassificationNode; |
| var checkVMRegions = tr.model.MemoryDumpTestUtils.checkVMRegions; |
| |
| function checkProtectionFlagsToString(protectionFlags, expectedString) { |
| var vmRegion = VMRegion.fromDict({ |
| startAddress: 256, |
| sizeInBytes: 336, |
| protectionFlags: protectionFlags, |
| mappedFile: '[stack:20310]', |
| byteStats: { |
| privateDirtyResident: 96, |
| swapped: 144, |
| proportionalResident: 158 |
| } |
| }); |
| assert.strictEqual(vmRegion.protectionFlagsToString, expectedString); |
| } |
| |
| var TEST_RULES = { |
| name: 'Root', |
| children: [ |
| { |
| name: 'Words', |
| file: /^[a-zA-Z]/, |
| children: [ |
| { |
| name: 'A-D', |
| file: /^[a-dA-D]/ |
| }, |
| { |
| name: 'E-H', |
| file: /^[e-hE-H]/ |
| } |
| ] |
| }, |
| { |
| name: 'Digits', |
| file: /\d$/, |
| children: [] |
| } |
| ] |
| }; |
| |
| // Constant representing the expectation that the children of a |
| // VMRegionClassificationNode have not been built yet. |
| var CHILDREN_NOT_BUILT_YET = {}; |
| |
| function checkTree(node, expectedStructure) { |
| assert.strictEqual(node.title, expectedStructure.title); |
| assert.strictEqual(node.hasRegions, expectedStructure.hasRegions); |
| assert.strictEqual(node.sizeInBytes, expectedStructure.sizeInBytes); |
| assert.deepEqual(node.byteStats, expectedStructure.byteStats || {}); |
| assert.strictEqual(node.isLeafNode, expectedStructure.isLeafNode); |
| |
| var actualRegions = node.regions; |
| var expectedRegions = expectedStructure.regions; |
| if (expectedRegions === undefined) { |
| assert.isUndefined(actualRegions); |
| } else { |
| assert.instanceOf(actualRegions, Array); |
| checkVMRegions(actualRegions, expectedRegions); |
| } |
| |
| var expectedChildren = expectedStructure.children; |
| if (expectedChildren === CHILDREN_NOT_BUILT_YET) { |
| assert.isUndefined(node.children_); |
| } else if (expectedChildren === undefined) { |
| assert.isUndefined(node.children); |
| } else { |
| var actualChildrenMap = new Map(); |
| node.children.forEach(function(childNode) { |
| actualChildrenMap.set(childNode.title, childNode); |
| }); |
| var expectedChildrenMap = new Map(); |
| expectedChildren.forEach(function(childNode) { |
| expectedChildrenMap.set(childNode.title, childNode); |
| }); |
| assert.strictEqual(actualChildrenMap.size, expectedChildrenMap.size); |
| for (var title of expectedChildrenMap.keys()) { |
| checkTree(actualChildrenMap.get(title), |
| expectedChildrenMap.get(title)); |
| } |
| } |
| } |
| |
| function checkClassificationRules(mappedFile, expectedPath) { |
| var region = VMRegion.fromDict({ |
| mappedFile: mappedFile, |
| sizeInBytes: 16, |
| byteStats: { |
| privateDirtyResident: 7 |
| } |
| }); |
| var node = VMRegionClassificationNode.fromRegions([region]); |
| expectedPath.forEach(function(title) { |
| node = tr.b.findFirstInArray(node.children, function(childNode) { |
| return childNode.title === title; |
| }); |
| }); |
| assert.deepEqual(node.regions, [region]); |
| } |
| |
| test('vmRegion_protectionFlagsToString', function() { |
| checkProtectionFlagsToString(undefined, undefined); |
| checkProtectionFlagsToString(0, '---p'); |
| checkProtectionFlagsToString(VMRegion.PROTECTION_FLAG_READ, 'r--p'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_MAYSHARE, |
| 'r--s'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_EXECUTE, |
| 'r-xp'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE, |
| 'rw-p'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| 'rwxp'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE | |
| VMRegion.PROTECTION_FLAG_MAYSHARE, |
| 'rw-s'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_EXECUTE | |
| VMRegion.PROTECTION_FLAG_MAYSHARE, |
| 'r-xs'); |
| checkProtectionFlagsToString( |
| VMRegion.PROTECTION_FLAG_READ | VMRegion.PROTECTION_FLAG_WRITE | |
| VMRegion.PROTECTION_FLAG_EXECUTE | |
| VMRegion.PROTECTION_FLAG_MAYSHARE, |
| 'rwxs'); |
| }); |
| |
| // The add(After|Before)Build tests below check that the classification tree |
| // has the correct structure regardless of the ordering of adding regions and |
| // the lazy construction. |
| |
| test('vmRegionClassificationNode_constructor_addAfterBuild', function() { |
| var rootNode = new VMRegionClassificationNode(TEST_RULES); |
| |
| // Check the root node and verify that the full tree structure has *not* |
| // been constructed yet. |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: false, |
| isLeafNode: false, |
| children: CHILDREN_NOT_BUILT_YET |
| }); |
| |
| // Reading the children of the root node *should* trigger building the |
| // full tree. |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: false, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: false, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| } |
| ] |
| }); |
| |
| // Add VM regions to the tree *after* it has been fully built. |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'W2', // Root/Words/Other. |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 77, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'W2', |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| }); |
| |
| test('vmRegionClassificationNode_constructor_addBeforeBuild', function() { |
| var rootNode = new VMRegionClassificationNode(TEST_RULES); |
| |
| // Add regions to the tree *before* it has been fully built. This should |
| // *not* trigger building the full tree (but the total sizeInBytes and |
| // byteStats should be updated accordingly). |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'W2', // Root/Words/Other. |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 77, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: CHILDREN_NOT_BUILT_YET |
| }); |
| |
| // Reading the children of the root node should trigger building the full |
| // tree. |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 77, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'W2', |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| |
| // Add more VM regions *after* the tree has been fully built. |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '%invalid%', // Root/Other. |
| sizeInBytes: 123 |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__43', // Root/Digits. |
| byteStats: { |
| swapped: 19 |
| } |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'free', // Root/Words/E-H. |
| sizeInBytes: undefined |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 16 + 123, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 77, |
| swapped: 64 + 19, |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: true, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'free' |
| } |
| ] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'W2', |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77, |
| swapped: 19 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }, |
| { |
| mappedFile: '__43', |
| byteStats: { |
| swapped: 19 |
| } |
| } |
| ] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 123, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '%invalid%', |
| sizeInBytes: 123 |
| } |
| ] |
| } |
| ] |
| }); |
| }); |
| |
| test('vmRegionClassificationNode_fromRegions_addAfterBuild', function() { |
| // Construct the root node from a list of regions. This should *not* |
| // trigger building the full tree (but the total sizeInBytes and byteStats |
| // should be updated accordingly). |
| var rootNode = VMRegionClassificationNode.fromRegions([ |
| VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '__43', // Root/Digits. |
| byteStats: { |
| swapped: 19 |
| } |
| }) |
| ], TEST_RULES); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77, |
| swapped: 19 |
| }, |
| isLeafNode: false, |
| children: CHILDREN_NOT_BUILT_YET |
| }); |
| |
| // Reading the children of the root node should trigger building the full |
| // tree. |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77, |
| swapped: 19 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: false, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77, |
| swapped: 19 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }, |
| { |
| mappedFile: '__43', |
| byteStats: { |
| swapped: 19 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| |
| // Add more VM regions *after* the tree has been fully built. |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'W2', // Root/Words/Other. |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 77, |
| swapped: 19 + 64, |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'W2', |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77, |
| swapped: 19 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }, |
| { |
| mappedFile: '__43', |
| byteStats: { |
| swapped: 19 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| }); |
| |
| test('vmRegionClassificationNode_fromRegions_addBeforeBuild', function() { |
| // Construct the root node from a list of regions and then add another |
| // region. This should *not* trigger building the full tree (but the total |
| // sizeInBytes and byteStats should be updated accordingly). |
| var rootNode = VMRegionClassificationNode.fromRegions([ |
| VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '__43', // Root/Digits. |
| byteStats: { |
| swapped: 19 |
| } |
| }) |
| ], TEST_RULES); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| startAddress: 2048, // Necessary to distinguish from the first region. |
| sizeInBytes: 1000, |
| byteStats: { |
| privateDirtyResident: 500 |
| } |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 1000, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 + 500, |
| swapped: 19 |
| }, |
| isLeafNode: false, |
| children: CHILDREN_NOT_BUILT_YET |
| }); |
| |
| // Reading the children of the root node should trigger building the full |
| // tree. |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 1000, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 + 500, |
| swapped: 19 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: false, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| sizeInBytes: 1000, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 + 500, |
| swapped: 19 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }, |
| { |
| mappedFile: '__43', |
| byteStats: { |
| swapped: 19 |
| } |
| }, |
| { |
| mappedFile: '__42', |
| startAddress: 2048, |
| sizeInBytes: 1000, |
| byteStats: { |
| privateDirtyResident: 500 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| |
| // Add more VM regions *after* the tree has been fully built. |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'W2', // Root/Words/Other. |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| })); |
| checkTree(rootNode, { |
| title: 'Root', |
| hasRegions: true, |
| sizeInBytes: 1000 + 16, |
| byteStats: { |
| proportionalResident: 32 + 33, |
| privateDirtyResident: 500 + 77, |
| swapped: 19 + 64, |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'Words', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: false, |
| children: [ |
| { |
| title: 'A-D', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'E-H', |
| hasRegions: false, |
| isLeafNode: true, |
| regions: [] |
| }, |
| { |
| title: 'Other', |
| hasRegions: true, |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: 'W2', |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| { |
| title: 'Digits', |
| hasRegions: true, |
| sizeInBytes: 1000, |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 500 + 77, |
| swapped: 19 |
| }, |
| isLeafNode: true, |
| regions: [ |
| { |
| mappedFile: '__42', |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| }, |
| { |
| mappedFile: '__43', |
| byteStats: { |
| swapped: 19 |
| } |
| }, |
| { |
| mappedFile: '__42', |
| startAddress: 2048, |
| sizeInBytes: 1000, |
| byteStats: { |
| privateDirtyResident: 500 |
| } |
| } |
| ] |
| } |
| ] |
| }); |
| }); |
| |
| test('vmRegionClassificationNode_someRegion', function() { |
| var rootNode = new VMRegionClassificationNode(TEST_RULES); |
| |
| // There are no regions in the tree, so the method should always return |
| // false. |
| assert.isFalse(rootNode.someRegion(function(region) { |
| throw new Error('There are no regions in the tree!!!'); |
| })); |
| |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: 'W2', // Root/Words/Other. |
| sizeInBytes: 16, |
| byteStats: { |
| proportionalResident: 32, |
| swapped: 64 |
| } |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__42', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| })); |
| rootNode.addRegion(VMRegion.fromDict({ |
| mappedFile: '__43', // Root/Digits. |
| byteStats: { |
| proportionalResident: 33, |
| privateDirtyResident: 77 |
| } |
| })); |
| |
| function checkSomeRegion() { |
| // Find the order in which the regions are traversed and checked that all |
| // regions were visited. |
| var visitedRegionMappedFiles = []; |
| assert.isFalse(rootNode.someRegion(function(region) { |
| visitedRegionMappedFiles.push(region.mappedFile); |
| return false; |
| })); |
| assert.lengthOf(visitedRegionMappedFiles, 3); |
| assert.sameMembers(visitedRegionMappedFiles, ['W2', '__42', '__43']); |
| |
| // Assuming the traversal order is deterministic, we check that once the |
| // callback returns true, no further regions are visited. |
| visitedRegionMappedFiles.forEach( |
| function(mappedFileToMatch, index) { |
| var visitedRegionMappedFiles2 = []; |
| assert.isTrue(rootNode.someRegion(function(region) { |
| this.files.push(region.mappedFile); |
| return region.mappedFile === mappedFileToMatch; |
| }, { files: visitedRegionMappedFiles2 } /* opt_this */)); |
| assert.deepEqual(visitedRegionMappedFiles2, |
| visitedRegionMappedFiles.slice(0, index + 1)); |
| }); |
| } |
| |
| // Before lazy construction (single node with a flat list of regions). |
| checkSomeRegion(); |
| assert.isUndefined(rootNode.children_); |
| |
| // After lazy construction (tree of nodes with lists of regions). |
| assert.isDefined(rootNode.children); // Force building the tree. |
| assert.isDefined(rootNode.children_); |
| checkSomeRegion(); |
| }); |
| |
| test('classificationRules', function() { |
| checkClassificationRules('/dev/ashmem/dalvik-main space (deleted)', |
| ['Android', 'Java runtime', 'Spaces', 'Normal']); |
| checkClassificationRules('/dev/ashmem/dalvik-non moving space', |
| ['Android', 'Java runtime', 'Spaces', 'Non-moving']); |
| checkClassificationRules('/dev/ashmem/dalvik-zygote space (deleted)', |
| ['Android', 'Java runtime', 'Spaces', 'Zygote']); |
| checkClassificationRules('/dev/ashmem/dalvik-allocation stack (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules( |
| '/dev/ashmem/dalvik-allocspace main rosalloc space 1 live-bitmap 2', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules( |
| '/dev/ashmem/dalvik-allocspace non moving space live-bitmap 4', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-allocspace zygote / ' + |
| 'non moving space live-bitmap 0 (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-card table (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-large live objects (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-live stack (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules( |
| '/dev/ashmem/dalvik-mark sweep sweep array free buffer (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-rosalloc page map (deleted)', |
| ['Android', 'Java runtime', 'Accounting']); |
| checkClassificationRules('/dev/ashmem/dalvik-indirect ref table (deleted)', |
| ['Android', 'Java runtime', 'Indirect Reference Table']); |
| checkClassificationRules('/dev/ashmem/dalvik-LinearAlloc (deleted)', |
| ['Android', 'Java runtime', 'Linear Alloc']); |
| checkClassificationRules('/dev/ashmem/dalvik-jit-code-cache (deleted)', |
| ['Android', 'Java runtime', 'Cache']); |
| checkClassificationRules('/dev/ashmem/CursorWindow (deleted)', |
| ['Android', 'Cursor']); |
| checkClassificationRules('/dev/ashmem (deleted)', ['Android', 'Ashmem']); |
| checkClassificationRules('/dev/ashmem/GFXStats-10082', |
| ['Android', 'Ashmem']); |
| |
| checkClassificationRules('[stack:23164]', ['Stack']); |
| checkClassificationRules('[stack]', ['Stack']); |
| |
| checkClassificationRules('[discounted tracing overhead]', ['Native heap']); |
| checkClassificationRules('', ['Native heap']); |
| checkClassificationRules('[heap]', ['Native heap']); |
| checkClassificationRules('[anon:libc_malloc]', ['Native heap']); |
| checkClassificationRules('[anon:thread signal stack]', ['Native heap']); |
| checkClassificationRules('/dev/ashmem/libc malloc (deleted)', |
| ['Native heap']); |
| |
| checkClassificationRules('/usr/lib/nvidia-340/libGL.so.331.79', |
| ['Files', 'so']); |
| checkClassificationRules('/usr/lib/x86_64-linux-gnu/libibus-1.0.so.5.0.505', |
| ['Files', 'so']); |
| checkClassificationRules('/data/data/com.google.android.apps.chrome/' + |
| 'app_chrome/RELRO:libchrome.so (deleted)', ['Files', 'so']); |
| checkClassificationRules( |
| '/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf', |
| ['Files', 'ttf']); |
| checkClassificationRules( |
| '/data/app/com.google.android.apps.chrome-2/base.apk', |
| ['Files', 'apk']); |
| checkClassificationRules( |
| '/data/app/com.google.android.apps.chrome-2/lib/arm/libchrome.so', |
| ['Files', 'so']); |
| checkClassificationRules( |
| '/data/app/com.google.android.apps.chrome-2/oat/arm/base.odex', |
| ['Files', 'dex']); |
| checkClassificationRules( |
| '/data/dalvik-cache/arm/system@framework@boot.art', ['Files', 'art']); |
| checkClassificationRules( |
| '/data/dalvik-cache/arm/system@framework@boot.oat', ['Files', 'oat']); |
| |
| checkClassificationRules('/dev/nvidia0', ['Devices', 'GPU']); |
| checkClassificationRules('/dev/kgsl-3d0', ['Devices', 'GPU']); |
| checkClassificationRules('anon_inode:dmabuf', ['Devices', 'DMA']); |
| checkClassificationRules('/dev/binder', ['Devices', 'Other']); |
| |
| checkClassificationRules('/src/out/Release/chrome', ['Other']); |
| checkClassificationRules('/tmp/gluY4SVp (deleted)', ['Other']); |
| checkClassificationRules('/src/out/Release/resources.pak', ['Other']); |
| checkClassificationRules('[vdso]', ['Other']); |
| checkClassificationRules('[vsyscall]', ['Other']); |
| checkClassificationRules('[vectors]', ['Other']); |
| checkClassificationRules('[vvar]', ['Other']); |
| }); |
| }); |
| </script> |