• 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) {
41        this.count += num;
42        this.relatedInsns.forEach(relatedInsn => { relatedInsn.num += num });
43    }
44
45    set(num: number) {
46        this.count = num;
47        this.relatedInsns.forEach(relatedInsn => { relatedInsn.num = num });
48    }
49
50    getCount() {
51        return this.count;
52    }
53
54    getInstSize() {
55        return this.instSize;
56    }
57
58    getTotalSize() {
59        return this.count * this.instSize;
60    }
61
62    getRelatedInsns() {
63        return this.relatedInsns;
64    }
65
66    getNodeMap() {
67        return this.nodeMap;
68    }
69
70    updateNodeMap(nodeName: string) {
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>) {
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) {
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() {
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                LOGD(key + "\t\t\t" + value.getCount() + "\t\t"+ value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
191                     + value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%"); // multiplying 100 is to calculate percentage data
192            } else if (key.length < 16) { // 16 indicates insn name length
193                LOGD(key + "\t\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
194                     + value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
195            } else {
196                LOGD(key + "\t" + value.getCount() + "\t\t" + value.getInstSize() + "\t\t" + value.getTotalSize() + "\t\t"
197                     + value.getSavedSizeIfRemoved(this) + "\t" + Math.round(value.getSavedSizeIfRemoved(this) / totalSize * 100) + "%");
198            }
199        });
200
201        LOGD("total insns number : \t" + totalInsnsNum + "\t\t" + "total Size : \t" + totalSize);
202
203        LOGD("\n");
204        this.insHistogram.forEach((value, key) => {
205            if (value.getNodeMap().size > 1) {
206
207                LOGD("op code: " + key);
208                value.getNodeMap().forEach((num: number, node: string) => {
209                    if (node.length < 8) {
210                        LOGD("Node: \t" + node + "\t\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
211                    } else if (node.length < 16) {
212                        LOGD("Node: \t" + node + "\t\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
213                    } else if (node.length < 24) {
214                        LOGD("Node: \t" + node + "\t\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
215                    } else {
216                        LOGD("Node: \t" + node + "\t\t\tnum: \t" + num + "\t\t" + Math.round(num / value.getCount() * 100) + "%");
217                    }
218                });
219                LOGD("\n");
220            }
221        });
222    }
223}
224
225export class CompilerStatistics {
226    private histogramMap: Map<string, HistogramStatistics> = new Map<string, HistogramStatistics>();
227    private numOfHoistingCases: number[] = [0, 0, 0, 0];
228    private hoistingRelatedInsnNum: number = 0;
229
230    constructor() {
231
232    }
233
234    addHoistingRelatedInsnNum(num: number) {
235        this.hoistingRelatedInsnNum += num;
236    }
237
238    addNumOfHoistCases(type: HoistingType) {
239        this.numOfHoistingCases[type]++;
240    }
241
242    getInsHistogramStatistics(pg: PandaGen) {
243        let histogram = new HistogramStatistics(pg.internalName);
244
245        histogram.catchStatistics(pg);
246        this.histogramMap.set(pg.internalName, histogram);
247    }
248
249    printHistogram(verbose: boolean) {
250        let totalHistogram = new HistogramStatistics("Total");
251
252        // @ts-ignore
253        this.histogramMap.forEach((histogram, funcName) => {
254            totalHistogram.unionStatistics(histogram);
255
256            if (verbose) {
257                histogram.print();
258            }
259        });
260
261        totalHistogram.print();
262    }
263
264    printHoistStatistics(): void {
265        LOGD("\n");
266        LOGD("HoistingRelated Histogram:", "======whole file=======");
267        LOGD("global var\tlocal var\tglobal function\tlocal function");
268        LOGD(this.numOfHoistingCases[0] + "\t\t" + this.numOfHoistingCases[1] + "\t\t" + this.numOfHoistingCases[2] + "\t\t" + this.numOfHoistingCases[3]);
269        LOGD("\n");
270        LOGD("Approximately hoisting related insns nums");
271        LOGD(this.hoistingRelatedInsnNum);
272    }
273}