• 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 { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar';
19import { FrameChart } from '../../../chart/FrameChart';
20import { SelectionParam } from '../../../../bean/BoxSelection';
21import { ChartMode } from '../../../../bean/FrameChartStruct';
22import { FilterData, TabPaneFilter } from '../TabPaneFilter';
23import { procedurePool } from '../../../../database/Procedure';
24import { MerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon';
25import { showButtonMenu } from '../SheetUtils';
26import { CallTreeLevelStruct } from '../../../../bean/EbpfStruct';
27import '../../../../../base-ui/headline/lit-headline';
28import { LitHeadLine } from '../../../../../base-ui/headline/lit-headline';
29import { NUM_3, NUM_4 } from '../../../../bean/NumBean';
30import { TabPaneCallTreeHtml } from './TabPaneCallTree.html';
31
32const InvertOptionIndex: number = 0;
33const hideEventOptionIndex: number = 2;
34const hideThreadOptionIndex: number = 3;
35
36@element('tabpane-calltree')
37export class TabPaneCallTree extends BaseElement {
38  public queryFuncName: string = '';
39  public procedureAction: string = '';
40  private callTreeTbl: LitTable | null | undefined;
41  private callTreeTbr: LitTable | null | undefined;
42  private callTreeProgressEL: LitProgressBar | null | undefined;
43  private callTreeRightSource: Array<MerageBean> = [];
44  private callTreeFilter: TabPaneFilter | null | undefined;
45  private callTreeDataSource: any[] = [];
46  private callTreeSortKey: string = 'weight';
47  private callTreeSortType: number = 0;
48  private callTreeSelectedData: any = undefined;
49  private frameChart: FrameChart | null | undefined;
50  private isChartShow: boolean = false;
51  private systmeRuleName: string = '/system/';
52  private callTreeNumRuleName: string = '/max/min/';
53  private needShowMenu: boolean = true;
54  private searchValue: string = '';
55  private loadingList: number[] = [];
56  private loadingPage: any;
57  private currentSelection: SelectionParam | undefined;
58  private flameChartMode: ChartMode = ChartMode.Duration;
59  private currentCallTreeDataSource: Array<MerageBean> = [];
60  private currentRowClickData: any;
61  private initWidth: number = 0;
62  private _pieTitle: string = '';
63  private _cWidth: number = 0;
64  private _currentCallTreeLevel: number = 0;
65  private _rowClickData: any = undefined;
66  private callTreeLevel: CallTreeLevelStruct | undefined | null;
67  private callTreeHeadLine: LitHeadLine | null | undefined;
68
69  set pieTitle(value: string) {
70    this._pieTitle = value;
71    if (this._pieTitle.length > 0) {
72      this.callTreeHeadLine!.isShow = true;
73      this.callTreeHeadLine!.titleTxt = this._pieTitle;
74      this.callTreeHeadLine!.closeCallback = (): void => {
75        this.restore();
76      };
77    }
78  }
79
80  set cWidth(value: number) {
81    this._cWidth = value;
82  }
83
84  set currentCallTreeLevel(value: number) {
85    this._currentCallTreeLevel = value;
86  }
87
88  set rowClickData(value: any) {
89    this._rowClickData = value;
90  }
91
92  set data(callTreeSelection: SelectionParam | any) {
93    if (callTreeSelection !== this.currentSelection && this._rowClickData === this.currentRowClickData) {
94      this._rowClickData = undefined;
95    }
96    if (callTreeSelection === this.currentSelection && !this.currentSelection?.isRowClick) {
97      return;
98    }
99    this.searchValue = '';
100    this.initModeAndAction();
101    this.currentSelection = callTreeSelection;
102    this.currentRowClickData = this._rowClickData;
103    this.callTreeTbl!.style.visibility = 'visible';
104    if (this.parentElement!.clientHeight > this.callTreeFilter!.clientHeight) {
105      this.callTreeFilter!.style.display = 'flex';
106    } else {
107      this.callTreeFilter!.style.display = 'none';
108    }
109    procedurePool.submitWithName('logic0', 'fileSystem-reset', [], undefined, () => {});
110    this.callTreeFilter!.initializeFilterTree(true, true, true);
111    this.callTreeFilter!.filterValue = '';
112    this.callTreeProgressEL!.loading = true;
113    this.loadingPage.style.visibility = 'visible';
114    this.getDataByWorkAndUpDateCanvas(callTreeSelection);
115  }
116
117  getDataByWorkAndUpDateCanvas(callTreeSelection: SelectionParam): void {
118    if (this.clientWidth === 0) {
119      this.initWidth = this._cWidth;
120    } else {
121      this.initWidth = this.clientWidth;
122    }
123    if (this._rowClickData && this.currentRowClickData !== undefined && this.currentSelection?.isRowClick) {
124      this.getCallTreeDataByPieLevel();
125    } else {
126      this.callTreeHeadLine!.isShow = false;
127      this.getCallTreeData(callTreeSelection, this.initWidth);
128    }
129  }
130
131  private getCallTreeData(callTreeSelection: SelectionParam | any, initWidth: number): void {
132    this.getDataByWorker(
133      [
134        {
135          funcName: 'setSearchValue',
136          funcArgs: [''],
137        },
138        {
139          funcName: 'getCurrentDataFromDb',
140          funcArgs: [{ queryFuncName: this.queryFuncName, ...callTreeSelection }],
141        },
142      ],
143      (results: any[]) => {
144        this.setLTableData(results);
145        this.callTreeTbr!.recycleDataSource = [];
146        this.frameChart!.mode = this.flameChartMode;
147        this.frameChart?.updateCanvas(true, initWidth);
148        this.frameChart!.data = this.callTreeDataSource;
149        this.currentCallTreeDataSource = this.callTreeDataSource;
150        this.switchFlameChart();
151        this.callTreeFilter!.icon = 'block';
152      }
153    );
154  }
155
156  /**
157   * 根据Analysis Tab饼图跳转过来的层级绘制对应的CallTree Tab火焰图和表格
158   */
159  private getCallTreeDataByPieLevel(): void {
160    this.callTreeLevel = new CallTreeLevelStruct();
161    this.callTreeLevel = {
162      processId: this._rowClickData.pid,
163      threadId: this._rowClickData.tid,
164      typeId: this._rowClickData.type,
165      libId: this._rowClickData.libId,
166      symbolId: this._rowClickData.symbolId,
167    };
168    let args = [];
169    args.push({
170      funcName: 'getCurrentDataFromDb',
171      funcArgs: [this.currentSelection, this.callTreeLevel],
172    });
173
174    if (this._rowClickData && this._rowClickData.libId !== undefined && this._currentCallTreeLevel === NUM_3) {
175      this.callTreeLevel.libName = this._rowClickData.tableName;
176      args.push({
177        funcName: 'showLibLevelData',
178        funcArgs: [this.callTreeLevel.libId, this.callTreeLevel.libName],
179      });
180    } else if (
181      this._rowClickData &&
182      this._rowClickData.symbolId !== undefined &&
183      this._currentCallTreeLevel === NUM_4
184    ) {
185      this.callTreeLevel.symbolName = this._rowClickData.tableName;
186      args.push({
187        funcName: 'showFunLevelData',
188        funcArgs: [this.callTreeLevel.symbolId, this.callTreeLevel.symbolName],
189      });
190    }
191
192    this.getDataByWorker(args, (results: any[]) => {
193      this.callTreeProgressEL!.loading = false;
194      this.loadingPage.style.visibility = 'hidden';
195      this.setLTableData(results);
196      this.callTreeTbr!.recycleDataSource = [];
197      this.frameChart!.mode = this.flameChartMode;
198      this.frameChart?.updateCanvas(true, this.initWidth);
199      this.frameChart!.data = this.callTreeDataSource;
200      this.currentCallTreeDataSource = this.callTreeDataSource;
201      this.switchFlameChart();
202      this.callTreeFilter!.icon = 'block';
203    });
204  }
205
206  private restore(): void {
207    this.searchValue = '';
208    this.callTreeFilter!.filterValue = '';
209    this.callTreeHeadLine!.isShow = false;
210    this._rowClickData = undefined;
211    this.getCallTreeData(this.currentSelection, this.initWidth);
212  }
213
214  initModeAndAction(): void {
215    if (this.procedureAction === '' && this.hasAttribute('action')) {
216      this.procedureAction = this.getAttribute('action') || '';
217    }
218    if (this.hasAttribute('flame-mode')) {
219      let callTreeFlameMode = this.getAttribute('flame-mode');
220      switch (callTreeFlameMode) {
221        case 'Byte':
222          this.flameChartMode = ChartMode.Byte;
223          break;
224        case 'Count':
225          this.flameChartMode = ChartMode.Count;
226          break;
227        case 'Duration':
228          this.flameChartMode = ChartMode.Duration;
229          break;
230      }
231    }
232    if (this.hasAttribute('query')) {
233      this.queryFuncName = this.getAttribute('query') || '';
234    }
235  }
236
237  getParentTree(callTreeSrc: Array<MerageBean>, target: MerageBean, parents: Array<MerageBean>): boolean {
238    for (let callTreeBean of callTreeSrc) {
239      if (callTreeBean.id === target.id) {
240        parents.push(callTreeBean);
241        return true;
242      } else {
243        if (this.getParentTree(callTreeBean.children as Array<MerageBean>, target, parents)) {
244          parents.push(callTreeBean);
245          return true;
246        }
247      }
248    }
249    return false;
250  }
251
252  getChildTree(callTreeSrc: Array<MerageBean>, id: string, children: Array<MerageBean>): boolean {
253    for (let callTreeBean of callTreeSrc) {
254      if (callTreeBean.id === id && callTreeBean.children.length === 0) {
255        children.push(callTreeBean);
256        return true;
257      } else {
258        if (this.getChildTree(callTreeBean.children as Array<MerageBean>, id, children)) {
259          children.push(callTreeBean);
260          return true;
261        }
262      }
263    }
264    return false;
265  }
266
267  setRightTableData(bean: MerageBean): void {
268    let parents: Array<MerageBean> = [];
269    let children: Array<MerageBean> = [];
270    this.getParentTree(this.callTreeDataSource, bean, parents);
271    let maxId: string = bean.id;
272    let maxDur: number = 0;
273
274    function findMaxStack(bean: MerageBean): void {
275      if (bean.children.length === 0) {
276        if (bean.dur > maxDur) {
277          maxDur = bean.dur;
278          maxId = bean.id;
279        }
280      } else {
281        bean.children.map((callChild: any) => {
282          findMaxStack(<MerageBean>callChild);
283        });
284      }
285    }
286
287    findMaxStack(bean);
288    this.getChildTree(bean.children as Array<MerageBean>, maxId, children);
289    let callTreeArr = parents.reverse().concat(children.reverse());
290    for (let data of callTreeArr) {
291      data.type =
292        data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1;
293    }
294    let len = callTreeArr.length;
295    this.callTreeRightSource = callTreeArr;
296    this.callTreeTbr!.dataSource = len === 0 ? [] : callTreeArr;
297  }
298
299  connectedCallback(): void {
300    this.parentElement!.onscroll = (): void => {
301      this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop;
302    };
303    this.frameChart!.addChartClickListener((needShowMenu: boolean) => {
304      this.parentElement!.scrollTo(0, 0);
305      showButtonMenu(this.callTreeFilter, needShowMenu);
306      this.needShowMenu = needShowMenu;
307    });
308    let filterHeight = 0;
309    new ResizeObserver((entries: ResizeObserverEntry[]): void => {
310      let callTreeTabFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement;
311      if (callTreeTabFilter.clientHeight > 0) filterHeight = callTreeTabFilter.clientHeight;
312      if (this.parentElement!.clientHeight > filterHeight) {
313        callTreeTabFilter.style.display = 'flex';
314      } else {
315        callTreeTabFilter.style.display = 'none';
316      }
317      if (this.callTreeTbl!.style.visibility === 'hidden') {
318        callTreeTabFilter.style.display = 'none';
319      }
320      if (this.parentElement?.clientHeight !== 0) {
321        if (this.isChartShow) {
322          this.frameChart?.updateCanvas(false, entries[0].contentRect.width);
323          this.frameChart?.calculateChartData();
324        }
325        if (this.callTreeTbl) {
326          // @ts-ignore
327          this.callTreeTbl.shadowRoot.querySelector('.table').style.height =
328            this.parentElement!.clientHeight - 10 - 35 + 'px';
329          this.callTreeTbl.reMeauseHeight();
330        }
331        if (this.callTreeTbr) {
332          // @ts-ignore
333          this.callTreeTbr.shadowRoot.querySelector('.table').style.height =
334            this.parentElement!.clientHeight - 45 - 21 + 'px';
335          this.callTreeTbr.reMeauseHeight();
336        }
337        this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px';
338      }
339    }).observe(this.parentElement!);
340  }
341
342  initElements(): void {
343    this.callTreeHeadLine = this.shadowRoot?.querySelector<LitHeadLine>('.titleBox');
344    this.callTreeTbl = this.shadowRoot?.querySelector<LitTable>('#tb-calltree');
345    this.callTreeProgressEL = this.shadowRoot?.querySelector('.call-tree-progress') as LitProgressBar;
346    this.frameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart');
347    this.loadingPage = this.shadowRoot?.querySelector('.call-tree-loading');
348    this.callTreeTbl!.rememberScrollTop = true;
349    this.callTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#filter');
350    this.callTreeFilter!.disabledTransfer(true);
351    this.addEventListener('contextmenu', (event) => {
352      event.preventDefault(); // 阻止默认的上下文菜单弹框
353    });
354    this.rowClickEvent();
355    let boundFilterFunc = this.filterFunc.bind(this);
356    this.callTreeFilter!.getDataLibrary(boundFilterFunc);
357    this.callTreeFilter!.getDataMining(boundFilterFunc);
358    this.handleCallTreeData();
359    this.handleConstraintsData();
360    this.handleFilterData();
361    this.callTreeColumnClick();
362  }
363
364  private filterFunc(data: any): void {
365    let callTreeFuncArgs: any[] = [];
366    if (data.type === 'check') {
367      this.handleCheckType(data, callTreeFuncArgs);
368    } else if (data.type === 'select') {
369      this.handleSelectType(callTreeFuncArgs, data);
370    } else if (data.type === 'button') {
371      if (data.item === 'symbol') {
372        if (this.callTreeSelectedData && !this.callTreeSelectedData.canCharge) {
373          return;
374        }
375        if (this.callTreeSelectedData !== undefined) {
376          this.handleSymbolCase(data, callTreeFuncArgs);
377        } else {
378          return;
379        }
380      } else if (data.item === 'library') {
381        if (this.callTreeSelectedData && !this.callTreeSelectedData.canCharge) {
382          return;
383        }
384        if (this.callTreeSelectedData !== undefined && this.callTreeSelectedData.libName !== '') {
385          this.handleLibraryCase(data, callTreeFuncArgs);
386        } else {
387          return;
388        }
389      } else if (data.item === 'restore') {
390        this.handleRestoreCase(data, callTreeFuncArgs);
391      }
392    }
393    this.performDataProcessing(callTreeFuncArgs);
394  }
395
396  private handleLibraryCase(data: any, callTreeFuncArgs: any[]): void {
397    this.callTreeFilter!.addDataMining({ name: this.callTreeSelectedData.libName }, data.item);
398    callTreeFuncArgs.push({
399      funcName: 'splitTree',
400      funcArgs: [this.callTreeSelectedData.libName, false, false],
401    });
402  }
403
404  private handleSymbolCase(data: any, callTreeFuncArgs: any[]): void {
405    this.callTreeFilter!.addDataMining({ name: this.callTreeSelectedData.symbolName }, data.item);
406    callTreeFuncArgs.push({
407      funcName: 'splitTree',
408      funcArgs: [this.callTreeSelectedData.symbolName, false, true],
409    });
410  }
411
412  private callTreeColumnClick(): void {
413    this.callTreeTbl!.addEventListener('column-click', (evt: Event): void => {
414      // @ts-ignore
415      this.callTreeSortKey = evt.detail.key;
416      // @ts-ignore
417      this.callTreeSortType = evt.detail.sort;
418      // @ts-ignore
419      this.setLTableData(this.callTreeDataSource);
420      this.frameChart!.data = this.callTreeDataSource;
421    });
422  }
423
424  private performDataProcessing(callTreeFuncArgs: any[]): void {
425    this.getDataByWorker(callTreeFuncArgs, (result: any[]) => {
426      this.setLTableData(result);
427      this.frameChart!.data = this.callTreeDataSource;
428      if (this.isChartShow) this.frameChart?.calculateChartData();
429      this.callTreeTbl!.move1px();
430      if (this.callTreeSelectedData) {
431        this.callTreeSelectedData.isSelected = false;
432        this.callTreeTbl?.clearAllSelection(this.callTreeSelectedData);
433        this.callTreeTbr!.recycleDataSource = [];
434        this.callTreeSelectedData = undefined;
435      }
436    });
437  }
438
439  private handleRestoreCase(data: any, callTreeFuncArgs: any[]): void {
440    if (data.remove !== undefined && data.remove.length > 0) {
441      let list = data.remove.map((item: any) => {
442        return item.name;
443      });
444      callTreeFuncArgs.push({
445        funcName: 'resotreAllNode',
446        funcArgs: [list],
447      });
448      callTreeFuncArgs.push({
449        funcName: 'resetAllNode',
450        funcArgs: [],
451      });
452      list.forEach((symbolName: string) => {
453        callTreeFuncArgs.push({
454          funcName: 'clearSplitMapData',
455          funcArgs: [symbolName],
456        });
457      });
458    }
459  }
460
461  private handleFilterData(): void {
462    this.callTreeFilter!.getFilterData((callTreeFilterData: FilterData) => {
463      if (this.searchValue !== this.callTreeFilter!.filterValue) {
464        this.searchValue = this.callTreeFilter!.filterValue;
465        let callTreeArgs = [
466          {
467            funcName: 'setSearchValue',
468            funcArgs: [this.searchValue],
469          },
470          {
471            funcName: 'resetAllNode',
472            funcArgs: [],
473          },
474        ];
475        this.getDataByWorker(callTreeArgs, (result: any[]): void => {
476          this.callTreeTbl!.isSearch = true;
477          this.callTreeTbl!.setStatus(result, true);
478          this.setLTableData(result);
479          this.frameChart!.data = this.callTreeDataSource;
480          this.switchFlameChart(callTreeFilterData);
481        });
482      } else {
483        this.callTreeTbl!.setStatus(this.callTreeDataSource, true);
484        this.setLTableData(this.callTreeDataSource);
485        this.switchFlameChart(callTreeFilterData);
486      }
487    });
488  }
489
490  private handleConstraintsData(): void {
491    this.callTreeFilter!.getCallTreeConstraintsData((data: any) => {
492      let callTreeConstraintsArgs: any[] = [
493        {
494          funcName: 'resotreAllNode',
495          funcArgs: [[this.callTreeNumRuleName]],
496        },
497        {
498          funcName: 'clearSplitMapData',
499          funcArgs: [this.callTreeNumRuleName],
500        },
501      ];
502      if (data.checked) {
503        callTreeConstraintsArgs.push({
504          funcName: 'hideNumMaxAndMin',
505          funcArgs: [parseInt(data.min), data.max],
506        });
507      }
508      callTreeConstraintsArgs.push({
509        funcName: 'resetAllNode',
510        funcArgs: [],
511      });
512      this.getDataByWorker(callTreeConstraintsArgs, (result: any[]) => {
513        this.setLTableData(result);
514        this.frameChart!.data = this.callTreeDataSource;
515        if (this.isChartShow) this.frameChart?.calculateChartData();
516      });
517    });
518  }
519
520  private handleCallTreeData(): void {
521    this.callTreeFilter!.getCallTreeData((data: any) => {
522      if ([InvertOptionIndex, hideThreadOptionIndex, hideEventOptionIndex].includes(data.value)) {
523        this.refreshAllNode({
524          ...this.callTreeFilter!.getFilterTreeData(),
525          callTree: data.checks,
526        });
527      } else {
528        let callTreeArgs: any[] = [];
529        if (data.checks[1]) {
530          callTreeArgs.push({
531            funcName: 'hideSystemLibrary',
532            funcArgs: [true],
533          });
534          callTreeArgs.push({
535            funcName: 'resetAllNode',
536            funcArgs: [],
537          });
538        } else {
539          callTreeArgs.push({
540            funcName: 'resotreAllNode',
541            funcArgs: [[this.systmeRuleName]],
542          });
543          callTreeArgs.push({
544            funcName: 'resetAllNode',
545            funcArgs: [],
546          });
547          callTreeArgs.push({
548            funcName: 'clearSplitMapData',
549            funcArgs: [this.systmeRuleName],
550          });
551        }
552        this.getDataByWorker(callTreeArgs, (result: any[]) => {
553          this.setLTableData(result);
554          this.frameChart!.data = this.callTreeDataSource;
555          if (this.isChartShow) {
556            this.frameChart?.calculateChartData();
557          }
558        });
559      }
560    });
561  }
562
563  private handleSelectType(callTreeFuncArgs: any[], data: any): void {
564    callTreeFuncArgs.push({
565      funcName: 'resotreAllNode',
566      funcArgs: [[data.item.name]],
567    });
568    callTreeFuncArgs.push({
569      funcName: 'clearSplitMapData',
570      funcArgs: [data.item.name],
571    });
572    callTreeFuncArgs.push({
573      funcName: 'splitTree',
574      funcArgs: [data.item.name, data.item.select === '0', data.item.type === 'symbol'],
575    });
576  }
577
578  private handleCheckType(data: any, callTreeFuncArgs: any[]): void {
579    if (data.item.checked) {
580      callTreeFuncArgs.push({
581        funcName: 'splitTree',
582        funcArgs: [data.item.name, data.item.select === '0', data.item.type === 'symbol'],
583      });
584    } else {
585      callTreeFuncArgs.push({
586        funcName: 'resotreAllNode',
587        funcArgs: [[data.item.name]],
588      });
589      callTreeFuncArgs.push({
590        funcName: 'resetAllNode',
591        funcArgs: [],
592      });
593      callTreeFuncArgs.push({
594        funcName: 'clearSplitMapData',
595        funcArgs: [data.item.name],
596      });
597    }
598  }
599
600  private rowClickEvent(): void {
601    this.callTreeTbl!.addEventListener('row-click', (evt: any) => {
602      // @ts-ignore
603      let data = evt.detail.data as MerageBean;
604      document.dispatchEvent(
605        new CustomEvent('number_calibration', {
606          detail: { time: data.tsArray, durations: data.durArray },
607        })
608      );
609      this.setRightTableData(data);
610      data.isSelected = true;
611      this.callTreeSelectedData = data;
612      this.callTreeTbr?.clearAllSelection(data);
613      this.callTreeTbr?.setCurrentSelection(data);
614      // @ts-ignore
615      if ((evt.detail as any).callBack) {
616        // @ts-ignore
617        (evt.detail as any).callBack(true);
618      }
619    });
620    this.callTreeTbr = this.shadowRoot?.querySelector<LitTable>('#tb-list');
621    this.callTreeTbr!.addEventListener('row-click', (evt: any): void => {
622      // @ts-ignore
623      let data = evt.detail.data as MerageBean;
624      this.callTreeTbl?.clearAllSelection(data);
625      (data as any).isSelected = true;
626      this.callTreeTbl!.scrollToData(data);
627      // @ts-ignore
628      if ((evt.detail as any).callBack) {
629        // @ts-ignore
630        (evt.detail as any).callBack(true);
631      }
632    });
633  }
634
635  switchFlameChart(data?: any): void {
636    let callTreePageTab = this.shadowRoot?.querySelector('#show_table');
637    let callTreePageChart = this.shadowRoot?.querySelector('#show_chart');
638    if (!data || data.icon === 'block') {
639      callTreePageChart?.setAttribute('class', 'show');
640      callTreePageTab?.setAttribute('class', '');
641      this.isChartShow = true;
642      this.callTreeFilter!.disabledMining = true;
643      showButtonMenu(this.callTreeFilter, this.needShowMenu);
644      this.frameChart?.calculateChartData();
645    } else if (data.icon === 'tree') {
646      callTreePageChart?.setAttribute('class', '');
647      callTreePageTab?.setAttribute('class', 'show');
648      showButtonMenu(this.callTreeFilter, true);
649      this.isChartShow = false;
650      this.callTreeFilter!.disabledMining = false;
651      this.frameChart!.clearCanvas();
652      this.callTreeTbl!.reMeauseHeight();
653    }
654  }
655
656  refreshAllNode(filterData: any): void {
657    let callTreeArgs: any[] = [];
658    let isTopDown: boolean = !filterData.callTree[0];
659    let isHideSystemLibrary = filterData.callTree[1];
660    let isHideEvent: boolean = filterData.callTree[2];
661    let isHideThread: boolean = filterData.callTree[3];
662    let list = filterData.dataMining.concat(filterData.dataLibrary);
663    callTreeArgs.push({ funcName: 'hideThread', funcArgs: [isHideThread] });
664    callTreeArgs.push({ funcName: 'hideEvent', funcArgs: [isHideEvent] });
665    callTreeArgs.push({ funcName: 'getCallChainsBySampleIds', funcArgs: [isTopDown, this.queryFuncName] });
666    this.callTreeTbr!.recycleDataSource = [];
667    if (isHideSystemLibrary) {
668      callTreeArgs.push({ funcName: 'hideSystemLibrary', funcArgs: [true] });
669    }
670    if (filterData.callTreeConstraints.checked) {
671      callTreeArgs.push({
672        funcName: 'hideNumMaxAndMin',
673        funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]],
674      });
675    }
676    callTreeArgs.push({ funcName: 'splitAllProcess', funcArgs: [list] });
677    callTreeArgs.push({
678      funcName: 'resetAllNode',
679      funcArgs: [],
680    });
681    if (this._rowClickData && this._rowClickData.libId !== undefined && this._currentCallTreeLevel === 3) {
682      callTreeArgs.push({
683        funcName: 'showLibLevelData',
684        funcArgs: [this.callTreeLevel!.libId, this.callTreeLevel!.libName],
685      });
686    } else if (this._rowClickData && this._rowClickData.symbolId !== undefined && this._currentCallTreeLevel === 4) {
687      callTreeArgs.push({
688        funcName: 'showFunLevelData',
689        funcArgs: [this.callTreeLevel!.symbolId, this.callTreeLevel!.symbolName],
690      });
691    }
692    this.getDataByWorker(callTreeArgs, (result: any[]): void => {
693      this.setLTableData(result);
694      this.frameChart!.data = this.callTreeDataSource;
695      if (this.isChartShow) this.frameChart?.calculateChartData();
696    });
697  }
698
699  setLTableData(resultData: any[]): void {
700    this.callTreeDataSource = this.sortCallFnTree(resultData);
701    this.callTreeTbl!.recycleDataSource = this.callTreeDataSource;
702  }
703
704  sortCallFnTree(arr: Array<any>): Array<any> {
705    let sortArr = arr.sort((compareFnA: any, compareFnB: any): number => {
706      if (this.callTreeSortKey === 'self') {
707        if (this.callTreeSortType === 0) {
708          return compareFnB.dur - compareFnA.dur;
709        } else if (this.callTreeSortType === 1) {
710          return compareFnA.selfDur - compareFnB.selfDur;
711        } else {
712          return compareFnB.selfDur - compareFnA.selfDur;
713        }
714      } else {
715        if (this.callTreeSortType === 0) {
716          return compareFnB.dur - compareFnA.dur;
717        } else if (this.callTreeSortType === 1) {
718          return compareFnA.dur - compareFnB.dur;
719        } else {
720          return compareFnB.dur - compareFnA.dur;
721        }
722      }
723    });
724    sortArr.map((call: any): void => {
725      call.children = this.sortCallFnTree(call.children);
726    });
727    return sortArr;
728  }
729
730  getDataByWorker(args: any[], handler: Function): void {
731    this.loadingList.push(1);
732    this.loadingPage.style.visibility = 'visible';
733    this.callTreeProgressEL!.loading = true;
734    procedurePool.submitWithName(
735      'logic0',
736      this.procedureAction,
737      { args, callType: this.queryFuncName },
738      undefined,
739      (callTreeResults: any): void => {
740        handler(callTreeResults);
741        this.loadingList.splice(0, 1);
742        if (this.loadingList.length === 0) {
743          this.callTreeProgressEL!.loading = false;
744          this.loadingPage.style.visibility = 'hidden';
745        }
746      }
747    );
748  }
749
750  initHtml(): string {
751    return TabPaneCallTreeHtml;
752  }
753}
754