blob: a9034bff7e0d9dd559fddeb7dbfdfb7163d25313 [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {mergeCallsites} from './flamegraph_util';
import {CallsiteInfo} from './state';
test('zeroCallsitesMerged', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 4,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 2,
name: 'B4',
depth: 1,
totalSize: 4,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 5);
// Small callsites are not next ot each other, nothing should be changed.
expect(mergedCallsites).toEqual(callsites);
});
test('zeroCallsitesMerged2', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 6,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 4,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 5,
parentId: 2,
name: 'B5',
depth: 1,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 5);
// Small callsites are not next ot each other, nothing should be changed.
expect(mergedCallsites).toEqual(callsites);
});
test('twoCallsitesMerged', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 6);
expect(mergedCallsites).toEqual([
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: '[merged]',
depth: 1,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
]);
});
test('manyCallsitesMerged', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 3,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 5,
parentId: 1,
name: 'A5',
depth: 1,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 6,
parentId: 3,
name: 'A36',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 7,
parentId: 4,
name: 'A47',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 8,
parentId: 5,
name: 'A58',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const expectedMergedCallsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: '[merged]',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 6,
parentId: 3,
name: '[merged]',
depth: 2,
totalSize: 3,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 4);
// In this case, callsites A3, A4 and A5 should be merged since they are
// smaller then 4 and are on same depth with same parent. Callsites A36, A47
// and A58 should also be merged since their parents are merged.
expect(mergedCallsites).toEqual(expectedMergedCallsites);
});
test('manyCallsitesMergedWithoutChildren', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 3,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 5,
parentId: 1,
name: 'A5',
depth: 1,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 6,
parentId: 2,
name: 'B6',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 7,
parentId: 4,
name: 'A47',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 8,
parentId: 6,
name: 'B68',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const expectedMergedCallsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: '[merged]',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 6,
parentId: 2,
name: 'B6',
depth: 1,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 7,
parentId: 3,
name: 'A47',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 8,
parentId: 6,
name: 'B68',
depth: 2,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 4);
// In this case, callsites A3, A4 and A5 should be merged since they are
// smaller then 4 and are on same depth with same parent. Callsite A47
// should not be merged with B68 althought they are small because they don't
// have sam parent. A47 should now have parent A3 because A4 is merged.
expect(mergedCallsites).toEqual(expectedMergedCallsites);
});
test('smallCallsitesNotNextToEachOtherInArray', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 20,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 1,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 5,
parentId: 1,
name: 'A5',
depth: 1,
totalSize: 3,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const expectedMergedCallsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 20,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: '[merged]',
depth: 1,
totalSize: 4,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 8,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 4);
// In this case, callsites A3, A4 and A5 should be merged since they are
// smaller then 4 and are on same depth with same parent. Callsite A47
// should not be merged with B68 althought they are small because they don't
// have sam parent. A47 should now have parent A3 because A4 is merged.
expect(mergedCallsites).toEqual(expectedMergedCallsites);
});
test('smallCallsitesNotMerged', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: 1,
name: 'A2',
depth: 1,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 1);
expect(mergedCallsites).toEqual(callsites);
});
test('mergingRootCallsites', () => {
const callsites: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const mergedCallsites = mergeCallsites(callsites, 20);
expect(mergedCallsites).toEqual([
{
id: 1,
parentId: -1,
name: '[merged]',
depth: 0,
totalSize: 12,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
]);
});
test('largerFlamegraph', () => {
const data: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 60,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 40,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 25,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: 'A4',
depth: 1,
totalSize: 15,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 5,
parentId: 1,
name: 'A5',
depth: 1,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 6,
parentId: 1,
name: 'A6',
depth: 1,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 7,
parentId: 2,
name: 'B7',
depth: 1,
totalSize: 30,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 8,
parentId: 2,
name: 'B8',
depth: 1,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 9,
parentId: 3,
name: 'A39',
depth: 2,
totalSize: 20,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 10,
parentId: 4,
name: 'A410',
depth: 2,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 11,
parentId: 4,
name: 'A411',
depth: 2,
totalSize: 3,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 12,
parentId: 4,
name: 'A412',
depth: 2,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 13,
parentId: 5,
name: 'A513',
depth: 2,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 14,
parentId: 5,
name: 'A514',
depth: 2,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 15,
parentId: 7,
name: 'A715',
depth: 2,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 16,
parentId: 7,
name: 'A716',
depth: 2,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 17,
parentId: 7,
name: 'A717',
depth: 2,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 18,
parentId: 7,
name: 'A718',
depth: 2,
totalSize: 5,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 19,
parentId: 9,
name: 'A919',
depth: 3,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 20,
parentId: 17,
name: 'A1720',
depth: 3,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
const expectedData: CallsiteInfo[] = [
{
id: 1,
parentId: -1,
name: 'A',
depth: 0,
totalSize: 60,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 2,
parentId: -1,
name: 'B',
depth: 0,
totalSize: 40,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 3,
parentId: 1,
name: 'A3',
depth: 1,
totalSize: 25,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 4,
parentId: 1,
name: '[merged]',
depth: 1,
totalSize: 35,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 7,
parentId: 2,
name: 'B7',
depth: 1,
totalSize: 30,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 8,
parentId: 2,
name: 'B8',
depth: 1,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 9,
parentId: 3,
name: 'A39',
depth: 2,
totalSize: 20,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 10,
parentId: 4,
name: '[merged]',
depth: 2,
totalSize: 25,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 15,
parentId: 7,
name: '[merged]',
depth: 2,
totalSize: 25,
selfSize: 0,
mapping: 'x',
merged: true,
highlighted: false,
},
{
id: 19,
parentId: 9,
name: 'A919',
depth: 3,
totalSize: 10,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
{
id: 20,
parentId: 15,
name: 'A1720',
depth: 3,
totalSize: 2,
selfSize: 0,
mapping: 'x',
merged: false,
highlighted: false,
},
];
// In this case, on depth 1, callsites A4, A5 and A6 should be merged and
// initiate merging of their children A410, A411, A412, A513, A514. On depth2,
// callsites A715, A716, A717 and A718 should be merged.
const actualData = mergeCallsites(data, 16);
expect(actualData).toEqual(expectedData);
});