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