• 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 { FileMerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem';
25import { ParseExpression } from '../SheetUtils';
26import { FilterByAnalysis, NativeMemoryExpression } from '../../../../bean/NativeHook';
27import { SpSystemTrace } from '../../../SpSystemTrace';
28import '../../../../../base-ui/headline/lit-headline';
29import { LitHeadLine } from '../../../../../base-ui/headline/lit-headline';
30import { TabPaneNMCallTreeHtml } from './TabPaneNMCallTree.html';
31import { queryNativeHookStatisticSubType, queryNativeHookSubType } from '../../../../database/sql/NativeHook.sql';
32
33const InvertOpyionIndex: number = 0;
34const HideSystemSoOptionIndex: number = 1;
35const HideThreadOptionIndex: number = 3;
36
37@element('tabpane-nm-calltree')
38export class TabpaneNMCalltree extends BaseElement {
39  private nmCallTreeTbl: LitTable | null | undefined;
40  private filesystemTbr: LitTable | null | undefined;
41  private nmCallTreeProgressEL: LitProgressBar | null | undefined;
42  private nmCallTreeFilter: TabPaneFilter | null | undefined;
43  private nmCallTreeSource: unknown[] = [];
44  private nativeType: Array<string> = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
45  private sortKey: string = 'heapSizeStr';
46  private sortType: number = 0;
47  private currentSelectedData: unknown = undefined;
48  private nmCallTreeFrameChart: FrameChart | null | undefined;
49  private isChartShow: boolean = false;
50  private systmeRuleName: string = '/system/';
51  private numRuleName: string = '/max/min/';
52  private needShowMenu: boolean = true;
53  private searchValue: string = '';
54  private loadingList: number[] = [];
55  private nmCallTreeLoadingPage: unknown;
56  private currentSelection: SelectionParam | undefined;
57  private filterAllocationType: string = '0';
58  private filterNativeType: string = '0';
59  private filterResponseType: number = -1;
60  private filterResponseSelect: string = '0';
61  private responseTypes: unknown[] = [];
62  private subTypeArr: number[] = [];
63  private lastIsExpression = false;
64  private currentNMCallTreeFilter: TabPaneFilter | undefined | null;
65  private expressionStruct: NativeMemoryExpression | null = null;
66  private isHideThread: boolean = false;
67  private currentSelectIPid = 1;
68  private headLine: LitHeadLine | null | undefined;
69  private _filterData: FilterByAnalysis | undefined;
70  private _analysisTabWidth: number = 0;
71  private _initFromAnalysis = false;
72
73  set analysisTabWidth(width: number) {
74    this._analysisTabWidth = width;
75  }
76
77  set titleTxt(value: string) {
78    this.headLine!.titleTxt = value;
79  }
80
81  set filterData(data: FilterByAnalysis) {
82    // click from analysis
83    this._filterData = data;
84  }
85
86  set titleBoxShow(value: Boolean) {
87    this.headLine!.isShow = value;
88  }
89
90  set initFromAnalysis(flag: boolean) {
91    this._initFromAnalysis = flag;
92  }
93
94  set data(nmCallTreeParam: SelectionParam) {
95    if (nmCallTreeParam === this.currentSelection) {
96      return;
97    }
98    this.nmCallTreeSource = [];
99    this.currentSelection = nmCallTreeParam;
100    this.currentSelectIPid = nmCallTreeParam.nativeMemoryCurrentIPid;
101    this.init(nmCallTreeParam);
102  }
103
104  private async init(nmCallTreeParam: SelectionParam): Promise<void> {
105    this.initUI();
106    await this.initFilterTypes();
107    let types: Array<string | number> = [];
108    this.initTypes(nmCallTreeParam, types);
109    const initWidth = this._analysisTabWidth > 0 ? this._analysisTabWidth : this.clientWidth;
110    this.getDataByWorkerQuery(
111      {
112        leftNs: nmCallTreeParam.leftNs,
113        rightNs: nmCallTreeParam.rightNs,
114        types,
115      },
116      (results: unknown[]): void => {
117        this.setLTableData(results);
118        this.filesystemTbr!.recycleDataSource = [];
119
120        this.nmCallTreeFrameChart?.updateCanvas(true, initWidth);
121        if (this._initFromAnalysis) {
122          this.filterByAnalysis();
123        } else {
124          // @ts-ignore
125          this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
126          this.switchFlameChart();
127          this.nmCallTreeFilter!.icon = 'block';
128        }
129      }
130    );
131  }
132
133  initUI(): void {
134    this.headLine!.clear();
135    this.isHideThread = false;
136    this.searchValue = '';
137    this.nmCallTreeTbl!.style.visibility = 'visible';
138    if (this.parentElement!.clientHeight > this.nmCallTreeFilter!.clientHeight) {
139      this.nmCallTreeFilter!.style.display = 'flex';
140    } else {
141      this.nmCallTreeFilter!.style.display = 'none';
142    }
143    procedurePool.submitWithName('logic0', 'native-memory-reset', [], undefined, () => {});
144    this.nmCallTreeFilter!.disabledTransfer(true);
145    this.nmCallTreeFilter!.initializeFilterTree(true, true, this.currentSelection!.nativeMemory.length > 0);
146    this.nmCallTreeFilter!.filterValue = '';
147
148    this.nmCallTreeProgressEL!.loading = true; // @ts-ignore
149    this.nmCallTreeLoadingPage.style.visibility = 'visible';
150  }
151
152  initTypes(nmCallTreeParam: SelectionParam, types: Array<string | number>): void {
153    if (nmCallTreeParam.nativeMemory.length > 0) {
154      this.nmCallTreeFilter!.isStatisticsMemory = false;
155      if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[0]) !== -1) {
156        types.push("'AllocEvent'");
157        types.push("'MmapEvent'");
158      } else {
159        if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[1]) !== -1) {
160          types.push("'AllocEvent'");
161        }
162        if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[2]) !== -1) {
163          types.push("'MmapEvent'");
164        }
165      }
166    } else {
167      this.nmCallTreeFilter!.isStatisticsMemory = true;
168      if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[0]) !== -1) {
169        types.push(0);
170        types.push(1);
171      } else {
172        if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[1]) !== -1) {
173          types.push(0);
174        }
175        if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[2]) !== -1) {
176          types.push(1);
177        }
178      }
179    }
180  }
181
182  setFilterType(selections: Array<unknown>, data: FilterByAnalysis): void {
183    if (data.type === 'AllocEvent') {
184      data.type = '1';
185    }
186    if (this.subTypeArr.length > 0) {
187      this.subTypeArr.map((memory): void => {
188        selections.push({
189          memoryTap: memory,
190        });
191        if (this.currentSelection?.nativeMemory && this.currentSelection.nativeMemory.length > 0) {
192          const typeName = SpSystemTrace.DATA_DICT.get(memory);
193          if ((data.type === 'MmapEvent' && memory === -1) || data.type === typeName) {
194            data.type = `${selections.length + 2}`;
195          }
196        } else {
197          if (
198            (data.type === 'MmapEvent' && memory === 1) ||
199            (data.type === 'FILE_PAGE_MSG' && memory === 2) ||
200            (data.type === 'MEMORY_USING_MSG' && memory === 3)
201          ) {
202            data.type = `${selections.length + 2}`;
203          }
204        }
205      });
206    }
207  }
208
209  filterByAnalysis(): void {
210    let filterContent: unknown[] = [];
211    let param = new Map<string, unknown>();
212    let selections: Array<unknown> = [];
213    this.setFilterType(selections, this._filterData!);
214    param.set('filterByTitleArr', this._filterData);
215    param.set('filterAllocType', '0');
216    param.set('statisticsSelection', selections);
217    param.set('leftNs', this.currentSelection?.leftNs);
218    param.set('rightNs', this.currentSelection?.rightNs);
219    filterContent.push(
220      {
221        funcName: 'groupCallchainSample',
222        funcArgs: [param],
223      },
224      {
225        funcName: 'getCallChainsBySampleIds',
226        funcArgs: [true],
227      }
228    );
229    this.getDataByWorker(filterContent, (result: unknown[]) => {
230      this.setLTableData(result); // @ts-ignore
231      this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
232      this.switchFlameChart();
233      this.nmCallTreeFilter!.icon = 'block';
234      this.initFromAnalysis = false;
235    });
236    this.banTypeAndLidSelect();
237  }
238
239  banTypeAndLidSelect(): void {
240    this.currentNMCallTreeFilter!.firstSelect = '0';
241    let secondSelect = this.shadowRoot
242      ?.querySelector('#nm-call-tree-filter')!
243      .shadowRoot!.querySelector('#second-select');
244    let thirdSelect = this.shadowRoot
245      ?.querySelector('#nm-call-tree-filter')!
246      .shadowRoot!.querySelector('#third-select');
247    thirdSelect?.setAttribute('disabled', '');
248    secondSelect?.setAttribute('disabled', '');
249  }
250
251  getParentTree(
252    nmCallTreeSrc: Array<FileMerageBean>,
253    nmCallTreeTarget: FileMerageBean,
254    parents: Array<FileMerageBean>
255  ): boolean {
256    for (let nmCallTreeBean of nmCallTreeSrc) {
257      if (nmCallTreeBean.id === nmCallTreeTarget.id) {
258        parents.push(nmCallTreeBean);
259        return true;
260      } else {
261        if (this.getParentTree(nmCallTreeBean.children as Array<FileMerageBean>, nmCallTreeTarget, parents)) {
262          parents.push(nmCallTreeBean);
263          return true;
264        }
265      }
266    }
267    return false;
268  }
269
270  getChildTree(nmCallTreeSrc: Array<FileMerageBean>, id: string, children: Array<FileMerageBean>): boolean {
271    for (let nmCallTreeBean of nmCallTreeSrc) {
272      if (nmCallTreeBean.id === id && nmCallTreeBean.children.length === 0) {
273        children.push(nmCallTreeBean);
274        return true;
275      } else {
276        if (this.getChildTree(nmCallTreeBean.children as Array<FileMerageBean>, id, children)) {
277          children.push(nmCallTreeBean);
278          return true;
279        }
280      }
281    }
282    return false;
283  }
284
285  setRightTableData(fileMerageBean: FileMerageBean): void {
286    let parents: Array<FileMerageBean> = [];
287    let children: Array<FileMerageBean> = []; // @ts-ignore
288    this.getParentTree(this.nmCallTreeSource, fileMerageBean, parents);
289    let maxId = fileMerageBean.id;
290    let maxDur = 0;
291
292    function findMaxStack(merageBean: unknown): void {
293      // @ts-ignore
294      if (merageBean.children.length === 0) {
295        // @ts-ignore
296        if (merageBean.heapSize > maxDur) {
297          // @ts-ignore
298          maxDur = merageBean.heapSize; // @ts-ignore
299          maxId = merageBean.id;
300        }
301      } else {
302        // @ts-ignore
303        merageBean.children.map((callChild: unknown): void => {
304          findMaxStack(<FileMerageBean>callChild);
305        });
306      }
307    }
308
309    findMaxStack(fileMerageBean);
310    this.getChildTree(fileMerageBean.children as Array<FileMerageBean>, maxId, children);
311    let resultValue = parents.reverse().concat(children.reverse());
312    for (let data of resultValue) {
313      data.type = data.lib.endsWith('.so.1') || data.lib.endsWith('.dll') || data.lib.endsWith('.so') ? 0 : 1;
314    }
315    let resultLength = resultValue.length;
316    this.filesystemTbr!.dataSource = resultLength === 0 ? [] : resultValue;
317  }
318
319  //底部的筛选菜单
320  showBottomMenu(isShow: boolean): void {
321    if (isShow) {
322      this.nmCallTreeFilter?.showThird(true);
323      this.nmCallTreeFilter?.setAttribute('first', '');
324      this.nmCallTreeFilter?.setAttribute('second', '');
325      this.nmCallTreeFilter?.setAttribute('tree', '');
326      this.nmCallTreeFilter?.setAttribute('input', '');
327      this.nmCallTreeFilter?.setAttribute('inputLeftText', '');
328    } else {
329      this.nmCallTreeFilter?.showThird(false);
330      this.nmCallTreeFilter?.removeAttribute('first');
331      this.nmCallTreeFilter?.removeAttribute('second');
332      this.nmCallTreeFilter?.removeAttribute('tree');
333      this.nmCallTreeFilter?.removeAttribute('input');
334      this.nmCallTreeFilter?.removeAttribute('inputLeftText');
335    }
336  }
337
338  async initFilterTypes(): Promise<void> {
339    this.currentNMCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter');
340    let secondFilterList = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
341    const addSubType = (subTypeList: unknown): void => {
342      if (!subTypeList) {
343        return;
344      }
345      this.subTypeArr = []; // @ts-ignore
346      for (let data of subTypeList) {
347        secondFilterList.push(data.subType);
348        this.subTypeArr.push(data.subTypeId);
349      }
350    };
351    if (this.currentSelection!.nativeMemory!.length > 0) {
352      let subTypeList = await queryNativeHookSubType(
353        this.currentSelection!.leftNs,
354        this.currentSelection!.rightNs,
355        this.currentSelectIPid
356      );
357      addSubType(subTypeList);
358    } else {
359      let subTypeList = await queryNativeHookStatisticSubType(
360        this.currentSelection!.leftNs,
361        this.currentSelection!.rightNs,
362        this.currentSelectIPid
363      );
364      addSubType(subTypeList);
365    }
366    this.nMCallTreeFilterExtend(secondFilterList);
367  }
368
369  private nMCallTreeFilterExtend(secondFilterList: string[]): void {
370    procedurePool.submitWithName('logic0', 'native-memory-get-responseType', {}, undefined, (res: unknown) => {
371      // @ts-ignore
372      this.responseTypes = res;
373      let nullIndex = this.responseTypes.findIndex((item) => {
374        // @ts-ignore
375        return item.key === 0;
376      });
377      if (nullIndex !== -1) {
378        this.responseTypes.splice(nullIndex, 1);
379      }
380      this.currentNMCallTreeFilter!.setSelectList(
381        null,
382        secondFilterList,
383        'Allocation Lifespan',
384        'Allocation Type',
385        this.responseTypes.map((item: unknown) => {
386          // @ts-ignore
387          return item.value;
388        })
389      );
390      this.currentNMCallTreeFilter!.setFilterModuleSelect('#first-select', 'width', '150px');
391      this.currentNMCallTreeFilter!.setFilterModuleSelect('#second-select', 'width', '150px');
392      this.currentNMCallTreeFilter!.setFilterModuleSelect('#third-select', 'width', '150px');
393      this.currentNMCallTreeFilter!.firstSelect = '0';
394      this.currentNMCallTreeFilter!.secondSelect = '0';
395      this.currentNMCallTreeFilter!.thirdSelect = '0';
396      this.filterAllocationType = '0';
397      this.filterNativeType = '0';
398      this.filterResponseSelect = '0';
399      this.filterResponseType = -1;
400    });
401  }
402
403  initElements(): void {
404    this.headLine = this.shadowRoot?.querySelector<LitHeadLine>('.titleBox');
405    this.nmCallTreeTbl = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-calltree');
406    this.nmCallTreeProgressEL = this.shadowRoot?.querySelector('.nm-call-tree-progress') as LitProgressBar;
407    this.nmCallTreeFrameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart');
408    this.nmCallTreeFrameChart!.mode = ChartMode.Byte;
409    this.nmCallTreeLoadingPage = this.shadowRoot?.querySelector('.nm-call-tree-loading');
410    this.nmCallTreeFrameChart!.addChartClickListener((needShowMenu: boolean): void => {
411      this.parentElement!.scrollTo(0, 0);
412      this.showBottomMenu(needShowMenu);
413      this.needShowMenu = needShowMenu;
414    });
415    this.nmCallTreeTbl!.rememberScrollTop = true;
416    this.nmCallTreeTbl!.exportTextHandleMap.set('heapSizeStr', (value) => {
417      // @ts-ignore
418      return `${value.size}`;
419    });
420    this.nmCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter');
421    this.filesystemTbr = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-list');
422    let spApplication = document.querySelector('body > sp-application');
423    let spSystemTrace = spApplication?.shadowRoot?.querySelector(
424      'div > div.content > sp-system-trace'
425    ) as SpSystemTrace;
426    let filterFunc = (nmCallTreeFuncData: unknown): void => {
427      let nmCallTreeFuncArgs: unknown[] = []; // @ts-ignore
428      if (nmCallTreeFuncData.type === 'check') {
429        nmCallTreeFuncArgs = this.filterFuncByCheckType(nmCallTreeFuncData, nmCallTreeFuncArgs); // @ts-ignore
430      } else if (nmCallTreeFuncData.type === 'select') {
431        nmCallTreeFuncArgs = this.filterFuncBySelectType(nmCallTreeFuncData, nmCallTreeFuncArgs); // @ts-ignore
432      } else if (nmCallTreeFuncData.type === 'button') {
433        nmCallTreeFuncArgs = this.filterFuncByButtonType(nmCallTreeFuncData, nmCallTreeFuncArgs);
434      }
435      this.getDataByWorker(nmCallTreeFuncArgs, (result: unknown[]): void => {
436        this.setLTableData(result); // @ts-ignore
437        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
438        if (this.isChartShow) {
439          this.nmCallTreeFrameChart?.calculateChartData();
440        }
441        this.nmCallTreeTbl!.move1px();
442        if (this.currentSelectedData) {
443          // @ts-ignore
444          this.currentSelectedData.isSelected = false;
445          this.nmCallTreeTbl?.clearAllSelection(this.currentSelectedData);
446          this.filesystemTbr!.recycleDataSource = [];
447          this.currentSelectedData = undefined;
448        }
449      });
450    };
451    this.nmCallTreeFilter!.getDataLibrary(filterFunc.bind(this));
452    this.nmCallTreeFilter!.getDataMining(filterFunc.bind(this));
453    this.nmCallTreeFilter!.getCallTreeData(this.getCallTreeByNMCallTreeFilter.bind(this));
454    this.nmCallTreeFilter!.getCallTreeConstraintsData(this.getCallTreeConByNMCallTreeFilter.bind(this));
455    this.nmCallTreeFilter!.getFilterData(this.getFilterDataByNMCallTreeFilter.bind(this));
456    this.initCloseCallBackByHeadLine();
457    this.nmCallTreeFilter?.addEventListener('focus', () => {
458      spSystemTrace.focusTarget = 'bottomUpInput';
459    });
460    this.nmCallTreeFilter?.addEventListener('blur', () => {
461      spSystemTrace.focusTarget = '';
462    });
463  }
464
465  private getFilterDataByNMCallTreeFilter(nmCallTreeData: FilterData): void {
466    if (
467      (this.isChartShow && nmCallTreeData.icon === 'tree') ||
468      (!this.isChartShow && nmCallTreeData.icon === 'block')
469    ) {
470      this.switchFlameChart(nmCallTreeData);
471    } else {
472      this.initGetFilterByNMCallTreeFilter(nmCallTreeData);
473    }
474  }
475
476  private getCallTreeConByNMCallTreeFilter(nmCallTreeConstraintsData: unknown): void {
477    let nmCallTreeConstraintsArgs: unknown[] = [
478      {
479        funcName: 'resotreAllNode',
480        funcArgs: [[this.numRuleName]],
481      },
482      {
483        funcName: 'clearSplitMapData',
484        funcArgs: [this.numRuleName],
485      },
486    ]; // @ts-ignore
487    if (nmCallTreeConstraintsData.checked) {
488      nmCallTreeConstraintsArgs.push({
489        funcName: 'hideNumMaxAndMin',
490        // @ts-ignore
491        funcArgs: [parseInt(nmCallTreeConstraintsData.min), nmCallTreeConstraintsData.max],
492      });
493    }
494    nmCallTreeConstraintsArgs.push({
495      funcName: 'resetAllNode',
496      funcArgs: [],
497    });
498    this.getDataByWorker(nmCallTreeConstraintsArgs, (result: unknown[]): void => {
499      this.setLTableData(result); // @ts-ignore
500      this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
501      if (this.isChartShow) {
502        this.nmCallTreeFrameChart?.calculateChartData();
503      }
504    });
505  }
506
507  private getCallTreeByNMCallTreeFilter(callTreeData: unknown): void {
508    // @ts-ignore
509    if ([InvertOpyionIndex, HideSystemSoOptionIndex, HideThreadOptionIndex].includes(callTreeData.value)) {
510      this.refreshAllNode({
511        ...this.nmCallTreeFilter!.getFilterTreeData(),
512        // @ts-ignore
513        callTree: callTreeData.checks,
514      });
515    } else {
516      let resultArgs: unknown[] = [];
517      // @ts-ignore
518      if (callTreeData.checks[1]) {
519        resultArgs.push({
520          funcName: 'hideSystemLibrary',
521          funcArgs: [],
522        });
523        resultArgs.push({
524          funcName: 'resetAllNode',
525          funcArgs: [],
526        });
527      } else {
528        resultArgs.push({
529          funcName: 'resotreAllNode',
530          funcArgs: [[this.systmeRuleName]],
531        });
532        resultArgs.push({
533          funcName: 'resetAllNode',
534          funcArgs: [],
535        });
536        resultArgs.push({
537          funcName: 'clearSplitMapData',
538          funcArgs: [this.systmeRuleName],
539        });
540      }
541      this.getDataByWorker(resultArgs, (result: unknown[]): void => {
542        this.setLTableData(result); // @ts-ignore
543        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
544        if (this.isChartShow) {
545          this.nmCallTreeFrameChart?.calculateChartData();
546        }
547      });
548    }
549  }
550
551  private filterFuncByButtonType(nmCallTreeFuncData: unknown, nmCallTreeFuncArgs: unknown[]): unknown[] {
552    // @ts-ignore
553    if (nmCallTreeFuncData.item === 'symbol') {
554      // @ts-ignore
555      if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
556        return nmCallTreeFuncArgs;
557      }
558      if (this.currentSelectedData !== undefined) {
559        // @ts-ignore
560        this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.symbol }, nmCallTreeFuncData.item);
561        nmCallTreeFuncArgs.push({
562          funcName: 'splitTree',
563          // @ts-ignore
564          funcArgs: [this.currentSelectedData.symbol, false, true],
565        });
566      } else {
567        return nmCallTreeFuncArgs;
568      } // @ts-ignore
569    } else if (nmCallTreeFuncData.item === 'library') {
570      // @ts-ignore
571      if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
572        return nmCallTreeFuncArgs;
573      } // @ts-ignore
574      if (this.currentSelectedData !== undefined && this.currentSelectedData.libName !== '') {
575        // @ts-ignore
576        this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.libName }, nmCallTreeFuncData.item);
577        nmCallTreeFuncArgs.push({
578          funcName: 'splitTree',
579          // @ts-ignore
580          funcArgs: [this.currentSelectedData.libName, false, false],
581        });
582      } else {
583        return nmCallTreeFuncArgs;
584      } // @ts-ignore
585    } else if (nmCallTreeFuncData.item === 'restore') {
586      // @ts-ignore
587      if (nmCallTreeFuncData.remove !== undefined && nmCallTreeFuncData.remove.length > 0) {
588        // @ts-ignore
589        let list = nmCallTreeFuncData.remove.map((item: unknown): unknown => {
590          // @ts-ignore
591          return item.name;
592        });
593        nmCallTreeFuncArgs.push({ funcName: 'resotreAllNode', funcArgs: [list] });
594        nmCallTreeFuncArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
595        list.forEach((symbol: string): void => {
596          nmCallTreeFuncArgs.push({ funcName: 'clearSplitMapData', funcArgs: [symbol] });
597        });
598      }
599    }
600    return nmCallTreeFuncArgs;
601  }
602
603  private filterFuncBySelectType(nmCallTreeFuncData: unknown, nmCallTreeFuncArgs: unknown[]): unknown[] {
604    nmCallTreeFuncArgs.push({
605      funcName: 'resotreAllNode',
606      // @ts-ignore
607      funcArgs: [[nmCallTreeFuncData.item.name]],
608    });
609    nmCallTreeFuncArgs.push({
610      funcName: 'clearSplitMapData',
611      // @ts-ignore
612      funcArgs: [nmCallTreeFuncData.item.name],
613    });
614    nmCallTreeFuncArgs.push({
615      funcName: 'splitTree',
616      funcArgs: [
617        // @ts-ignore
618        nmCallTreeFuncData.item.name, // @ts-ignore
619        nmCallTreeFuncData.item.select === '0', // @ts-ignore
620        nmCallTreeFuncData.item.type === 'symbol',
621      ],
622    });
623    return nmCallTreeFuncArgs;
624  }
625
626  private filterFuncByCheckType(nmCallTreeFuncData: unknown, nmCallTreeFuncArgs: unknown[]): unknown[] {
627    // @ts-ignore
628    if (nmCallTreeFuncData.item.checked) {
629      nmCallTreeFuncArgs.push({
630        funcName: 'splitTree',
631        funcArgs: [
632          // @ts-ignore
633          nmCallTreeFuncData.item.name, // @ts-ignore
634          nmCallTreeFuncData.item.select === '0', // @ts-ignore
635          nmCallTreeFuncData.item.type === 'symbol',
636        ],
637      });
638    } else {
639      nmCallTreeFuncArgs.push({
640        funcName: 'resotreAllNode', // @ts-ignore
641        funcArgs: [[nmCallTreeFuncData.item.name]],
642      });
643      nmCallTreeFuncArgs.push({
644        funcName: 'resetAllNode',
645        funcArgs: [],
646      });
647      nmCallTreeFuncArgs.push({
648        funcName: 'clearSplitMapData', // @ts-ignore
649        funcArgs: [nmCallTreeFuncData.item.name],
650      });
651    }
652    return nmCallTreeFuncArgs;
653  }
654
655  private initGetFilterByNMCallTreeFilter(nmCallTreeData: FilterData): void {
656    if (
657      this.filterAllocationType !== nmCallTreeData.firstSelect ||
658      this.filterNativeType !== nmCallTreeData.secondSelect ||
659      this.filterResponseSelect !== nmCallTreeData.thirdSelect
660    ) {
661      this.filterAllocationType = nmCallTreeData.firstSelect || '0';
662      this.filterNativeType = nmCallTreeData.secondSelect || '0';
663      this.filterResponseSelect = nmCallTreeData.thirdSelect || '0';
664      let thirdIndex = parseInt(nmCallTreeData.thirdSelect || '0');
665      if (this.responseTypes.length > thirdIndex) {
666        // @ts-ignore
667        this.filterResponseType = this.responseTypes[thirdIndex].key || -1;
668      }
669      this.searchValue = this.nmCallTreeFilter!.filterValue;
670      this.expressionStruct = new ParseExpression(this.searchValue).parse();
671      this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
672    } else if (this.searchValue !== this.nmCallTreeFilter!.filterValue) {
673      this.searchValue = this.nmCallTreeFilter!.filterValue;
674      this.expressionStruct = new ParseExpression(this.searchValue).parse();
675      let nmArgs = [];
676      if (this.expressionStruct) {
677        this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
678        this.lastIsExpression = true;
679        return;
680      } else {
681        if (this.lastIsExpression) {
682          this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
683          this.lastIsExpression = false;
684          return;
685        }
686        nmArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] });
687        nmArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
688        this.lastIsExpression = false;
689      }
690      this.getDataByWorker(nmArgs, (result: unknown[]): void => {
691        this.nmCallTreeTbl!.isSearch = true;
692        this.nmCallTreeTbl!.setStatus(result, true);
693        this.setLTableData(result); // @ts-ignore
694        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
695        this.switchFlameChart(nmCallTreeData);
696      });
697    } else {
698      this.nmCallTreeTbl!.setStatus(this.nmCallTreeSource, true);
699      this.setLTableData(this.nmCallTreeSource);
700      this.switchFlameChart(nmCallTreeData);
701    }
702  }
703
704  private initCloseCallBackByHeadLine(): void {
705    //点击之后删除掉筛选条件  将所有重置  将目前的title隐藏 高度恢复
706    this.headLine!.closeCallback = (): void => {
707      this.headLine!.clear();
708      this.searchValue = '';
709      this.currentNMCallTreeFilter!.filterValue = '';
710      this._filterData = undefined;
711      this.currentNMCallTreeFilter!.firstSelect = '0';
712      this.currentNMCallTreeFilter!.secondSelect = '0';
713      this.currentNMCallTreeFilter!.thirdSelect = '0';
714      this.filterAllocationType = '0';
715      this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData(), true);
716      this.initFilterTypes();
717      this.nmCallTreeFrameChart?.resizeChange();
718    };
719  }
720
721  connectedCallback(): void {
722    super.connectedCallback();
723    this.nmCallTreeTbl!.addEventListener('row-click', this.nmCallTreeTblRowClickHandler);
724    this.filesystemTbr!.addEventListener('row-click', this.filesystemTbrRowClickHandler);
725    this.nmCallTreeTbl!.addEventListener('column-click', this.nmCallTreeTblColumnClickHandler);
726    let filterHeight = 0;
727    new ResizeObserver((entries: ResizeObserverEntry[]): void => {
728      let nmCallTreeTabFilter = this.shadowRoot!.querySelector('#nm-call-tree-filter') as HTMLElement;
729      if (nmCallTreeTabFilter.clientHeight > 0) {
730        filterHeight = nmCallTreeTabFilter.clientHeight;
731      }
732      if (this.parentElement!.clientHeight > filterHeight) {
733        nmCallTreeTabFilter.style.display = 'flex';
734      } else {
735        nmCallTreeTabFilter.style.display = 'none';
736      }
737      if (this.nmCallTreeTbl!.style.visibility === 'hidden') {
738        nmCallTreeTabFilter.style.display = 'none';
739      }
740      if (this.parentElement?.clientHeight !== 0) {
741        if (this.isChartShow) {
742          this.nmCallTreeFrameChart?.updateCanvas(false, entries[0].contentRect.width);
743          this.nmCallTreeFrameChart?.calculateChartData();
744        }
745        let headLineHeight = 0;
746        if (this.headLine?.isShow) {
747          headLineHeight = this.headLine!.clientHeight;
748        }
749        if (this.nmCallTreeTbl) {
750          // @ts-ignore
751          this.nmCallTreeTbl.shadowRoot.querySelector('.table').style.height = `${
752            this.parentElement!.clientHeight - 10 - 35 - headLineHeight
753          }px`;
754        }
755        this.nmCallTreeTbl?.reMeauseHeight();
756        if (this.filesystemTbr) {
757          // @ts-ignore
758          this.filesystemTbr.shadowRoot.querySelector('.table').style.height = `${
759            this.parentElement!.clientHeight - 45 - 21 - headLineHeight
760          }px`;
761        }
762        this.filesystemTbr?.reMeauseHeight(); // @ts-ignore
763        this.nmCallTreeLoadingPage.style.height = `${this.parentElement!.clientHeight - 24}px`;
764      }
765    }).observe(this.parentElement!);
766    this.parentElement!.onscroll = (): void => {
767      this.nmCallTreeFrameChart!.tabPaneScrollTop = this.parentElement!.scrollTop;
768    };
769  }
770
771  disconnectedCallback(): void {
772    super.disconnectedCallback();
773    this.nmCallTreeTbl!.removeEventListener('row-click', this.nmCallTreeTblRowClickHandler);
774    this.filesystemTbr!.removeEventListener('row-click', this.filesystemTbrRowClickHandler);
775    this.nmCallTreeTbl!.removeEventListener('column-click', this.nmCallTreeTblColumnClickHandler);
776  }
777
778  filesystemTbrRowClickHandler = (event: unknown): void => {
779    // @ts-ignore
780    let data = event.detail.data as FileMerageBean;
781    this.nmCallTreeTbl?.clearAllSelection(data); // @ts-ignore
782    (data as unknown).isSelected = true;
783    this.nmCallTreeTbl!.scrollToData(data); // @ts-ignore
784    if ((event.detail as unknown).callBack) {
785      // @ts-ignore
786      (event.detail as unknown).callBack(true);
787    }
788  };
789
790  nmCallTreeTblColumnClickHandler = (event: unknown): void => {
791    // @ts-ignore
792    this.sortKey = event.detail.key; // @ts-ignore
793    this.sortType = event.detail.sort;
794    this.setLTableData(this.nmCallTreeSource, true); // @ts-ignore
795    this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
796  };
797
798  nmCallTreeTblRowClickHandler = (event: unknown): void => {
799    // @ts-ignore
800    let nmCallTreeData = event.detail.data as FileMerageBean;
801    this.setRightTableData(nmCallTreeData);
802    nmCallTreeData.isSelected = true;
803    this.currentSelectedData = nmCallTreeData;
804    this.filesystemTbr?.clearAllSelection(nmCallTreeData);
805    this.filesystemTbr?.setCurrentSelection(nmCallTreeData);
806    // @ts-ignore
807    if ((event.detail as unknown).callBack) {
808      // @ts-ignore
809      (event.detail as unknown).callBack(true);
810    }
811    document.dispatchEvent(
812      new CustomEvent('number_calibration', {
813        // @ts-ignore
814        detail: { time: event.detail.tsArray, counts: event.detail.countArray },
815      })
816    );
817  };
818
819  private switchFlameChart(flameChartData?: unknown): void {
820    let nmCallTreePageTab = this.shadowRoot?.querySelector('#show_table');
821    let nmCallTreePageChart = this.shadowRoot?.querySelector('#show_chart'); // @ts-ignore
822    if (!flameChartData || flameChartData.icon === 'block') {
823      nmCallTreePageChart?.setAttribute('class', 'show');
824      nmCallTreePageTab?.setAttribute('class', '');
825      this.isChartShow = true;
826      this.nmCallTreeFilter!.disabledMining = true;
827      this.showBottomMenu(this.needShowMenu);
828      this.nmCallTreeFrameChart?.calculateChartData(); // @ts-ignore
829    } else if (flameChartData.icon === 'tree') {
830      nmCallTreePageChart?.setAttribute('class', '');
831      nmCallTreePageTab?.setAttribute('class', 'show');
832      this.showBottomMenu(true);
833      this.isChartShow = false;
834      this.nmCallTreeFilter!.disabledMining = false;
835      this.nmCallTreeFrameChart!.clearCanvas();
836      this.nmCallTreeTbl!.reMeauseHeight();
837    }
838  }
839
840  private refreshAllNode(filterData: unknown, isAnalysisReset?: boolean): void {
841    let nmCallTreeArgs: unknown[] = []; // @ts-ignore
842    let isTopDown: boolean = !filterData.callTree[0]; // @ts-ignore
843    let isHideSystemLibrary = filterData.callTree[1]; // @ts-ignore
844    this.isHideThread = filterData.callTree[3]; // @ts-ignore
845    let list = filterData.dataMining.concat(filterData.dataLibrary);
846    let groupArgs = this.setGroupArgsByRefreshAllNode();
847    if ((this.lastIsExpression && !this.expressionStruct) || isAnalysisReset) {
848      nmCallTreeArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] });
849    }
850    nmCallTreeArgs.push({ funcName: 'hideThread', funcArgs: [this.isHideThread] });
851    nmCallTreeArgs.push(
852      {
853        funcName: 'groupCallchainSample',
854        funcArgs: [groupArgs],
855      },
856      {
857        funcName: 'getCallChainsBySampleIds',
858        funcArgs: [isTopDown],
859      }
860    );
861    this.filesystemTbr!.recycleDataSource = [];
862    if (isHideSystemLibrary) {
863      nmCallTreeArgs.push({
864        funcName: 'hideSystemLibrary',
865        funcArgs: [],
866      });
867    } // @ts-ignore
868    if (filterData.callTreeConstraints.checked) {
869      nmCallTreeArgs.push({
870        funcName: 'hideNumMaxAndMin', // @ts-ignore
871        funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]],
872      });
873    }
874    nmCallTreeArgs.push({ funcName: 'splitAllProcess', funcArgs: [list] });
875    nmCallTreeArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
876    this.getDataByWorker(nmCallTreeArgs, (result: unknown[]) => {
877      this.setLTableData(result); // @ts-ignore
878      this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
879      if (this.isChartShow) {
880        this.nmCallTreeFrameChart?.calculateChartData();
881      }
882    });
883  }
884
885  private setGroupArgsByRefreshAllNode(): Map<string, unknown> {
886    let groupArgs = new Map<string, unknown>();
887    groupArgs.set('filterAllocType', this.filterAllocationType);
888    groupArgs.set('filterEventType', this.filterNativeType);
889    if (this.expressionStruct) {
890      groupArgs.set('filterExpression', this.expressionStruct);
891      groupArgs.set('filterResponseType', -1);
892      this.currentNMCallTreeFilter!.thirdSelect = '0';
893    } else {
894      groupArgs.set('filterResponseType', this.filterResponseType);
895    }
896    groupArgs.set('leftNs', this.currentSelection?.leftNs || 0);
897    groupArgs.set('rightNs', this.currentSelection?.rightNs || 0);
898    let selections: Array<unknown> = [];
899    if (this.subTypeArr.length > 0) {
900      this.subTypeArr.map((memory): void => {
901        selections.push({
902          memoryTap: memory,
903        });
904      });
905    }
906    groupArgs.set('statisticsSelection', selections);
907    if (this._filterData) {
908      groupArgs.set('filterByTitleArr', this._filterData);
909    }
910    groupArgs.set(
911      'nativeHookType',
912      this.currentSelection!.nativeMemory.length > 0 ? 'native-hook' : 'native-hook-statistic'
913    );
914    return groupArgs;
915  }
916
917  setLTableData(resultData: unknown[], sort?: boolean): void {
918    if (sort) {
919      this.nmCallTreeSource = this.sortTree(resultData);
920    } else {
921      if (resultData && resultData[0]) {
922        this.nmCallTreeSource =
923          this.currentSelection!.nativeMemory.length > 0 && !this.isHideThread
924            ? this.sortTree(resultData) // @ts-ignore
925            : this.sortTree(resultData[0].children || []);
926      } else {
927        this.nmCallTreeSource = [];
928      }
929    }
930    this.nmCallTreeTbl!.recycleDataSource = this.nmCallTreeSource;
931  }
932
933  sortTree(arr: Array<unknown>): Array<unknown> {
934    let nmCallTreeSortArr = arr.sort((callTreeLeftData, callTreeRightData): number => {
935      if (this.sortKey === 'heapSizeStr' || this.sortKey === 'heapPercent') {
936        if (this.sortType === 0) {
937          // @ts-ignore
938          return callTreeRightData.size - callTreeLeftData.size;
939        } else if (this.sortType === 1) {
940          // @ts-ignore
941          return callTreeLeftData.size - callTreeRightData.size;
942        } else {
943          // @ts-ignore
944          return callTreeRightData.size - callTreeLeftData.size;
945        }
946      } else {
947        if (this.sortType === 0) {
948          // @ts-ignore
949          return callTreeRightData.count - callTreeLeftData.count;
950        } else if (this.sortType === 1) {
951          // @ts-ignore
952          return callTreeLeftData.count - callTreeRightData.count;
953        } else {
954          // @ts-ignore
955          return callTreeRightData.count - callTreeLeftData.count;
956        }
957      }
958    });
959    nmCallTreeSortArr.map((call): void => {
960      // @ts-ignore
961      call.children = this.sortTree(call.children);
962    });
963    return nmCallTreeSortArr;
964  }
965
966  getDataByWorker(args: unknown[], handler: Function): void {
967    this.loadingList.push(1);
968    this.nmCallTreeProgressEL!.loading = true; // @ts-ignore
969    this.nmCallTreeLoadingPage.style.visibility = 'visible';
970    procedurePool.submitWithName(
971      'logic0',
972      'native-memory-calltree-action',
973      args,
974      undefined,
975      (callTreeActionResults: unknown): void => {
976        handler(callTreeActionResults);
977        this.loadingList.splice(0, 1);
978        if (this.loadingList.length === 0) {
979          this.nmCallTreeProgressEL!.loading = false; // @ts-ignore
980          this.nmCallTreeLoadingPage.style.visibility = 'hidden';
981        }
982      }
983    );
984  }
985
986  getDataByWorkerQuery(args: unknown, handler: Function): void {
987    this.loadingList.push(1);
988    this.nmCallTreeProgressEL!.loading = true; // @ts-ignore
989    this.nmCallTreeLoadingPage.style.visibility = 'visible';
990    procedurePool.submitWithName(
991      'logic0',
992      this.currentSelection!.nativeMemory!.length > 0
993        ? 'native-memory-queryCallchainsSamples'
994        : 'native-memory-queryStatisticCallchainsSamples',
995      args,
996      undefined,
997      (callChainsResults: unknown): void => {
998        handler(callChainsResults);
999        this.loadingList.splice(0, 1);
1000        if (this.loadingList.length === 0) {
1001          this.nmCallTreeProgressEL!.loading = false; // @ts-ignore
1002          this.nmCallTreeLoadingPage.style.visibility = 'hidden';
1003        }
1004      }
1005    );
1006  }
1007
1008  initHtml(): string {
1009    return TabPaneNMCallTreeHtml;
1010  }
1011}
1012