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 { AllocationFunction } from '../model/UiStruct';
17fb726d48Sopenharmony_ciimport { FileStruct, HeapTraceFunctionInfo } from '../model/DatabaseStruct';
18fb726d48Sopenharmony_ci
19fb726d48Sopenharmony_ciexport class AllocationLogic {
20fb726d48Sopenharmony_ci  private fileStruct: FileStruct;
21fb726d48Sopenharmony_ci  private traceNodes: Array<AllocationFunction>;
22fb726d48Sopenharmony_ci  private bottomUpList: Array<AllocationFunction>;
23fb726d48Sopenharmony_ci
24fb726d48Sopenharmony_ci  constructor(fileStruct: FileStruct) {
25fb726d48Sopenharmony_ci    this.fileStruct = fileStruct;
26fb726d48Sopenharmony_ci    this.bottomUpList = [];
27fb726d48Sopenharmony_ci    this.traceNodes = this.fileStruct.snapshotStruct.traceNodes;
28fb726d48Sopenharmony_ci    this.setBottomUpTree();
29fb726d48Sopenharmony_ci  }
30fb726d48Sopenharmony_ci
31fb726d48Sopenharmony_ci  private setBottomUpTree(): void {
32fb726d48Sopenharmony_ci    let keyMap = new Map<String, AllocationFunction>();
33fb726d48Sopenharmony_ci    for (let node of this.traceNodes) {
34fb726d48Sopenharmony_ci      if (node.parentsId.length > 1) {
35fb726d48Sopenharmony_ci        node.hasParent = true;
36fb726d48Sopenharmony_ci      } else if (node.parentsId.length === 0) {
37fb726d48Sopenharmony_ci        node.hasParent = false;
38fb726d48Sopenharmony_ci      } else {
39fb726d48Sopenharmony_ci        if (node.parentsId[0] === -1) {
40fb726d48Sopenharmony_ci          node.hasParent = false;
41fb726d48Sopenharmony_ci        } else {
42fb726d48Sopenharmony_ci          node.hasParent = true;
43fb726d48Sopenharmony_ci        }
44fb726d48Sopenharmony_ci      }
45fb726d48Sopenharmony_ci      // combine node
46fb726d48Sopenharmony_ci      if (keyMap.has(node.name + node.functionIndex)) {
47fb726d48Sopenharmony_ci        let uniqueNode = keyMap.get(node.name + node.functionIndex);
48fb726d48Sopenharmony_ci        if (!uniqueNode) {
49fb726d48Sopenharmony_ci          continue;
50fb726d48Sopenharmony_ci        }
51fb726d48Sopenharmony_ci        uniqueNode.size += node.size;
52fb726d48Sopenharmony_ci        uniqueNode.count += node.count;
53fb726d48Sopenharmony_ci        uniqueNode.liveSize += node.liveSize;
54fb726d48Sopenharmony_ci        uniqueNode.liveCount += node.liveCount;
55fb726d48Sopenharmony_ci        uniqueNode.parentsId.push(...node.parentsId);
56fb726d48Sopenharmony_ci        uniqueNode.combineId.add(uniqueNode.id);
57fb726d48Sopenharmony_ci        uniqueNode.combineId.add(node.id);
58fb726d48Sopenharmony_ci      } else {
59fb726d48Sopenharmony_ci        keyMap.set(node.name + node.functionIndex, node);
60fb726d48Sopenharmony_ci        node.combineId.add(node.id);
61fb726d48Sopenharmony_ci        this.bottomUpList.push(node);
62fb726d48Sopenharmony_ci      }
63fb726d48Sopenharmony_ci    }
64fb726d48Sopenharmony_ci    this.bottomUpList.sort(function (a, b) {
65fb726d48Sopenharmony_ci      return b.size - a.size;
66fb726d48Sopenharmony_ci    });
67fb726d48Sopenharmony_ci  }
68fb726d48Sopenharmony_ci
69fb726d48Sopenharmony_ci  private getNodeById(id: number): AllocationFunction | null {
70fb726d48Sopenharmony_ci    for (let func of this.bottomUpList) {
71fb726d48Sopenharmony_ci      if (func.id === id) {
72fb726d48Sopenharmony_ci        return func;
73fb726d48Sopenharmony_ci      }
74fb726d48Sopenharmony_ci    }
75fb726d48Sopenharmony_ci    return null;
76fb726d48Sopenharmony_ci  }
77fb726d48Sopenharmony_ci
78fb726d48Sopenharmony_ci  private getFunctionStack(node: AllocationFunction, functionList: Array<HeapTraceFunctionInfo>): void {
79fb726d48Sopenharmony_ci    functionList.push(this.fileStruct.snapshotStruct.functionInfos[node.functionIndex]);
80fb726d48Sopenharmony_ci    if (node.parentsId.length > 0) {
81fb726d48Sopenharmony_ci      for (let parentId of node.parentsId) {
82fb726d48Sopenharmony_ci        let parentNode = this.getNodeById(parentId);
83fb726d48Sopenharmony_ci        if (parentNode) {
84fb726d48Sopenharmony_ci          this.getFunctionStack(parentNode, functionList);
85fb726d48Sopenharmony_ci        }
86fb726d48Sopenharmony_ci      }
87fb726d48Sopenharmony_ci    }
88fb726d48Sopenharmony_ci  }
89fb726d48Sopenharmony_ci
90fb726d48Sopenharmony_ci  /**
91fb726d48Sopenharmony_ci   * get Bottom Up FUnction List
92fb726d48Sopenharmony_ci   * @returns bottomUpList
93fb726d48Sopenharmony_ci   */
94fb726d48Sopenharmony_ci  public getFunctionList(): Array<AllocationFunction> {
95fb726d48Sopenharmony_ci    return this.bottomUpList;
96fb726d48Sopenharmony_ci  }
97fb726d48Sopenharmony_ci
98fb726d48Sopenharmony_ci  /**
99fb726d48Sopenharmony_ci   * set node parents node
100fb726d48Sopenharmony_ci   * node has multi parent because bottom up combine multi node
101fb726d48Sopenharmony_ci   * @param node selected node
102fb726d48Sopenharmony_ci   */
103fb726d48Sopenharmony_ci  public getParent(node: AllocationFunction): void {
104fb726d48Sopenharmony_ci    if (node.hasParent) {
105fb726d48Sopenharmony_ci      if (node.parentsId.length > 1) {
106fb726d48Sopenharmony_ci        for (let childrenId of node.parentsId) {
107fb726d48Sopenharmony_ci          let children = this.traceNodes[childrenId - 1].clone();
108fb726d48Sopenharmony_ci          children.size = node.size;
109fb726d48Sopenharmony_ci          children.count = node.count;
110fb726d48Sopenharmony_ci          children.liveSize = node.liveSize;
111fb726d48Sopenharmony_ci          children.liveCount = node.liveCount;
112fb726d48Sopenharmony_ci          node.parents.push(children);
113fb726d48Sopenharmony_ci        }
114fb726d48Sopenharmony_ci      } else if ((node.parentsId.length = 1)) {
115fb726d48Sopenharmony_ci        let childrenId = node.parentsId[0];
116fb726d48Sopenharmony_ci        if (!node.parents) {
117fb726d48Sopenharmony_ci          node.parents = [];
118fb726d48Sopenharmony_ci        }
119fb726d48Sopenharmony_ci        let children = this.traceNodes[childrenId - 1].clone();
120fb726d48Sopenharmony_ci        children.size = node.size;
121fb726d48Sopenharmony_ci        children.count = node.count;
122fb726d48Sopenharmony_ci        children.liveSize = node.liveSize;
123fb726d48Sopenharmony_ci        children.liveCount = node.liveCount;
124fb726d48Sopenharmony_ci        node.parents.push(children);
125fb726d48Sopenharmony_ci        this.getParent(children);
126fb726d48Sopenharmony_ci      } else {
127fb726d48Sopenharmony_ci        // no need to do anything
128fb726d48Sopenharmony_ci      }
129fb726d48Sopenharmony_ci    }
130fb726d48Sopenharmony_ci  }
131fb726d48Sopenharmony_ci
132fb726d48Sopenharmony_ci  /**
133fb726d48Sopenharmony_ci   * get use bottom up method combine's node ids
134fb726d48Sopenharmony_ci   * @param allocationNodeId node id
135fb726d48Sopenharmony_ci   * @returns node combine id
136fb726d48Sopenharmony_ci   */
137fb726d48Sopenharmony_ci  public getFunctionNodeIds(allocationNodeId: number): Array<number> {
138fb726d48Sopenharmony_ci    let node = this.getNodeById(allocationNodeId);
139fb726d48Sopenharmony_ci    if (node) {
140fb726d48Sopenharmony_ci      return Array.from(node.combineId);
141fb726d48Sopenharmony_ci    } else {
142fb726d48Sopenharmony_ci      return [];
143fb726d48Sopenharmony_ci    }
144fb726d48Sopenharmony_ci  }
145fb726d48Sopenharmony_ci
146fb726d48Sopenharmony_ci  /**
147fb726d48Sopenharmony_ci   * get full stack for node
148fb726d48Sopenharmony_ci   * @param allocationNodeId node.traceNodeId
149fb726d48Sopenharmony_ci   * @returns stack list
150fb726d48Sopenharmony_ci   */
151fb726d48Sopenharmony_ci  public getNodeStack(allocationNodeId: number): Array<HeapTraceFunctionInfo> {
152fb726d48Sopenharmony_ci    let currentNode = this.getNodeById(allocationNodeId);
153fb726d48Sopenharmony_ci    let functionList: HeapTraceFunctionInfo[] = [];
154fb726d48Sopenharmony_ci    if (currentNode) {
155fb726d48Sopenharmony_ci      this.getFunctionStack(currentNode, functionList);
156fb726d48Sopenharmony_ci    }
157fb726d48Sopenharmony_ci    return functionList;
158fb726d48Sopenharmony_ci  }
159fb726d48Sopenharmony_ci}
160