• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 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 { getInstructionSize, IRNode, IRNodeKind } from "./irnodes";
17import { LOGD } from "./log";
18import { PandaGen } from "./pandagen";
19
20export enum HoistingType {
21    GLOBAL_VAR = 0,
22    LOCAL_VAR,
23    GLOBAL_FUNCTION,
24    LOCAL_FUNCTION
25}
26
27class ItemValue {
28    private count: number = 1;
29    private instSize: number;
30    private relatedInsns: { name: string, num: number }[] = [];
31    private nodeMap: Map<string, number> = new Map<string, number>();
32
33    constructor(instSize: number, relatedInsns?: { name: string, num: number }) {
34        this.instSize = instSize;
35        if (relatedInsns) {
36            this.relatedInsns.push(relatedInsns);
37        }
38    }
39
40    add(num: number): void {
41        this.count += num;
42        this.relatedInsns.forEach(relatedInsn => { relatedInsn.num += num });
43    }
44
45    set(num: number): void {
46        this.count = num;
47        this.relatedInsns.forEach(relatedInsn => { relatedInsn.num = num });
48    }
49
50    getCount(): number {
51        return this.count;
52    }
53
54    getInstSize(): number {
55        return this.instSize;
56    }
57
58    getTotalSize(): number {
59        return this.count * this.instSize;
60    }
61
62    getRelatedInsns(): { name: string, num: number }[] {
63        return this.relatedInsns;
64    }
65
66    getNodeMap(): Map<string, number> {
67        return this.nodeMap;
68    }
69
70    updateNodeMap(nodeName: string): void {
71        if (!this.nodeMap.has(nodeName)) {
72            this.nodeMap.set(nodeName, 1);
73        } else {
74            let old = this.nodeMap.get(nodeName);
75            this.nodeMap.set(nodeName, old! + 1);
76        }
77    }
78
79    unionNodeMap(nodeMap: Map<string, number>): void {
80        nodeMap.forEach((value: number, key: string) => {
81            if (!this.nodeMap.has(key)) {
82                this.nodeMap.set(key, value);
83            } else {
84                let oldvalue = this.nodeMap.get(key);
85                oldvalue! += value;
86                this.nodeMap.set(key, oldvalue!);
87            }
88        });
89    }
90
91    getSavedSizeIfRemoved(Histogram: HistogramStatistics): number {
92        let savedSize = this.getTotalSize();
93        this.relatedInsns.forEach(relatedInsn => {
94            let histogram = Histogram.getStatistics();
95            let item = histogram.get(relatedInsn.name);
96            if (item) {
97                savedSize += (relatedInsn.num) * item.getInstSize();
98            }
99        });
100
101        return savedSize;
102    }
103
104    static createItemValue(name: string, instSize: number): ItemValue {
105        let relatedInsns: { name: string, num: number };
106        if (name === "lda.str") {
107            relatedInsns = { name: "sta.dyn", num: 1 };
108        }
109
110        return new ItemValue(instSize, relatedInsns!);
111    }
112}
113
114class HistogramStatistics {
115    private insHistogram: Map<string, ItemValue> = new Map<string, ItemValue>();
116    private funcName: string;
117
118    constructor(funcName: string) {
119        this.funcName = funcName;
120    }
121
122    getInsName(ins: IRNode): string {
123        if (ins.kind === IRNodeKind.LABEL) {
124            return "Label";
125        }
126
127        return ins.getMnemonic();
128    }
129
130    unionStatistics(histogram: HistogramStatistics): void {
131        let histogramData = histogram.getStatistics();
132        histogramData.forEach((value: ItemValue, key: string) => {
133            if (!this.insHistogram.has(key)) {
134                this.insHistogram.set(key, value);
135            } else {
136                let old = this.insHistogram.get(key);
137                old!.add(value.getCount());
138                old!.unionNodeMap(value.getNodeMap());
139                this.insHistogram.set(key, old!);
140            }
141        });
142    }
143
144    catchStatistics(pg: PandaGen): void {
145        pg.getInsns().forEach(ins => {
146            let key = this.getInsName(ins);
147            let opSize = getInstructionSize(ins.kind);
148            let nodeName = ins.getNodeName();
149            if (key.length <= 1) {
150                LOGD("this IRNode had no key: " + ins.toString());
151            }
152            if (!this.insHistogram.has(key)) {
153                let item = ItemValue.createItemValue(key, opSize);
154                item.updateNodeMap(nodeName);
155                this.insHistogram.set(key, item);
156            } else {
157                let old = this.insHistogram.get(key);
158                old!.updateNodeMap(nodeName);
159                old!.add(1);
160                this.insHistogram.set(key, old!);
161            }
162        });
163        return;
164    }
165
166    getStatistics(): Map<string, ItemValue> {
167        return this.insHistogram;
168    }
169
170    getTotal(): number[] {
171        let totalInsnsNum: number = 0;
172        let totalSize: number = 0;
173        // @ts-ignore
174        this.insHistogram.forEach((value, key) => {
175            totalInsnsNum += value.getCount();
176            totalSize += value.getTotalSize();
177        });
178
179        return [totalInsnsNum, totalSize];
180    }
181
182    print(): void {
183        let totalInsnsNum = this.getTotal()[0];
184        let totalSize = this.getTotal()[1];
185        LOGD("\n");
186        LOGD("Histogram:", "====== (" + this.funcName + ") ======");
187        LOGD("op code\t\t\tinsns number\tins size\ttotal size\tsize percentage");
188        this.insHistogram.forEach((value, key) => {
189            if (key.length < 8) { // 8 indicates insn name length
190                // multiplying 100 is to calculate percentage data
191                LOGD(key + "\t\t\t" + value.getCount() + "\t\t"+ value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t" +
192                     value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
193            } else if (key.length < 16) { // 16 indicates insn name length
194                LOGD(key + "\t\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t" +
195                     value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
196            } else {
197                LOGD(key + "\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t" +
198                     value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
199            }
200        });
201
202        LOGD("total insns number : \t" + totalInsnsNum + "\t\t" + "total Size : \t" + totalSize);
203
204        LOGD("\n");
205        this.insHistogram.forEach((value, key) => {
206            if (value.getNodeMap().size > 1) {
207
208                LOGD("op code: " + key);
209                value.getNodeMap().forEach((num: number, node: string) => {
210                    if (node.length < 8) {
211                        LOGD("Node: \t" + node + "\t\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
212                    } else if (node.length < 16) {
213                        LOGD("Node: \t" + node + "\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
214                    } else if (node.length < 24) {
215                        LOGD("Node: \t" + node + "\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
216                    } else {
217                        LOGD("Node: \t" + node + "\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
218                    }
219                });
220                LOGD("\n");
221            }
222        });
223    }
224}
225
226export class CompilerStatistics {
227    private histogramMap: Map<string, HistogramStatistics> = new Map<string, HistogramStatistics>();
228    private numOfHoistingCases: number[] = [0, 0, 0, 0];
229    private hoistingRelatedInsnNum: number = 0;
230
231    constructor() {
232
233    }
234
235    addHoistingRelatedInsnNum(num: number): void {
236        this.hoistingRelatedInsnNum += num;
237    }
238
239    addNumOfHoistCases(type: HoistingType): void {
240        this.numOfHoistingCases[type]++;
241    }
242
243    getInsHistogramStatistics(pg: PandaGen): void {
244        let histogram = new HistogramStatistics(pg.internalName);
245
246        histogram.catchStatistics(pg);
247        this.histogramMap.set(pg.internalName, histogram);
248    }
249
250    printHistogram(verbose: boolean): void {
251        let totalHistogram = new HistogramStatistics("Total");
252
253        // @ts-ignore
254        this.histogramMap.forEach((histogram, funcName) => {
255            totalHistogram.unionStatistics(histogram);
256
257            if (verbose) {
258                histogram.print();
259            }
260        });
261
262        totalHistogram.print();
263    }
264
265    printHoistStatistics(): void {
266        LOGD("\n");
267        LOGD("HoistingRelated Histogram:", "======whole file=======");
268        LOGD("global var\tlocal var\tglobal function\tlocal function");
269        LOGD(this.numOfHoistingCases[0] + "\t\t" + this.numOfHoistingCases[1] + "\t\t" + this.numOfHoistingCases[2] + "\t\t" + this.numOfHoistingCases[3]);
270        LOGD("\n");
271        LOGD("Approximately hoisting related insns nums");
272        LOGD(this.hoistingRelatedInsnNum);
273    }
274}