• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement';
17import { LitTable } from '../../../../../base-ui/table/lit-table';
18import { SelectionParam } from '../../../../bean/BoxSelection';
19import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie';
20import '../../../../../base-ui/chart/pie/LitChartPie';
21import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar';
22import { procedurePool } from '../../../../database/Procedure';
23import { TabPaneFilter } from '../TabPaneFilter';
24import { LitCheckBox } from '../../../../../base-ui/checkbox/LitCheckBox';
25import { initSort } from '../SheetUtils';
26import { TabpanePerfProfile } from './TabPerfProfile';
27import { TabPanePerfAnalysisHtml } from './TabPanePerfAnalysis.html';
28import { WebSocketManager } from '../../../../../webSocket/WebSocketManager';
29import { Constants, TypeConstants } from '../../../../../webSocket/Constants';
30
31@element('tabpane-perf-analysis')
32export class TabPanePerfAnalysis extends BaseElement {
33  private currentSelection: SelectionParam | unknown;
34  private perfAnalysisPie: LitChartPie | null | undefined;
35  private processData!: Array<unknown>;
36  private pidData!: unknown[];
37  private threadData!: unknown[];
38  private soData!: unknown[];
39  private functionData!: unknown[];
40  private perfTableThread: LitTable | null | undefined;
41  private perfTableProcess: LitTable | null | undefined;
42  private perfTableSo: LitTable | null | undefined;
43  private tableFunction: LitTable | null | undefined;
44  private sumCount: number | undefined | null;
45  private sumEventCount: number | undefined | null;
46  private perfAnalysisRange: HTMLLabelElement | null | undefined;
47  private back: HTMLDivElement | null | undefined;
48  private tabName: HTMLDivElement | null | undefined;
49  private progressEL: LitProgressBar | null | undefined;
50  private processName: string = '';
51  private threadName: string = '';
52  private callChainMap!: Map<number, unknown>;
53  private sortColumn: string = '';
54  private sortType: number = 0;
55  private allProcessCount!: {};
56  private allThreadCount!: {};
57  private allLibCount!: {};
58  private allSymbolCount!: {};
59  private currentLevel = -1;
60  private currentLevelData!: Array<unknown>;
61  private titleEl: HTMLDivElement | undefined | null;
62  private filterEl: TabPaneFilter | undefined | null;
63  private hideProcessCheckBox: LitCheckBox | undefined | null;
64  private hideThreadCheckBox: LitCheckBox | undefined | null;
65  private checkBoxs: NodeListOf<LitCheckBox> | undefined | null;
66  private tableArray: NodeListOf<LitTable> | undefined | null;
67  private isComplete: boolean = true;
68  private currentSelectionParam: SelectionParam | undefined | null;
69  static tabLoadingList: Array<string> = [];
70  private vaddrList: Array<unknown> = [];
71  private selectedTabfileName: string = '';
72  private clickFuncVaddrList: Array<unknown> = [];
73  private functionListener!: Function | undefined | null;
74  private currentSoName: string = '';
75
76  set data(val: SelectionParam) {
77    if (val === this.currentSelection) {
78      this.pidData.unshift(this.allProcessCount);
79      this.perfTableProcess!.recycleDataSource = this.pidData;
80      // @ts-ignore
81      this.pidData.shift(this.allProcessCount);
82      return;
83    }
84    if (this.tableArray) {
85      for (let table of this.tableArray) {
86        initSort(table!, this.sortColumn, this.sortType);
87      }
88    }
89    TabPanePerfAnalysis.tabLoadingList = [];
90    this.currentSelection = val;
91    this.tabName!.textContent = '';
92    this.hideProcessCheckBox!.checked = false;
93    this.hideThreadCheckBox!.checked = false;
94    this.reset(this.perfTableProcess!, false);
95    this.titleEl!.textContent = '';
96    this.perfAnalysisRange!.textContent = `Selected range: ${parseFloat(
97      ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)
98    )} ms`;
99    this.currentSelectionParam = val;
100    if (!this.callChainMap && this.isComplete) {
101      this.isComplete = false;
102      TabPanePerfAnalysis.tabLoadingList.push('analysis');
103      this.getCallChainDataFromWorker(val);
104    }
105  }
106
107  private initPerfTableListener(): void {
108    for (let perfTable of this.tableArray!) {
109      let querySelector = perfTable.shadowRoot?.querySelector<HTMLDivElement>('.table');
110      if (querySelector) {
111        querySelector.style.height = 'calc(100% - 31px)';
112      }
113      perfTable!.addEventListener('column-click', (evt) => {
114        // @ts-ignore
115        this.sortColumn = evt.detail.key;
116        // @ts-ignore
117        this.sortType = evt.detail.sort;
118        this.sortByColumn();
119      });
120      perfTable!.addEventListener('contextmenu', function (event) {
121        event.preventDefault(); // 阻止默认的上下文菜单弹框
122      });
123      perfTable!.addEventListener('row-hover', (evt) => {
124        this.perfTableRowHover(evt);
125      });
126      perfTable!.addEventListener('row-click', (evt) => {
127        // @ts-ignore
128        let detail = evt.detail;
129        let perfProfileTab = this.parentElement?.parentElement?.querySelector<TabpanePerfProfile>(
130          '#box-perf-profile > tabpane-perf-profile'
131        );
132        if (detail.button === 2 && detail.tableName && detail.tableName !== '') {
133          perfProfileTab!.cWidth = this.clientWidth;
134          perfProfileTab!.currentLevel = this.currentLevel;
135          if (this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
136            detail.data.pid = undefined;
137            detail.data.tid = undefined;
138          }
139          perfProfileTab!.rowClickData = detail.data;
140          let title;
141          if (this.titleEl?.textContent === '') {
142            title = detail.data.tableName;
143          } else {
144            title = `${this.titleEl?.textContent} / ${detail.data.tableName}`;
145          }
146          perfProfileTab!.pieTitle = title;
147          //  是否是在表格上右键点击跳转到火焰图的
148          // @ts-ignore
149          this.currentSelection.isRowClick = true;
150          perfProfileTab!.data = this.currentSelection;
151        }
152      });
153    }
154  }
155
156  private perfTableRowHover(evt: Event): void {
157    // @ts-ignore
158    let detail = evt.detail;
159    if (detail.data) {
160      let data = detail.data;
161      data.isHover = true;
162      if (detail.callBack) {
163        detail.callBack(true);
164      }
165    }
166    this.perfAnalysisPie?.showHover();
167    this.perfAnalysisPie?.hideTip();
168  }
169
170  initElements(): void {
171    this.perfAnalysisPie = this.shadowRoot!.querySelector<LitChartPie>('#perf-chart-pie');
172    this.perfAnalysisRange = this.shadowRoot?.querySelector('#time-range');
173    this.perfTableProcess = this.shadowRoot!.querySelector<LitTable>('#tb-process-usage');
174    this.perfTableSo = this.shadowRoot!.querySelector<LitTable>('#tb-so-usage');
175    this.tableFunction = this.shadowRoot!.querySelector<LitTable>('#tb-function-usage');
176    this.perfTableThread = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage');
177    this.back = this.shadowRoot!.querySelector<HTMLDivElement>('.perf-go-back');
178    this.tabName = this.shadowRoot!.querySelector<HTMLDivElement>('.perf-subheading');
179    this.progressEL = this.shadowRoot?.querySelector('.perf-progress') as LitProgressBar;
180    this.titleEl = this.shadowRoot!.querySelector<HTMLDivElement>('.title');
181    this.filterEl = this.shadowRoot?.querySelector('#filter');
182    this.filterEl!.setOptionsList(['Hide Process', 'Hide Thread']);
183    let popover = this.filterEl!.shadowRoot!.querySelector('#check-popover');
184    this.hideProcessCheckBox = popover!!.querySelector<LitCheckBox>('div > #hideProcess');
185    this.hideThreadCheckBox = popover!!.querySelector<LitCheckBox>('div > #hideThread');
186    this.checkBoxs = popover!.querySelectorAll<LitCheckBox>('.check-wrap > lit-check-box');
187    this.tableArray = this.shadowRoot!.querySelectorAll('lit-table') as NodeListOf<LitTable>;
188    this.initPerfTableListener();
189    for (let box of this.checkBoxs) {
190      box!.addEventListener('change', () => {
191        if (
192          (this.hideProcessCheckBox!.checked && this.hideThreadCheckBox!.checked) ||
193          (this.hideThreadCheckBox!.checked &&
194            // @ts-ignore
195            this.currentSelection.perfThread.length > 0 &&
196            // @ts-ignore
197            this.currentSelection.perfProcess.length === 0)
198        ) {
199          this.processName = '';
200          this.hideThread();
201          this.back!.style.visibility = 'hidden';
202        } else if (this.hideProcessCheckBox!.checked && !this.hideThreadCheckBox!.checked) {
203          this.hideProcess();
204        } else {
205          // @ts-ignore
206          this.getHiperfProcess(this.currentSelection);
207        }
208      });
209    }
210    this.getBack();
211    this.addRowClickEventListener(this.perfTableProcess!, this.perfProcessLevelClickEvent.bind(this));
212    this.addRowClickEventListener(this.perfTableThread!, this.perfThreadLevelClickEvent.bind(this));
213    this.addRowClickEventListener(this.perfTableSo!, this.perfSoLevelClickEvent.bind(this));
214    this.addRowClickEventListener(this.tableFunction!, this.functionClickEvent.bind(this));
215  }
216
217  private addRowClickEventListener(table: LitTable, clickEvent: Function): void {
218    table.addEventListener('row-click', (evt) => {
219      // @ts-ignore
220      const detail = evt.detail;
221      // @ts-ignore
222      const data = detail.data;
223      if (detail.button === 0 && data.tableName && data.count !== 0) {
224        clickEvent(data, this.currentSelection);
225      }
226    });
227  }
228
229  private reset(showTable: LitTable, isShowBack: boolean): void {
230    this.clearData();
231    if (isShowBack) {
232      this.back!.style.visibility = 'visible';
233    } else {
234      this.back!.style.visibility = 'hidden';
235      this.titleEl!.textContent = '';
236    }
237    if (this.tableArray) {
238      for (let table of this.tableArray) {
239        if (table === showTable) {
240          initSort(table!, this.sortColumn, this.sortType);
241          table.style.display = 'grid';
242          table!.removeAttribute('hideDownload');
243        } else {
244          table!.style.display = 'none';
245          table.setAttribute('hideDownload', '');
246        }
247      }
248    }
249  }
250
251  private clearData(): void {
252    this.perfAnalysisPie!.dataSource = [];
253    this.perfTableProcess!.recycleDataSource = [];
254    this.perfTableThread!.recycleDataSource = [];
255    this.perfTableSo!.recycleDataSource = [];
256    this.tableFunction!.recycleDataSource = [];
257  }
258
259  private showAssignLevel(
260    showTable: LitTable,
261    hideTable: LitTable,
262    currentLevel: number,
263    currentLevelData: Array<unknown>
264  ): void {
265    showTable!.style.display = 'grid';
266    hideTable!.style.display = 'none';
267    hideTable.setAttribute('hideDownload', '');
268    showTable?.removeAttribute('hideDownload');
269    this.currentLevel = currentLevel;
270    this.currentLevelData = currentLevelData;
271  }
272
273  private getBack(): void {
274    this.back!.addEventListener('click', () => {
275      if (this.tabName!.textContent === 'Statistic By Thread Count') {
276        this.showAssignLevel(this.perfTableProcess!, this.perfTableThread!, 0, this.pidData);
277        this.back!.style.visibility = 'hidden';
278        // @ts-ignore
279        this.processPieChart(this.currentSelection);
280      } else if (this.tabName!.textContent === 'Statistic By Library Count') {
281        if (this.hideThreadCheckBox?.checked) {
282          this.showAssignLevel(this.perfTableProcess!, this.perfTableSo!, 0, this.pidData);
283          this.back!.style.visibility = 'hidden';
284          // @ts-ignore
285          this.processPieChart(this.currentSelection);
286        } else {
287          this.showAssignLevel(this.perfTableThread!, this.perfTableSo!, 1, this.threadData);
288          // @ts-ignore
289          this.threadPieChart(this.currentSelection);
290        }
291      } else if (this.tabName!.textContent === 'Statistic By Function Count') {
292        this.showAssignLevel(this.perfTableSo!, this.tableFunction!, 2, this.soData);
293        this.libraryPieChart();
294      }
295      if (
296        (this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) ||
297        (this.hideProcessCheckBox?.checked && this.tabName!.textContent === 'Statistic By Thread Count') ||
298        (this.hideThreadCheckBox?.checked &&
299          this.tabName!.textContent === 'Statistic By Library Count' &&
300          // @ts-ignore
301          this.currentSelection.perfThread.length > 0 &&
302          // @ts-ignore
303          this.currentSelection.perfProcess.length === 0)
304      ) {
305        this.back!.style.visibility = 'hidden';
306        this.titleEl!.textContent = '';
307      }
308    });
309  }
310
311  private hideProcess(): void {
312    this.reset(this.perfTableThread!, false);
313    this.showAssignLevel(this.perfTableThread!, this.perfTableProcess!, 1, this.perfTableThread!.recycleDataSource);
314    this.processName = '';
315    this.titleEl!.textContent = '';
316    // @ts-ignore
317    this.getHiperfThread(null, this.currentSelection);
318  }
319
320  private hideThread(it?: unknown): void {
321    this.reset(this.perfTableSo!, true);
322    this.showAssignLevel(this.perfTableSo!, this.perfTableProcess!, 1, this.soData);
323    this.threadName = '';
324    if (it) {
325      // @ts-ignore
326      this.getHiperfSo(it, this.currentSelection);
327    } else {
328      // @ts-ignore
329      this.getHiperfSo(null, this.currentSelection);
330    }
331  }
332
333  private processPieChart(val: SelectionParam): void {
334    // @ts-ignore
335    this.sumCount = this.allProcessCount.allCount;
336    // @ts-ignore
337    this.sumEventCount = this.allProcessCount.allEventCount;
338    this.perfAnalysisPie!.config = {
339      appendPadding: 0,
340      data: this.getPerfPieChartData(this.pidData),
341      angleField: 'count',
342      colorField: 'tableName',
343      radius: 1,
344      label: {
345        type: 'outer',
346      },
347      tip: (perfObj): string => {
348        return `<div>
349                                <div>Process:${
350          // @ts-ignore
351          perfObj.obj.tableName
352          }</div>
353                                <div>Sample Count:${
354          // @ts-ignore
355          perfObj.obj.count
356          }</div>
357                                <div>Percent:${
358          // @ts-ignore
359          perfObj.obj.percent
360          }%</div>
361                                <div>Event Count:${
362          // @ts-ignore
363          perfObj.obj.eventCount
364          }</div>
365                                <div>Percent:${
366          // @ts-ignore
367          perfObj.obj.eventPercent
368          }%</div>
369                            </div>
370                               `;
371      },
372      angleClick: (it): void => {
373        // @ts-ignore
374        if (it.tableName !== 'other') {
375          this.perfProcessLevelClickEvent(it, val);
376        }
377      },
378      hoverHandler: (perfAnalyData): void => {
379        if (perfAnalyData) {
380          this.perfTableProcess!.setCurrentHover(perfAnalyData);
381        } else {
382          this.perfTableProcess!.mouseOut();
383        }
384      },
385      interactions: [
386        {
387          type: 'element-active',
388        },
389      ],
390    };
391    this.titleEl!.textContent = '';
392    this.tabName!.textContent = 'Statistic By Process Count';
393    if (this.pidData.length > 0) {
394      this.pidData.unshift(this.allProcessCount);
395    }
396    this.perfTableProcess!.recycleDataSource = this.pidData;
397    this.perfTableProcess?.reMeauseHeight();
398    // @ts-ignore
399    this.pidData.shift(this.allProcessCount);
400    this.currentLevelData = this.pidData;
401  }
402
403  private perfProcessLevelClickEvent(it: unknown, val: SelectionParam): void {
404    if (this.hideThreadCheckBox!.checked) {
405      this.hideThread(it);
406      this.showAssignLevel(this.perfTableSo!, this.perfTableProcess!, 1, this.soData);
407    } else {
408      this.reset(this.perfTableThread!, true);
409      this.showAssignLevel(this.perfTableThread!, this.perfTableProcess!, 1, this.threadData);
410      this.getHiperfThread(it, val);
411    }
412    // @ts-ignore
413    this.titleEl!.textContent = it.tableName;
414    // @ts-ignore
415    this.processName = it.tableName;
416    this.perfAnalysisPie?.hideTip();
417  }
418
419  private threadPieChart(val: SelectionParam): void {
420    if (val.perfThread.length > 0 && val.perfProcess.length === 0) {
421      this.back!.style.visibility = 'hidden';
422      this.titleEl!.textContent = '';
423      this.perfTableThread!.style.display = 'grid';
424    } else {
425      // @ts-ignore
426      this.titleEl!.textContent = this.processName;
427    }
428    // @ts-ignore
429    this.sumCount = this.allThreadCount.allCount;
430    // @ts-ignore
431    this.sumEventCount = this.allThreadCount.allEventCount;
432    this.perfAnalysisPie!.config = {
433      appendPadding: 0,
434      data: this.getPerfPieChartData(this.threadData),
435      angleField: 'count',
436      colorField: 'tableName',
437      radius: 1,
438      label: {
439        type: 'outer',
440      },
441      tip: (threadObj): string => {
442        // @ts-ignore
443        const obj = threadObj.obj as AnalysisObj;
444        return `<div><div>Thread:${obj.tableName}</div>
445        <div>Sample Count:${obj.count}</div>
446        <div>Percent:${obj.percent}%</div>
447        <div>Event Count:${obj.eventCount}</div>
448        <div>Percent:${obj.eventPercent}%</div>  </div>`;
449      },
450      angleClick: (it): void => {
451        // @ts-ignore
452        if (it.tableName !== 'other') {
453          this.perfThreadLevelClickEvent(it, val);
454        }
455      },
456      hoverHandler: (data): void => {
457        if (data) {
458          this.perfTableThread!.setCurrentHover(data);
459        } else {
460          this.perfTableThread!.mouseOut();
461        }
462      },
463      interactions: [{ type: 'element-active' }],
464    };
465    this.tabName!.textContent = 'Statistic By Thread Count';
466    this.threadData.unshift(this.allThreadCount);
467    this.perfTableThread!.recycleDataSource = this.threadData;
468    this.perfTableThread?.reMeauseHeight();
469    // @ts-ignore
470    this.threadData.shift(this.allThreadCount);
471    this.currentLevelData = this.threadData;
472  }
473
474  private perfThreadLevelClickEvent(it: unknown, val: SelectionParam): void {
475    this.reset(this.perfTableSo!, true);
476    this.showAssignLevel(this.perfTableSo!, this.perfTableThread!, 2, this.soData);
477    this.getHiperfSo(it, val);
478    let pName = this.processName;
479    // @ts-ignore
480    if (this.processName.length > 0 && it.tableName.length > 0) {
481      pName = `${this.processName} / `;
482    }
483    // @ts-ignore
484    this.titleEl!.textContent = pName + it.tableName;
485    // @ts-ignore
486    this.threadName = it.tableName;
487    this.perfAnalysisPie?.hideTip();
488  }
489
490  private initPerfAnalysisPieConfig(): void {
491    this.perfAnalysisPie!.config = {
492      appendPadding: 0,
493      data: this.getPerfPieChartData(this.soData),
494      angleField: 'count',
495      colorField: 'tableName',
496      radius: 1,
497      label: {
498        type: 'outer',
499      },
500      tip: (processObj): string => {
501        // @ts-ignore
502        const obj = processObj.obj as AnalysisObj;
503        return `<div>
504                <div>Library:${obj.tableName}</div>
505                <div>Sample Count:${obj.count}</div>
506                <div>Percent:${obj.percent}%</div>
507                <div>Event Count:${obj.eventCount}</div>
508                <div>Percent:${obj.eventPercent}%</div>
509                </div>`;
510      },
511      angleClick: (it): void => {
512        // @ts-ignore
513        if (it.tableName !== 'other') {
514          this.perfSoLevelClickEvent(it);
515        }
516      },
517      hoverHandler: (data): void => {
518        if (data) {
519          this.perfTableSo!.setCurrentHover(data);
520        } else {
521          this.perfTableSo!.mouseOut();
522        }
523      },
524      interactions: [
525        {
526          type: 'element-active',
527        },
528      ],
529    };
530  }
531
532  private libraryPieChart(): void {
533    // @ts-ignore
534    this.sumCount = this.allLibCount.allCount;
535    // @ts-ignore
536    this.sumEventCount = this.allLibCount.allEventCount;
537    this.initPerfAnalysisPieConfig();
538    let pName = this.processName;
539    if (this.processName.length > 0 && this.threadName.length > 0) {
540      pName = `${this.processName} / `;
541    }
542    this.titleEl!.textContent = pName + this.threadName;
543    this.tabName!.textContent = 'Statistic By Library Count';
544    this.soData.unshift(this.allLibCount);
545    this.perfTableSo!.recycleDataSource = this.soData;
546    this.perfTableSo?.reMeauseHeight();
547    // @ts-ignore
548    this.soData.shift(this.allLibCount);
549    this.currentLevelData = this.soData;
550  }
551
552  private perfSoLevelClickEvent(it: unknown): void {
553    this.reset(this.tableFunction!, true);
554    this.showAssignLevel(this.tableFunction!, this.perfTableSo!, 3, this.functionData);
555    // @ts-ignore
556    this.currentSoName = it.tableName;
557    this.getHiperfFunction(it);
558    let title = '';
559    if (this.processName.length > 0) {
560      title += `${this.processName} / `;
561    }
562    if (this.threadName.length > 0) {
563      title += `${this.threadName} / `;
564    }
565    // @ts-ignore
566    if (it.tableName.length > 0) {
567      // @ts-ignore
568      title += it.tableName;
569    }
570    this.titleEl!.textContent = title;
571    this.perfAnalysisPie?.hideTip();
572    // @ts-ignore
573    this.selectedTabfileName = it.tableName;
574  }
575
576  private functionClickEvent(it: unknown): void {
577    this.clickFuncVaddrList = this.vaddrList.filter((item: unknown) => {
578      // @ts-ignore
579      return item.process_id === it.pid &&
580        // @ts-ignore
581        item.thread_id === it.tid &&
582        // @ts-ignore
583        item.libName === this.selectedTabfileName &&
584        // @ts-ignore
585        item.symbolName === it.tableName;
586    });
587    if (this.clickFuncVaddrList.length > 0) {
588      const textEncoder = new TextEncoder();
589      const queryData = {
590        elf_name: this.currentSoName,
591        //@ts-ignore
592        vaddr: this.clickFuncVaddrList[0].vaddrInFile,
593        //@ts-ignore
594        func: it.tableName
595      };
596      const dataString = JSON.stringify(queryData);
597      const encodedData = textEncoder.encode(dataString);
598      WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_CMD, encodedData);
599    }
600    this.functionListener!(it, this.clickFuncVaddrList);
601  }
602
603  private sortByColumn(): void {
604    let currentTable: LitTable | null | undefined;
605    switch (this.currentLevel) {
606      case 0:
607        currentTable = this.perfTableProcess;
608        break;
609      case 1:
610        currentTable = this.perfTableThread;
611        break;
612      case 2:
613        currentTable = this.perfTableSo;
614        break;
615      case 3:
616        currentTable = this.tableFunction;
617        break;
618    }
619    if (!currentTable) {
620      return;
621    }
622    if (this.sortType === 0) {
623      let arr = [...this.currentLevelData];
624      switch (this.currentLevel) {
625        case 0:
626          arr.unshift(this.allProcessCount);
627          break;
628        case 1:
629          arr.unshift(this.allThreadCount);
630          break;
631        case 2:
632          arr.unshift(this.allLibCount);
633          break;
634        case 3:
635          arr.unshift(this.allSymbolCount);
636          break;
637      }
638      currentTable!.recycleDataSource = arr;
639    } else {
640      this.sortTypeNoZero(currentTable);
641    }
642  }
643
644  private sortTypeNoZero(currentTable: LitTable): void {
645    let array = [...this.currentLevelData];
646    if (this.sortColumn === 'tableName') {
647      currentTable!.recycleDataSource = array.sort((leftA, rightB) => {
648        if (this.sortType === 1) {
649          // @ts-ignore
650          if (leftA.tableName > rightB.tableName) {
651            return 1;
652            // @ts-ignore
653          } else if (leftA.tableName === rightB.tableName) {
654            return 0;
655          } else {
656            return -1;
657          }
658        } else {
659          // @ts-ignore
660          if (rightB.tableName > leftA.tableName) {
661            return 1;
662            // @ts-ignore
663          } else if (leftA.tableName === rightB.tableName) {
664            return 0;
665          } else {
666            return -1;
667          }
668        }
669      });
670    } else if (this.sortColumn === 'count' || this.sortColumn === 'percent') {
671      currentTable!.recycleDataSource = array.sort((a, b) => {
672        // @ts-ignore
673        return this.sortType === 1 ? a.count - b.count : b.count - a.count;
674      });
675    } else if (this.sortColumn === 'eventCount' || this.sortColumn === 'eventPercent') {
676      currentTable!.recycleDataSource = array.sort((a, b) => {
677        // @ts-ignore
678        return this.sortType === 1 ? a.eventCount - b.eventCount : b.eventCount - a.eventCount;
679      });
680    }
681    switch (this.currentLevel) {
682      case 0:
683        array.unshift(this.allProcessCount);
684        break;
685      case 1:
686        array.unshift(this.allThreadCount);
687        break;
688      case 2:
689        array.unshift(this.allLibCount);
690        break;
691      case 3:
692        array.unshift(this.allSymbolCount);
693        break;
694    }
695    currentTable!.recycleDataSource = array;
696  }
697
698  private initHiPerfProcessSelect(val: SelectionParam): void {
699    this.reset(this.perfTableProcess!, false);
700    this.progressEL!.loading = true;
701    if (!this.processData || this.processData.length === 0) {
702      this.progressEL!.loading = false;
703      if (val.perfThread.length > 0 && val.perfProcess.length === 0) {
704        this.threadData = [];
705        this.allThreadCount = [];
706        this.perfTableProcess!.style.display = 'none';
707        this.threadPieChart(val);
708      } else {
709        this.pidData = [];
710        this.allProcessCount = [];
711        this.processPieChart(val);
712      }
713      return;
714    }
715  }
716
717  async getHiperfProcess(val: SelectionParam): Promise<void> {
718    this.initHiPerfProcessSelect(val);
719    let allCount = 0;
720    let allEventCount = 0;
721    let pidMap = new Map<number, Array<number | string>>();
722    if (val.perfThread.length > 0 && val.perfProcess.length === 0) {
723      this.perfTableProcess!.style.display = 'none';
724      this.getHiperfThread(null, val);
725    } else {
726      for (let itemData of this.processData) {
727        // @ts-ignore
728        allCount += itemData.count;
729        // @ts-ignore
730        allEventCount += itemData.eventCount;
731        // @ts-ignore
732        if (pidMap.has(itemData.pid)) {
733          // @ts-ignore
734          pidMap.get(itemData.pid)?.push(itemData);
735        } else {
736          let itemArray: Array<number | string> = [];
737          // @ts-ignore
738          itemArray.push(itemData);
739          // @ts-ignore
740          pidMap.set(itemData.pid, itemArray);
741        }
742      }
743      this.pidData = [];
744      pidMap.forEach((arr: Array<unknown>, pid: number) => {
745        let count = 0;
746        let eventCount = 0;
747        for (let item of arr) {
748          // @ts-ignore
749          count += item.count;
750          // @ts-ignore
751          eventCount += item.eventCount;
752        }
753        // @ts-ignore
754        const pName = `${arr[0].processName}(${pid})`;
755        const pidData = {
756          tableName: pName,
757          pid: pid,
758          percent: ((count / allCount) * 100).toFixed(2),
759          count: count,
760          eventCount: eventCount,
761          eventPercent: ((eventCount / allEventCount) * 100).toFixed(2),
762        };
763        this.pidData.push(pidData);
764      });
765      // @ts-ignore
766      this.pidData.sort((a, b) => b.count - a.count);
767      this.allProcessCount = this.totalCountData(allCount, allEventCount);
768      this.currentLevel = 0;
769      this.progressEL!.loading = false;
770      this.processPieChart(val);
771    }
772  }
773
774  private getHiperfThread(item: unknown, val: SelectionParam): void {
775    this.progressEL!.loading = true;
776    let threadMap = new Map<number, Array<number | string>>();
777    let allCount = 0;
778    let allEventCount = 0;
779    if (!this.processData || this.processData.length === 0) {
780      return;
781    }
782    for (let itemData of this.processData) {
783      // @ts-ignore
784      if (item && itemData.pid !== item.pid && !this.hideProcessCheckBox?.checked) {
785        continue;
786      }
787      // @ts-ignore
788      allCount += itemData.count;
789      // @ts-ignore
790      allEventCount += itemData.eventCount;
791      // @ts-ignore
792      if (threadMap.has(itemData.tid)) {
793        // @ts-ignore
794        threadMap.get(itemData.tid)?.push(itemData);
795      } else {
796        let itemArray: Array<number | string> = [];
797        // @ts-ignore
798        itemArray.push(itemData);
799        // @ts-ignore
800        threadMap.set(itemData.tid, itemArray);
801      }
802    }
803    this.threadData = [];
804    threadMap.forEach((arr: Array<unknown>, tid: number) => {
805      let threadCount = 0;
806      let threadEventCount = 0;
807      // @ts-ignore
808      let tName = `${arr[0].threadName}(${tid})`;
809      for (let item of arr) {
810        // @ts-ignore
811        threadCount += item.count;
812        // @ts-ignore
813        threadEventCount += item.eventCount;
814      }
815      const threadData = {
816        // @ts-ignore
817        pid: item === null ? arr[0].pid : item.pid,
818        tid: tid,
819        tableName: tName,
820        count: threadCount,
821        percent: ((threadCount / allCount) * 100).toFixed(2),
822        eventCount: threadEventCount,
823        eventPercent: ((threadEventCount / allEventCount) * 100).toFixed(2),
824      };
825      this.threadData.push(threadData);
826    });
827    this.allThreadCount = this.totalCountData(allCount, allEventCount);
828    this.currentLevel = 1;
829    // @ts-ignore
830    this.threadData.sort((a, b) => b.count - a.count);
831    this.progressEL!.loading = false;
832    this.threadPieChart(val);
833  }
834
835  private getHiPerfSoIdByProcessData(item: unknown, itemData: unknown): boolean {
836    if (!this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
837      // @ts-ignore
838      if (item && (itemData.pid !== item.pid || itemData.tid !== item.tid)) {
839        return true;
840      }
841    } else if (!this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
842      // @ts-ignore
843      if (item && itemData.pid !== item.pid) {
844        return true;
845      }
846    } else if (this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
847      // @ts-ignore
848      if (item && itemData.tid !== item.tid) {
849        return true;
850      }
851    }
852    return false;
853  }
854
855  private getHiperfSo(item: unknown, val: SelectionParam): void {
856    this.progressEL!.loading = true;
857    let parentEventCount = 0;
858    let allCount = 0;
859    let allEventCount = 0;
860    let libMap = new Map<string, Array<number | string>>();
861    if (!this.processData || this.processData.length === 0) {
862      return;
863    }
864    for (let itemData of this.processData) {
865      if (this.getHiPerfSoIdByProcessData(item, itemData)) {
866        continue;
867      }
868      // @ts-ignore
869      allCount += itemData.count;
870      // @ts-ignore
871      allEventCount += itemData.eventCount;
872      // @ts-ignore
873      if (libMap.has(`${itemData.libId}-${itemData.libName}`)) {
874        // @ts-ignore
875        libMap.get(`${itemData.libId}-${itemData.libName}`)?.push(itemData);
876      } else {
877        let dataArray: Array<number | string> = [];
878        // @ts-ignore
879        dataArray.push(itemData);
880        // @ts-ignore
881        libMap.set(`${itemData.libId}-${itemData.libName}`, dataArray);
882      }
883    }
884    // @ts-ignore
885    item ? (parentEventCount = item.eventCount) : (parentEventCount = allEventCount);
886    this.soData = [];
887    libMap.forEach((arr: Array<unknown>) => {
888      let libCount = 0;
889      let libEventCount = 0;
890      // @ts-ignore
891      let libName = arr[0].libName;
892      // @ts-ignore
893      let libId = arr[0].libId;
894      for (let item of arr) {
895        // @ts-ignore
896        libCount += item.count;
897        // @ts-ignore
898        libEventCount += item.eventCount;
899      }
900      const libData = {
901        // @ts-ignore
902        pid: item === null ? arr[0].pid : item.pid,
903        // @ts-ignore
904        tid: item === null ? arr[0].tid : item.tid,
905        percent: ((libCount / allCount) * 100).toFixed(2),
906        count: libCount,
907        eventPercent: ((libEventCount / parentEventCount) * 100).toFixed(2),
908        eventCount: libEventCount,
909        tableName: libName,
910        libId: libId,
911      };
912      this.soData.push(libData);
913    });
914    this.initPerfSoData(allCount, allEventCount);
915  }
916
917  private initPerfSoData(allCount: number, allEventCount: number): void {
918    this.allLibCount = this.totalCountData(allCount, allEventCount);
919    // @ts-ignore
920    this.soData.sort((a, b) => b.count - a.count);
921    this.currentLevel = 2;
922    this.progressEL!.loading = false;
923    this.libraryPieChart();
924  }
925
926  private getHiperfFunction(item: unknown): void {
927    this.progressEL!.loading = true;
928    this.shadowRoot!.querySelector<HTMLDivElement>('.perf-subheading')!.textContent = 'Statistic By Function Count';
929    // @ts-ignore
930    let parentCount = item.count;
931    // @ts-ignore
932    let parentEventCount = item.eventCount;
933    let allCount = 0;
934    let allEventCount = 0;
935    let symbolMap = new Map<string, Array<unknown>>();
936    if (!this.processData || this.processData.length === 0) {
937      return;
938    }
939    for (let itemData of this.processData) {
940      if (this.getIdByProcessData(itemData, item)) {
941        continue;
942      }
943      // @ts-ignore
944      allCount += itemData.count;
945      // @ts-ignore
946      allEventCount += itemData.eventCount;
947      // @ts-ignore
948      if (symbolMap.has(`${itemData.symbolId}-${itemData.symbolName}`)) {
949        // @ts-ignore
950        symbolMap.get(`${itemData.symbolId}-${itemData.symbolName}`)?.push(itemData);
951      } else {
952        let dataArray: Array<number | string> = [];
953        // @ts-ignore
954        dataArray.push(itemData);
955        // @ts-ignore
956        symbolMap.set(`${itemData.symbolId}-${itemData.symbolName}`, dataArray);
957      }
958    }
959    this.functionData = [];
960    symbolMap.forEach((arr) => {
961      let symbolCount = 0;
962      let symbolEventCount = 0;
963      for (let item of arr) {
964        // @ts-ignore
965        symbolCount += item.count;
966        // @ts-ignore
967        symbolEventCount += item.eventCount;
968      }
969      // @ts-ignore
970      let symbolName = arr[0].symbolName;
971      // @ts-ignore
972      let symbolId = arr[0].symbolId;
973      const symbolData = {
974        // @ts-ignore
975        pid: item.pid,
976        // @ts-ignore
977        tid: item.tid,
978        // @ts-ignore
979        libId: item.libId,
980        percent: ((symbolCount / parentCount) * 100).toFixed(2),
981        count: symbolCount,
982        symbolId: symbolId,
983        eventPercent: ((symbolEventCount / parentEventCount) * 100).toFixed(2),
984        eventCount: symbolEventCount,
985        tableName: symbolName,
986      };
987      this.functionData.push(symbolData);
988    });
989    this.initPerfFunData(allCount, allEventCount);
990  }
991
992  private getIdByProcessData(itemData: unknown, item: unknown): boolean {
993    // @ts-ignore
994    let tid = item.tid;
995    // @ts-ignore
996    let pid = item.pid;
997    // @ts-ignore
998    let libId = item.libId;
999    let isContinue = false;
1000    if (!this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
1001      // @ts-ignore
1002      if (itemData.pid !== pid || itemData.tid !== tid || itemData.libId !== libId) {
1003        isContinue = true;
1004      }
1005    } else if (!this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
1006      // @ts-ignore
1007      if (itemData.pid !== pid || itemData.libId !== libId) {
1008        isContinue = true;
1009      }
1010    } else if (this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
1011      // @ts-ignore
1012      if (itemData.tid !== tid || itemData.libId !== libId) {
1013        isContinue = true;
1014      }
1015    } else if (this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
1016      // @ts-ignore
1017      if (itemData.libId !== libId) {
1018        isContinue = true;
1019      }
1020    }
1021    return isContinue;
1022  }
1023
1024  private initPerfFunData(allCount: number, allEventCount: number): void {
1025    // @ts-ignore
1026    this.functionData.sort((a, b) => b.count - a.count);
1027    this.allSymbolCount = this.totalCountData(allCount, allEventCount);
1028    this.currentLevel = 3;
1029    this.progressEL!.loading = false;
1030    // @ts-ignore
1031    this.sumCount = this.allSymbolCount.allCount;
1032    // @ts-ignore
1033    this.sumEventCount = this.allSymbolCount.allEventCount;
1034    this.perfAnalysisPie!.config = {
1035      appendPadding: 0,
1036      data: this.getPerfPieChartData(this.functionData),
1037      angleField: 'count',
1038      colorField: 'tableName',
1039      radius: 1,
1040      label: {
1041        type: 'outer',
1042      },
1043      // @ts-ignore
1044      tip: this.getTip(),
1045      hoverHandler: (data): void => {
1046        if (data) {
1047          this.tableFunction!.setCurrentHover(data);
1048        } else {
1049          this.tableFunction!.mouseOut();
1050        }
1051      },
1052      interactions: [
1053        {
1054          type: 'element-active',
1055        },
1056      ],
1057    };
1058    this.functionData.unshift(this.allSymbolCount);
1059    this.tableFunction!.recycleDataSource = this.functionData;
1060    this.tableFunction?.reMeauseHeight();
1061    // @ts-ignore
1062    this.functionData.shift(this.allSymbolCount);
1063    this.currentLevelData = this.functionData;
1064  }
1065
1066  private getTip() {
1067    return (obj: {
1068      obj: { tableName: unknown; count: unknown; percent: unknown; eventCount: unknown; eventPercent: unknown };
1069    }): string => {
1070      return `<div>
1071                    <div>Function:${obj.obj.tableName}</div>
1072                    <div>Sample Count:${obj.obj.count}</div>
1073                    <div>Percent:${obj.obj.percent}%</div>
1074                    <div>Event Count:${obj.obj.eventCount}</div>
1075                    <div>Percent:${obj.obj.eventPercent}%</div>
1076                </div>`;
1077    };
1078  }
1079
1080  totalCountData(
1081    count: number,
1082    eventCount: number
1083  ): {
1084    percent: string;
1085    count: number;
1086    allCount: number;
1087    eventCount: number;
1088    eventPercent: string;
1089    allEventCount: number;
1090    pid: string;
1091  } {
1092    let allCount;
1093    allCount = {
1094      percent: ((count / count) * 100).toFixed(2),
1095      count: count,
1096      allCount: count,
1097      eventCount: eventCount,
1098      allEventCount: eventCount,
1099      eventPercent: '100.00',
1100      pid: '',
1101    };
1102    return allCount;
1103  }
1104
1105  private getPerfPieChartData(res: unknown[]): unknown[] {
1106    if (res.length > 20) {
1107      let pieChartArr: string[] = [];
1108      let other: unknown = {
1109        tableName: 'other',
1110        count: 0,
1111        percent: 0,
1112        eventCount: 0,
1113        eventPercent: 0,
1114      };
1115      for (let i = 0; i < res.length; i++) {
1116        if (i < 19) {
1117          // @ts-ignore
1118          pieChartArr.push(res[i]);
1119        } else {
1120          // @ts-ignore
1121          other.count += res[i].count;
1122          // @ts-ignore
1123          other.percent = ((other.count / this.sumCount!) * 100).toFixed(2);
1124          // @ts-ignore
1125          other.eventCount += res[i].eventCount;
1126          // @ts-ignore
1127          other.eventPercent = ((other.eventCount / this.sumEventCount!) * 100).toFixed(2);
1128        }
1129      }
1130      // @ts-ignore
1131      pieChartArr.push(other);
1132      return pieChartArr;
1133    }
1134    return res;
1135  }
1136
1137  private getCallChainDataFromWorker(val: SelectionParam): void {
1138    this.getDataByWorker(val, (results: unknown) => {
1139      this.isComplete = true;
1140      if (this.currentSelectionParam !== val) {
1141        this.getCallChainDataFromWorker(this.currentSelectionParam!);
1142        return;
1143      }
1144      // @ts-ignore
1145      this.processData = results;
1146      if (this.processData.length === 0) {
1147        this.hideProcessCheckBox?.setAttribute('disabled', 'disabled');
1148        this.hideThreadCheckBox?.setAttribute('disabled', 'disabled');
1149      } else {
1150        this.hideProcessCheckBox?.removeAttribute('disabled');
1151        this.hideThreadCheckBox?.removeAttribute('disabled');
1152      }
1153      this.progressEL!.loading = false;
1154      this.getHiperfProcess(val);
1155      if (TabPanePerfAnalysis.tabLoadingList[0] === 'analysis') {
1156        TabPanePerfAnalysis.tabLoadingList.shift();
1157      }
1158    });
1159    const args = [
1160      {
1161        funcName: 'getVaddrToFile',
1162        funcArgs: [val],
1163      },
1164    ];
1165    procedurePool.submitWithName('logic0', 'perf-vaddr', args, undefined, (results: Array<unknown>) => {
1166      this.vaddrList = results;
1167    });
1168  }
1169
1170  private getDataByWorker(val: SelectionParam, handler: Function): void {
1171    this.progressEL!.loading = true;
1172    const args = [
1173      {
1174        funcName: 'setSearchValue',
1175        funcArgs: [''],
1176      },
1177      {
1178        funcName: 'getCurrentDataFromDbAnalysis',
1179        funcArgs: [val],
1180      },
1181    ];
1182    procedurePool.submitWithName('logic0', 'perf-action', args, undefined, (results: unknown) => {
1183      handler(results);
1184    });
1185  }
1186
1187  public connectedCallback(): void {
1188    new ResizeObserver(() => {
1189      this.perfTableProcess!.style.height = `${this.parentElement!.clientHeight - 50}px`;
1190      this.perfTableProcess?.reMeauseHeight();
1191      this.perfTableThread!.style.height = `${this.parentElement!.clientHeight - 50}px`;
1192      this.perfTableThread?.reMeauseHeight();
1193      this.tableFunction!.style.height = `${this.parentElement!.clientHeight - 50}px`;
1194      this.tableFunction?.reMeauseHeight();
1195      this.perfTableSo!.style.height = `${this.parentElement!.clientHeight - 50}px`;
1196      this.perfTableSo?.reMeauseHeight();
1197      if (this.parentElement!.clientHeight >= 0 && this.parentElement!.clientHeight <= 31) {
1198        this.filterEl!.style.display = 'none';
1199      } else {
1200        this.filterEl!.style.display = 'flex';
1201      }
1202    }).observe(this.parentElement!);
1203  }
1204
1205  public addFunctionRowClickEventListener(clickEvent: Function): void {
1206    this.functionListener = clickEvent;
1207  }
1208
1209  initHtml(): string {
1210    return TabPanePerfAnalysisHtml;
1211  }
1212}
1213