1/* 2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 16const { XTools } = require("../engine/XTools"); 17const { X2DFast } = require("../engine/graphics/X2DFast"); 18const { NapiLog } = require("./NapiLog"); 19 20class LogParser { 21 constructor(result) { 22 const regexVT100 = /\x1B\[[0-9;]*[A-Za-z]/g; // 匹配VT100字符的正则表达式 23 result = result.replace(regexVT100, ''); 24 result = result.replace(/\t/g, ' '); 25 result = result.replace(/\r/g, ''); 26 this.logLines_ = result.split("\n"); 27 this.stat_ = 0; 28 this.lineNum_ = 0; 29 this.initBlock_ = { 30 filePoint: null, 31 funcPoint: null, 32 blockType: -1, 33 }; 34 this.procBlock_ = { 35 blockStat: -1, 36 blockCollect: -1, 37 oneBlock: -1, 38 } 39 this.procNormal_ = null; 40 this.output_ = {}; 41 } 42 43 parsing() { 44 if (this.lineNum_ >= this.logLines_.length) { 45 return false; 46 } 47 48 for (let i = 0; i < 300 && this.lineNum_ < this.logLines_.length; i++) { 49 this.parseLine(this.logLines_[this.lineNum_]); 50 this.lineNum_++; 51 } 52 53 XTools.PROC_TO = this.lineNum_ * 20 / this.logLines_.length; 54 return true; 55 } 56 isBlock(l) { 57 for (let bt of XTools.CONFIG.BlockTypes) { 58 if (l.indexOf(bt) >= 0) { 59 this.stat_ = this.initBlock_.blockType; 60 this.procBlock_.blockStat = 0; 61 this.procBlock_.blockCollect = { 62 type: "block:" + bt, 63 func: this.initBlock_.funcPoint, 64 file: this.initBlock_.filePoint, 65 irList: [], 66 startLine: l, 67 } 68 this.procBlock_.oneBlock = null; 69 return true; 70 } 71 } 72 return false; 73 } 74 splitLast(s) { 75 let i = s.lastIndexOf("@"); 76 77 return [s.substring(0, i), s.substring(i + 1)]; 78 } 79 isStart(l) { 80 //========= After bytecode2circuit lowering [func_main_0@484@arkcompiler/ets_runtime/sd_test/ttabs.abc] ======== 81 const regexStart = /=+ *After ([a-zA-Z0-9_ ]+) \[([#a-zA-Z0-9_@/.]+)\] *=+/g 82 //========= After inlining [OthreMath@test@arkcompiler/ets_runtime/sd_test/test.abc] Caller method [func_main_0@641@arkcompiler/ets_runtime/sd_test/test.abc]====================[0m 83 const regexStart2 = /=+ *After ([a-zA-Z0-9_ ]+) \[([a-zA-Z0-9_@/.]+)\] *Caller method \[([#a-zA-Z0-9_@/.]+)\] *=+/g 84 85 if (l[11] !== '=') { 86 return; 87 } 88 let ret = regexStart.exec(l); 89 if (ret) { 90 let tt = this.splitLast(ret[2]); 91 this.procNormal_ = { 92 type: ret[1],//优化类型 93 func: tt[0],//函数名 94 file: tt[1],//文件名 95 irList: [], 96 startLine: l, 97 }; 98 this.stat_ = 1; 99 [this.initBlock_.funcPoint, this.initBlock_.filePoint] = [tt[0], tt[tt.length - 1]]; 100 this.initBlock_.blockType = 10; 101 } 102 else { 103 ret = regexStart2.exec(l); 104 if (ret) { 105 let tt = this.splitLast(ret[2]); 106 let tt2 = this.splitLast(ret[3]); 107 NapiLog.logInfo(tt[0], "Caller method(" + this.lineNum_ + "行)", ret[3]); 108 this.procNormal_ = { 109 type: ret[1] + " " + tt[0],//优化类型 110 func: tt2[0],//函数名 111 file: tt2[1],//文件名 112 irList: [], 113 startLine: l, 114 }; 115 this.stat_ = 1; 116 [this.initBlock_.funcPoint, this.initBlock_.filePoint] = [tt2[0], tt2[tt2.length - 1]]; 117 this.initBlock_.blockType = 10; 118 } 119 else { 120 if (l.search("After") > 0) { 121 alert(l); 122 } 123 } 124 } 125 } 126 collectNormal(l) { 127 let idx = l.search('{"id":'); 128 if (idx >= 0) { 129 let idx2 = l.lastIndexOf('}'); 130 let str = l.substring(idx, idx2 + 1); 131 132 let ir = JSON.parse(str); 133 {//根据XTools.CONFIG.MTypeField切割MType 134 let cutPos = []; 135 for (let field of XTools.CONFIG.MTypeField) { 136 let idx = ir.MType.indexOf(", " + field); 137 if (idx >= 0) { 138 cutPos.push(idx); 139 } 140 } 141 cutPos.push(ir.MType.length); 142 cutPos.sort((a, b) => { return parseInt(a) - parseInt(b) }); 143 if (cutPos[0] === 0) { 144 cutPos.shift(); 145 } 146 let p = 0; 147 let cutResult = []; 148 for (let i of cutPos) { 149 let tmp = ir.MType.substring(p, i); 150 if (tmp.startsWith(", ")) { 151 tmp = tmp.substring(2); 152 } 153 if (tmp.endsWith(", ")) { 154 tmp = tmp.substring(0, tmp.length - 2); 155 } 156 cutResult.push(tmp); 157 p = i; 158 } 159 cutResult.push("inNum=[" + ir.in[0].length + "," + ir.in[1].length + "," + ir.in[2].length + "," + ir.in[3].length + "," + ir.in[4].length + "]") 160 cutResult.push("outNum=" + ir.out.length); 161 ir.maxDetailWidth = 0; 162 for (let detail of cutResult) { 163 let w = X2DFast.gi().getTextWidth(detail, 14); 164 if (ir.maxDetailWidth < w) { 165 ir.maxDetailWidth = w; 166 } 167 } 168 ir.detailList = cutResult; 169 } 170 this.procNormal_.irList.push(ir); 171 } 172 else { 173 //= End typeHitRate: 0.500000 = 174 let regexEnd = /=+ End[a-zA-Z:.0-9 ]* =+/g 175 let tt = regexEnd.exec(l); 176 if (tt) {//收集结束,入大表l.search('== End ==') > 0 177 if (this.procNormal_.irList.length > 0) { 178 if (!(this.procNormal_.file in this.output_)) { 179 this.output_[this.procNormal_.file] = {}; 180 } 181 if (!(this.procNormal_.func in this.output_[this.procNormal_.file])) { 182 this.output_[this.procNormal_.file][this.procNormal_.func] = []; 183 } 184 this.output_[this.procNormal_.file][this.procNormal_.func].push(this.procNormal_); 185 } 186 else { 187 NapiLog.logError("After和End之间没有指令(" + this.lineNum_ + "行)"); 188 } 189 this.stat_ = 0; 190 } 191 else { 192 NapiLog.logError("After和End之间解析失败(" + (this.lineNum_ + 1) + ")行"); 193 this.stat_ = 0; 194 } 195 } 196 } 197 parseLine(l) { 198 switch (this.stat_) { 199 case 0://搜索起始 200 if (this.SearchBegin(l) || this.isBlock(l)) { 201 return; 202 } 203 this.isStart(l); 204 break; 205 case 1://收集ir表 206 this.collectNormal(l); 207 break; 208 case 10://收集block一 209 if (this.CollectBlock(l)) { 210 this.stat_ = 0; 211 this.lineNum_ -= 1; 212 } 213 break; 214 case 20://收集block二 215 if (this.CollectBlock2(l)) { 216 this.stat_ = 0; 217 this.lineNum_ -= 1; 218 } 219 break; 220 } 221 } 222 223 static Load(fn, cb) { 224 const xhr = new XMLHttpRequest(); 225 xhr.open('GET', fn); 226 xhr.onreadystatechange = () => { 227 if (xhr.readyState === XMLHttpRequest.DONE) { 228 if (xhr.status === 200) { 229 XTools.PORC_TO = 10; 230 cb(fn, xhr.responseText); 231 } 232 } 233 }; 234 xhr.send(); 235 } 236 NumberStringToArray(ss) { 237 let outs = ss.split(","); 238 let ret = [] 239 for (let s of outs) { 240 let ttt = parseInt(s); 241 if (!isNaN(ttt)) { 242 ret.push(ttt); 243 } 244 } 245 return ret; 246 } 247 SearchBegin(l) { 248 let ret; 249 let ib = this.initBlock_; 250 251 if (l.startsWith("[compiler] aot method")) { 252 ////[compiler] aot method [func_main_0@b.abc] log: 253 const regexFuncName = /^\[compiler\] aot method \[([#a-zA-Z0-9_@/.]+)\] (recordName \[[a-zA-Z0-9_]*\] )*log:/g 254 ret = regexFuncName.exec(l); 255 if (ret) { 256 [ib.funcPoint, ib.filePoint] = this.splitLast(ret[1]); 257 ib.blockType = 10; 258 return true; 259 } 260 } 261 if (l.startsWith("[compiler] ==================== Before state split")) { 262 const regexFuncName2 = /^\[compiler\] =+ Before state split linearizer \[([#a-zA-Z0-9_@/.]+)\] *=*/g 263 ret = regexFuncName2.exec(l); 264 if (ret) { 265 [ib.funcPoint, ib.filePoint] = this.splitLast(ret[1]); 266 ib.blockType = 20; 267 return true; 268 } 269 } 270 if (l.startsWith("[compiler] ==================== After graph lineari")) { 271 const regexFuncName3 = /^\[compiler\] =+ After graph linearizer \[([#a-zA-Z0-9_@/.]+)\] *=*/g 272 ret = regexFuncName3.exec(l); 273 if (ret) { 274 [ib.funcPoint, ib.filePoint] = this.splitLast(ret[1]); 275 ib.blockType = 20; 276 return true; 277 } 278 } 279 return false; 280 } 281 CollectBlock(l) { 282 const regexBlock = [ 283 /^\[compiler\] B([0-9]+): ;preds=([0-9, ]*)$/g,//[compiler] B0: ;preds= 284 /^\[compiler\] *Succes:([0-9, ]*)$/g,//[compiler] Succes: 285 /^\[compiler\] *Bytecode\[\] = *(Empty)*$/g,//[compiler] Bytecode[] = Empty 286 /^\[compiler\] *Trys:([0-9, ]*)$/g,//[compiler] Trys: 287 ] 288 let ret; 289 let pb = this.procBlock_; 290 if (pb.blockStat === 0) { 291 ret = regexBlock[0].exec(l); 292 if (ret) { 293 pb.oneBlock = { 294 id: ret[1], 295 op: "B" + ret[1], 296 detailList: [], 297 maxDetailWidth: 0, 298 } 299 pb.oneBlock.in = [[], [], [], [], this.NumberStringToArray(ret[2])]; 300 return false; 301 } 302 if (!pb.oneBlock) {//完成了一个block的解析 303 if (!(pb.blockCollect.file in this.output_)) { 304 this.output_[pb.blockCollect.file] = {}; 305 } 306 if (!(pb.blockCollect.func in this.output_[pb.blockCollect.file])) { 307 this.output_[pb.blockCollect.file][pb.blockCollect.func] = []; 308 } 309 this.output_[pb.blockCollect.file][pb.blockCollect.func].push(pb.blockCollect); 310 return true; 311 } 312 ret = regexBlock[1].exec(l); 313 if (ret) { 314 pb.oneBlock.out = this.NumberStringToArray(ret[1]); 315 return false; 316 } 317 ret = regexBlock[2].exec(l); 318 if (ret) { 319 pb.blockStat = 1; 320 return false; 321 } 322 } 323 else if (pb.blockStat === 1) {//开始记录bytecode,直到空行,结束这个block 324 if (/^\[compiler\] *$/g.test(l)) {//遇到空行,完成block 325 if (pb.oneBlock.maxDetailWidth === 0) { 326 pb.oneBlock.maxDetailWidth = X2DFast.gi().getTextWidth("Empty", 14); 327 pb.oneBlock.detailList.push("Empty"); 328 } 329 pb.blockCollect.irList.push(pb.oneBlock); 330 pb.oneBlock = null; 331 pb.blockStat = 0; 332 } 333 else { 334 let s = l.substring(11); 335 while (s.startsWith(" ")) { 336 s = s.substring(1); 337 } 338 let w = X2DFast.gi().getTextWidth(s, 14); 339 if (pb.oneBlock.maxDetailWidth < w) { 340 pb.oneBlock.maxDetailWidth = w; 341 } 342 pb.oneBlock.detailList.push(s); 343 } 344 } 345 return false; 346 } 347 CollectBlock2(l) { 348 const regexBlock = [ 349 /^\[compiler\] B([0-9]+):/g,//[compiler] B0: ;preds= 350 /^\[compiler\] *Preds:([0-9, ]*)$/g, 351 /^\[compiler\] *Succes:([0-9, ]*)$/g,//[compiler] Succes: 352 /^\[compiler\] *Bytecode\[\] = *(Empty)*$/g,//[compiler] Bytecode[] = Empty 353 /^\[compiler\] *Trys:([0-9, ]*)$/g,//[compiler] Trys: 354 ] 355 let pb = this.procBlock_; 356 let ret; 357 switch (pb.blockStat) { 358 case 0: 359 ret = regexBlock[0].exec(l); 360 if (ret) { 361 pb.oneBlock = { 362 id: ret[1], 363 op: "B" + ret[1], 364 detailList: [], 365 maxDetailWidth: 0, 366 } 367 pb.blockStat = 1; 368 return false; 369 } 370 if (!pb.oneBlock) {//完成了一个block的解析 371 if (!(pb.blockCollect.file in this.output_)) { 372 this.output_[pb.blockCollect.file] = {}; 373 } 374 if (!(pb.blockCollect.func in this.output_[pb.blockCollect.file])) { 375 this.output_[pb.blockCollect.file][pb.blockCollect.func] = []; 376 } 377 this.output_[pb.blockCollect.file][pb.blockCollect.func].push(pb.blockCollect); 378 return true; 379 } 380 break; 381 case 1: 382 ret = regexBlock[1].exec(l); 383 if (ret) { 384 pb.oneBlock.in = [[], [], [], [], this.NumberStringToArray(ret[1])]; 385 pb.blockStat = 2; 386 return false; 387 } 388 break; 389 case 2: 390 ret = regexBlock[2].exec(l); 391 if (ret) { 392 pb.oneBlock.out = this.NumberStringToArray(ret[1]); 393 pb.blockStat = 3; 394 return false; 395 } 396 break; 397 case 3://开始记录bytecode,直到空行,结束这个block 398 if (/^\[compiler\] *$/g.test(l)) {//遇到空行,完成block 399 if (pb.oneBlock.maxDetailWidth === 0) { 400 pb.oneBlock.maxDetailWidth = X2DFast.gi().getTextWidth("Empty", 14); 401 pb.oneBlock.detailList.push("Empty"); 402 } 403 pb.blockCollect.irList.push(pb.oneBlock); 404 pb.oneBlock = null; 405 pb.blockStat = 0; 406 } 407 else { 408 let s = l.substring(11); 409 while (s.startsWith(" ")) { 410 s = s.substring(1); 411 } 412 let w = X2DFast.gi().getTextWidth(s, 14); 413 if (pb.oneBlock.maxDetailWidth < w) { 414 pb.oneBlock.maxDetailWidth = w; 415 } 416 pb.oneBlock.detailList.push(s); 417 } 418 return false; 419 default: 420 return false; 421 } 422 return false; 423 } 424} 425 426module.exports = { 427 LogParser 428}