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}