1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { AllocationFunction } from '../model/UiStruct.js'; 17import { FileStruct, HeapTraceFunctionInfo } from '../model/DatabaseStruct.js'; 18 19export class AllocationLogic { 20 private fileStruct: FileStruct; 21 private traceNodes: Array<AllocationFunction>; 22 private bottomUpList: Array<AllocationFunction>; 23 24 constructor(fileStruct: FileStruct) { 25 this.fileStruct = fileStruct; 26 this.bottomUpList = []; 27 this.traceNodes = this.fileStruct.snapshotStruct.traceNodes; 28 this.setBottomUpTree(); 29 } 30 31 private setBottomUpTree() { 32 let keyMap = new Map<String, AllocationFunction>(); 33 for (let node of this.traceNodes) { 34 if (node.parentsId.length > 1) { 35 node.hasParent = true; 36 } else if (node.parentsId.length == 0) { 37 node.hasParent = false; 38 } else { 39 if (node.parentsId[0] == -1) { 40 node.hasParent = false; 41 } else { 42 node.hasParent = true; 43 } 44 } 45 // combine node 46 if (keyMap.has(node.name + node.functionIndex)) { 47 let uniqueNode = keyMap.get(node.name + node.functionIndex); 48 if (!uniqueNode) continue; 49 uniqueNode.size += node.size; 50 uniqueNode.count += node.count; 51 uniqueNode.liveSize += node.liveSize; 52 uniqueNode.liveCount += node.liveCount; 53 uniqueNode.parentsId.push(...node.parentsId); 54 uniqueNode.combineId.add(uniqueNode.id); 55 uniqueNode.combineId.add(node.id); 56 } else { 57 keyMap.set(node.name + node.functionIndex, node); 58 node.combineId.add(node.id); 59 this.bottomUpList.push(node); 60 } 61 } 62 this.bottomUpList.sort(function (a, b) { 63 return b.size - a.size; 64 }); 65 } 66 67 private getNodeById(id: number): AllocationFunction | null { 68 for (let func of this.bottomUpList) { 69 if (func.id == id) { 70 return func; 71 } 72 } 73 return null; 74 } 75 76 private getFunctionStack(node: AllocationFunction, functionList: Array<HeapTraceFunctionInfo>) { 77 functionList.push(this.fileStruct.snapshotStruct.functionInfos[node.functionIndex]); 78 if (node.parentsId.length > 0) { 79 for (let parentId of node.parentsId) { 80 let parentNode = this.getNodeById(parentId); 81 if (parentNode) { 82 this.getFunctionStack(parentNode, functionList); 83 } 84 } 85 } 86 } 87 88 /** 89 * get Bottom Up FUnction List 90 * @returns bottomUpList 91 */ 92 public getFunctionList(): Array<AllocationFunction> { 93 return this.bottomUpList; 94 } 95 96 /** 97 * set node parents node 98 * node has multi parent because bottom up combine multi node 99 * @param node selected node 100 */ 101 public getParent(node: AllocationFunction) { 102 if (node.hasParent) { 103 if (node.parentsId.length > 1) { 104 for (let childrenId of node.parentsId) { 105 let children = this.traceNodes[childrenId - 1].clone(); 106 children.size = node.size; 107 children.count = node.count; 108 children.liveSize = node.liveSize; 109 children.liveCount = node.liveCount; 110 node.parents.push(children); 111 } 112 } else if ((node.parentsId.length = 1)) { 113 let childrenId = node.parentsId[0]; 114 if (!node.parents) node.parents = new Array<AllocationFunction>(); 115 let children = this.traceNodes[childrenId - 1].clone(); 116 children.size = node.size; 117 children.count = node.count; 118 children.liveSize = node.liveSize; 119 children.liveCount = node.liveCount; 120 node.parents.push(children); 121 this.getParent(children); 122 } else { 123 // no need to do anything 124 } 125 } 126 } 127 128 /** 129 * get use bottom up method combine's node ids 130 * @param allocationNodeId node id 131 * @returns node combine id 132 */ 133 public getFunctionNodeIds(allocationNodeId: number): Array<number> { 134 let node = this.getNodeById(allocationNodeId); 135 if (node) { 136 return Array.from(node.combineId); 137 } else { 138 return []; 139 } 140 } 141 142 /** 143 * get full stack for node 144 * @param allocationNodeId node.traceNodeId 145 * @returns stack list 146 */ 147 public getNodeStack(allocationNodeId: number): Array<HeapTraceFunctionInfo> { 148 let currentNode = this.getNodeById(allocationNodeId); 149 let functionList = new Array<HeapTraceFunctionInfo>(); 150 if (currentNode) { 151 this.getFunctionStack(currentNode, functionList); 152 } 153 return functionList; 154 } 155} 156