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