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