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