1fb726d48Sopenharmony_ci/* 2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License. 5fb726d48Sopenharmony_ci * You may obtain a copy of the License at 6fb726d48Sopenharmony_ci * 7fb726d48Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fb726d48Sopenharmony_ci * 9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and 13fb726d48Sopenharmony_ci * limitations under the License. 14fb726d48Sopenharmony_ci */ 15fb726d48Sopenharmony_ci 16fb726d48Sopenharmony_ciimport { HeapLoader } from './logic/HeapLoader'; 17fb726d48Sopenharmony_ciimport { 18fb726d48Sopenharmony_ci AllocationFunction, 19fb726d48Sopenharmony_ci ConstructorComparison, 20fb726d48Sopenharmony_ci ConstructorItem, 21fb726d48Sopenharmony_ci ConstructorType, 22fb726d48Sopenharmony_ci FileInfo, 23fb726d48Sopenharmony_ci} from './model/UiStruct'; 24fb726d48Sopenharmony_ciimport { HeapNodeToConstructorItem } from './utils/Utils'; 25fb726d48Sopenharmony_ciimport { FileStruct, HeapSample, HeapTraceFunctionInfo } from './model/DatabaseStruct'; 26fb726d48Sopenharmony_ci 27fb726d48Sopenharmony_ciexport interface ParseListener { 28fb726d48Sopenharmony_ci parseDone(fileModule: Array<FileInfo>): void; 29fb726d48Sopenharmony_ci} 30fb726d48Sopenharmony_ci 31fb726d48Sopenharmony_ciexport class HeapDataInterface { 32fb726d48Sopenharmony_ci private static instance: HeapDataInterface; 33fb726d48Sopenharmony_ci private isParseDone = false; 34fb726d48Sopenharmony_ci private parseListener!: ParseListener; 35fb726d48Sopenharmony_ci private fileStructs!: Array<FileStruct>; 36fb726d48Sopenharmony_ci private baseFileStruct!: FileStruct | null; 37fb726d48Sopenharmony_ci 38fb726d48Sopenharmony_ci public static getInstance(): HeapDataInterface { 39fb726d48Sopenharmony_ci if (!this.instance) { 40fb726d48Sopenharmony_ci this.instance = new HeapDataInterface(); 41fb726d48Sopenharmony_ci } 42fb726d48Sopenharmony_ci return this.instance; 43fb726d48Sopenharmony_ci } 44fb726d48Sopenharmony_ci 45fb726d48Sopenharmony_ci private getFileStructById(id: number): FileStruct | null { 46fb726d48Sopenharmony_ci for (let fileStruct of this.fileStructs) { 47fb726d48Sopenharmony_ci if (fileStruct.id === id) { 48fb726d48Sopenharmony_ci return fileStruct; 49fb726d48Sopenharmony_ci } 50fb726d48Sopenharmony_ci } 51fb726d48Sopenharmony_ci return null; 52fb726d48Sopenharmony_ci } 53fb726d48Sopenharmony_ci 54fb726d48Sopenharmony_ci /** 55fb726d48Sopenharmony_ci * tell interface current file to provider file interface 56fb726d48Sopenharmony_ci * @param fileId file id 57fb726d48Sopenharmony_ci */ 58fb726d48Sopenharmony_ci public setFileId(fileId: number): void { 59fb726d48Sopenharmony_ci this.baseFileStruct = this.getFileStructById(fileId); 60fb726d48Sopenharmony_ci } 61fb726d48Sopenharmony_ci 62fb726d48Sopenharmony_ci /** 63fb726d48Sopenharmony_ci * set ParseListener to callback when node_files table in database is parse done 64fb726d48Sopenharmony_ci * @param listener callback 65fb726d48Sopenharmony_ci */ 66fb726d48Sopenharmony_ci public setPraseListener(listener: ParseListener): void { 67fb726d48Sopenharmony_ci this.parseListener = listener; 68fb726d48Sopenharmony_ci } 69fb726d48Sopenharmony_ci 70fb726d48Sopenharmony_ci /** 71fb726d48Sopenharmony_ci * obtain the list of Constructor classes 72fb726d48Sopenharmony_ci * @returns Array<ConstructorItem> 73fb726d48Sopenharmony_ci */ 74fb726d48Sopenharmony_ci public getClassesListForSummary(fileId: number, minNodeId?: number, maxNodeId?: number): Array<ConstructorItem> { 75fb726d48Sopenharmony_ci let constructorMap; 76fb726d48Sopenharmony_ci let constructorList: ConstructorItem[] = []; 77fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); 78fb726d48Sopenharmony_ci if (this.isParseDone && filStruct) { 79fb726d48Sopenharmony_ci constructorMap = filStruct.heapLoader.getClassesForSummary(minNodeId, maxNodeId); 80fb726d48Sopenharmony_ci constructorMap.forEach((construct, _) => { 81fb726d48Sopenharmony_ci constructorList.push(construct); 82fb726d48Sopenharmony_ci }); 83fb726d48Sopenharmony_ci constructorList.sort(function (a, b) { 84fb726d48Sopenharmony_ci return b.retainedSize - a.retainedSize; 85fb726d48Sopenharmony_ci }); 86fb726d48Sopenharmony_ci } 87fb726d48Sopenharmony_ci return constructorList; 88fb726d48Sopenharmony_ci } 89fb726d48Sopenharmony_ci 90fb726d48Sopenharmony_ci /** 91fb726d48Sopenharmony_ci * compare base file and target file, calculate delta size and count to target class 92fb726d48Sopenharmony_ci * @param baseFileId current file id 93fb726d48Sopenharmony_ci * @param targetFileId select id which file is to compare 94fb726d48Sopenharmony_ci * @returns diff class list 95fb726d48Sopenharmony_ci */ 96fb726d48Sopenharmony_ci public getClassListForComparison(baseFileId: number, targetFileId: number): Array<ConstructorComparison> { 97fb726d48Sopenharmony_ci let baseFileStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(baseFileId); 98fb726d48Sopenharmony_ci let targetFileStruct = this.getFileStructById(targetFileId); 99fb726d48Sopenharmony_ci if (!baseFileStruct || !targetFileStruct) { 100fb726d48Sopenharmony_ci return []; 101fb726d48Sopenharmony_ci } 102fb726d48Sopenharmony_ci let diffClassList: ConstructorComparison[] = []; 103fb726d48Sopenharmony_ci let diffClassMap = baseFileStruct.heapLoader.getClassesForComparison( 104fb726d48Sopenharmony_ci targetFileId, 105fb726d48Sopenharmony_ci targetFileStruct.heapLoader.getClassesForSummary() 106fb726d48Sopenharmony_ci ); 107fb726d48Sopenharmony_ci if (!diffClassMap || diffClassMap.size === 0) { 108fb726d48Sopenharmony_ci return []; 109fb726d48Sopenharmony_ci } 110fb726d48Sopenharmony_ci 111fb726d48Sopenharmony_ci for (let diffClass of diffClassMap.values()) { 112fb726d48Sopenharmony_ci diffClassList.push(diffClass); 113fb726d48Sopenharmony_ci } 114fb726d48Sopenharmony_ci diffClassList.sort((a, b) => b.addedSize - a.addedSize); 115fb726d48Sopenharmony_ci return diffClassList; 116fb726d48Sopenharmony_ci } 117fb726d48Sopenharmony_ci 118fb726d48Sopenharmony_ci /** 119fb726d48Sopenharmony_ci * get sample data for timeline 120fb726d48Sopenharmony_ci * @param fileId timeline file id 121fb726d48Sopenharmony_ci * @returns time stamp with size 122fb726d48Sopenharmony_ci */ 123fb726d48Sopenharmony_ci public getSamples(fileId: number): Array<HeapSample> { 124fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); 125fb726d48Sopenharmony_ci if (!filStruct) { 126fb726d48Sopenharmony_ci return []; 127fb726d48Sopenharmony_ci } 128fb726d48Sopenharmony_ci let samples = filStruct.snapshotStruct.samples; 129fb726d48Sopenharmony_ci return samples; 130fb726d48Sopenharmony_ci } 131fb726d48Sopenharmony_ci 132fb726d48Sopenharmony_ci /** 133fb726d48Sopenharmony_ci * get the functions which call the node 134fb726d48Sopenharmony_ci * @param node current select node 135fb726d48Sopenharmony_ci * @returns node.parent 136fb726d48Sopenharmony_ci */ 137fb726d48Sopenharmony_ci public getParentFunction(node: AllocationFunction): void { 138fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); 139fb726d48Sopenharmony_ci if (!filStruct) { 140fb726d48Sopenharmony_ci return; 141fb726d48Sopenharmony_ci } 142fb726d48Sopenharmony_ci filStruct.heapLoader.loadAllocationParent(node); 143fb726d48Sopenharmony_ci } 144fb726d48Sopenharmony_ci 145fb726d48Sopenharmony_ci /** 146fb726d48Sopenharmony_ci * get select node children while node type is class 147fb726d48Sopenharmony_ci * @param node current select node 148fb726d48Sopenharmony_ci * @returns node.children 149fb726d48Sopenharmony_ci */ 150fb726d48Sopenharmony_ci public getNextForConstructor(node: ConstructorItem): Array<ConstructorItem> { 151fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); 152fb726d48Sopenharmony_ci let children: ConstructorItem[] = []; 153fb726d48Sopenharmony_ci switch (node.type) { 154fb726d48Sopenharmony_ci case ConstructorType.ClassType: 155fb726d48Sopenharmony_ci children = node.classChildren; 156fb726d48Sopenharmony_ci break; 157fb726d48Sopenharmony_ci case ConstructorType.InstanceType: 158fb726d48Sopenharmony_ci case ConstructorType.FiledType: 159fb726d48Sopenharmony_ci children = filStruct!.heapLoader.getNextNode(node); 160fb726d48Sopenharmony_ci break; 161fb726d48Sopenharmony_ci } 162fb726d48Sopenharmony_ci return children; 163fb726d48Sopenharmony_ci } 164fb726d48Sopenharmony_ci 165fb726d48Sopenharmony_ci public getNextForComparison(comparisonNode: ConstructorComparison): Array<ConstructorItem> { 166fb726d48Sopenharmony_ci let baseFileStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(comparisonNode.fileId); 167fb726d48Sopenharmony_ci let targetFileStruct = this.getFileStructById(comparisonNode.targetFileId); 168fb726d48Sopenharmony_ci if (!baseFileStruct || !targetFileStruct) { 169fb726d48Sopenharmony_ci return []; 170fb726d48Sopenharmony_ci } 171fb726d48Sopenharmony_ci let children: ConstructorItem[] = []; 172fb726d48Sopenharmony_ci if (comparisonNode.type === ConstructorType.ComparisonType) { 173fb726d48Sopenharmony_ci for (let idx of comparisonNode.addedIndx) { 174fb726d48Sopenharmony_ci let node = baseFileStruct.heapLoader.getNodes()[idx]; 175fb726d48Sopenharmony_ci let compareNode = HeapNodeToConstructorItem(node); 176fb726d48Sopenharmony_ci compareNode.type = ConstructorType.InstanceType; 177fb726d48Sopenharmony_ci compareNode.addedSize = compareNode.shallowSize; 178fb726d48Sopenharmony_ci compareNode.isAdd = true; 179fb726d48Sopenharmony_ci compareNode.hasNext = node.edgeCount > 0; 180fb726d48Sopenharmony_ci children.push(compareNode); 181fb726d48Sopenharmony_ci } 182fb726d48Sopenharmony_ci 183fb726d48Sopenharmony_ci for (let idx of comparisonNode.deletedIdx) { 184fb726d48Sopenharmony_ci let node = targetFileStruct.heapLoader.getNodes()[idx]; 185fb726d48Sopenharmony_ci let compareNode = HeapNodeToConstructorItem(node); 186fb726d48Sopenharmony_ci compareNode.type = ConstructorType.InstanceType; 187fb726d48Sopenharmony_ci compareNode.removedSize = compareNode.shallowSize; 188fb726d48Sopenharmony_ci compareNode.isAdd = false; 189fb726d48Sopenharmony_ci compareNode.hasNext = node.edgeCount > 0; 190fb726d48Sopenharmony_ci children.push(compareNode); 191fb726d48Sopenharmony_ci } 192fb726d48Sopenharmony_ci } else { 193fb726d48Sopenharmony_ci children = this.getNextForConstructor(comparisonNode); 194fb726d48Sopenharmony_ci } 195fb726d48Sopenharmony_ci return children; 196fb726d48Sopenharmony_ci } 197fb726d48Sopenharmony_ci 198fb726d48Sopenharmony_ci /** 199fb726d48Sopenharmony_ci * get nodes which referenced this node 200fb726d48Sopenharmony_ci * @param constructor current node 201fb726d48Sopenharmony_ci * @returns reference nodes 202fb726d48Sopenharmony_ci */ 203fb726d48Sopenharmony_ci public getRetains(constructor: ConstructorItem): ConstructorItem[] { 204fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(constructor.fileId); 205fb726d48Sopenharmony_ci if (!filStruct) { 206fb726d48Sopenharmony_ci return []; 207fb726d48Sopenharmony_ci } 208fb726d48Sopenharmony_ci return filStruct?.heapLoader.getRetains(constructor); 209fb726d48Sopenharmony_ci } 210fb726d48Sopenharmony_ci 211fb726d48Sopenharmony_ci /** 212fb726d48Sopenharmony_ci * get AllocationStack page data 213fb726d48Sopenharmony_ci * @param node the row of data clicked 214fb726d48Sopenharmony_ci * @returns AllocationStackFrame[] 215fb726d48Sopenharmony_ci */ 216fb726d48Sopenharmony_ci public getAllocationStackData(node: ConstructorItem): Array<HeapTraceFunctionInfo> { 217fb726d48Sopenharmony_ci let functions: Array<HeapTraceFunctionInfo> = []; 218fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); 219fb726d48Sopenharmony_ci if (!filStruct && (node.type === ConstructorType.ClassType || node.type === ConstructorType.RetainersType)) { 220fb726d48Sopenharmony_ci return functions; 221fb726d48Sopenharmony_ci } else { 222fb726d48Sopenharmony_ci functions = filStruct!.heapLoader.getAllocationStack(node.traceNodeId); 223fb726d48Sopenharmony_ci } 224fb726d48Sopenharmony_ci return functions; 225fb726d48Sopenharmony_ci } 226fb726d48Sopenharmony_ci 227fb726d48Sopenharmony_ci /** 228fb726d48Sopenharmony_ci * obtain the minimum id of the node 229fb726d48Sopenharmony_ci * @param fileId current file id 230fb726d48Sopenharmony_ci * @returns minNodeId 231fb726d48Sopenharmony_ci */ 232fb726d48Sopenharmony_ci public getMinNodeId(fileId: number): number | undefined { 233fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); 234fb726d48Sopenharmony_ci if (!filStruct) { 235fb726d48Sopenharmony_ci return undefined; 236fb726d48Sopenharmony_ci } 237fb726d48Sopenharmony_ci return filStruct!.heapLoader.getMinAndMaxNodeId().minNodeId; 238fb726d48Sopenharmony_ci } 239fb726d48Sopenharmony_ci 240fb726d48Sopenharmony_ci /** 241fb726d48Sopenharmony_ci * obtain the maximum id of the node 242fb726d48Sopenharmony_ci * @param fileId current file id 243fb726d48Sopenharmony_ci * @returns maxNodeId 244fb726d48Sopenharmony_ci */ 245fb726d48Sopenharmony_ci public getMaxNodeId(fileId: number): number | undefined { 246fb726d48Sopenharmony_ci let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); 247fb726d48Sopenharmony_ci if (!filStruct) { 248fb726d48Sopenharmony_ci return undefined; 249fb726d48Sopenharmony_ci } 250fb726d48Sopenharmony_ci return filStruct!.heapLoader.getMinAndMaxNodeId().maxNodeId; 251fb726d48Sopenharmony_ci } 252fb726d48Sopenharmony_ci 253fb726d48Sopenharmony_ci async parseData(fileModule: Array<FileStruct>): Promise<void> { 254fb726d48Sopenharmony_ci this.fileStructs = fileModule; 255fb726d48Sopenharmony_ci this.isParseDone = false; 256fb726d48Sopenharmony_ci let percent: number; 257fb726d48Sopenharmony_ci for (let fileStruct of fileModule) { 258fb726d48Sopenharmony_ci let heapLoader = new HeapLoader(fileStruct); 259fb726d48Sopenharmony_ci fileStruct.heapLoader = heapLoader; 260fb726d48Sopenharmony_ci percent = 50 + Math.floor(50 / fileModule.length) * (fileModule.indexOf(fileStruct) + 1); 261fb726d48Sopenharmony_ci } 262fb726d48Sopenharmony_ci this.isParseDone = true; 263fb726d48Sopenharmony_ci if (this.parseListener) { 264fb726d48Sopenharmony_ci this.parseListener.parseDone(fileModule); 265fb726d48Sopenharmony_ci } 266fb726d48Sopenharmony_ci } 267fb726d48Sopenharmony_ci 268fb726d48Sopenharmony_ci /** 269fb726d48Sopenharmony_ci * get all file struct in database 270fb726d48Sopenharmony_ci * @returns all fileInfo 271fb726d48Sopenharmony_ci */ 272fb726d48Sopenharmony_ci public getFileStructs(): Array<FileInfo> { 273fb726d48Sopenharmony_ci return this.fileStructs; 274fb726d48Sopenharmony_ci } 275fb726d48Sopenharmony_ci 276fb726d48Sopenharmony_ci /** 277fb726d48Sopenharmony_ci * clear Cache 278fb726d48Sopenharmony_ci */ 279fb726d48Sopenharmony_ci public clearData(): void { 280fb726d48Sopenharmony_ci if (!this.fileStructs) { 281fb726d48Sopenharmony_ci return; 282fb726d48Sopenharmony_ci } 283fb726d48Sopenharmony_ci for (let file of this.fileStructs) { 284fb726d48Sopenharmony_ci file.snapshotStruct.clear(); 285fb726d48Sopenharmony_ci file.heapLoader.clear(); 286fb726d48Sopenharmony_ci } 287fb726d48Sopenharmony_ci this.fileStructs.length = 0; 288fb726d48Sopenharmony_ci } 289fb726d48Sopenharmony_ci} 290