• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]====================
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}