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}