• 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: any[] = [];
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: any = 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: any;
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: any[] = [];
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: any[]): 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          this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
125          this.switchFlameChart();
126          this.nmCallTreeFilter!.icon = 'block';
127        }
128      }
129    );
130  }
131
132  initUI(): void {
133    this.headLine!.clear();
134    this.isHideThread = false;
135    this.searchValue = '';
136    this.nmCallTreeTbl!.style.visibility = 'visible';
137    if (this.parentElement!.clientHeight > this.nmCallTreeFilter!.clientHeight) {
138      this.nmCallTreeFilter!.style.display = 'flex';
139    } else {
140      this.nmCallTreeFilter!.style.display = 'none';
141    }
142    procedurePool.submitWithName('logic0', 'native-memory-reset', [], undefined, () => {});
143    this.nmCallTreeFilter!.disabledTransfer(true);
144    this.nmCallTreeFilter!.initializeFilterTree(true, true, this.currentSelection!.nativeMemory.length > 0);
145    this.nmCallTreeFilter!.filterValue = '';
146
147    this.nmCallTreeProgressEL!.loading = true;
148    this.nmCallTreeLoadingPage.style.visibility = 'visible';
149  }
150
151  initTypes(nmCallTreeParam: SelectionParam, types: Array<string | number>): void {
152    if (nmCallTreeParam.nativeMemory.length > 0) {
153      this.nmCallTreeFilter!.isStatisticsMemory = false;
154      if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[0]) !== -1) {
155        types.push("'AllocEvent'");
156        types.push("'MmapEvent'");
157      } else {
158        if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[1]) !== -1) {
159          types.push("'AllocEvent'");
160        }
161        if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[2]) !== -1) {
162          types.push("'MmapEvent'");
163        }
164      }
165    } else {
166      this.nmCallTreeFilter!.isStatisticsMemory = true;
167      if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[0]) !== -1) {
168        types.push(0);
169        types.push(1);
170      } else {
171        if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[1]) !== -1) {
172          types.push(0);
173        }
174        if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[2]) !== -1) {
175          types.push(1);
176        }
177      }
178    }
179  }
180
181  setFilterType(selections: Array<any>, data: FilterByAnalysis): void {
182    if (data.type === 'AllocEvent') {
183      data.type = '1';
184    }
185    const that = this;
186    if (this.subTypeArr.length > 0) {
187      this.subTypeArr.map((memory): void => {
188        selections.push({
189          memoryTap: memory,
190        });
191        if (that.currentSelection?.nativeMemory && that.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: any[] = [];
211    let param = new Map<string, any>();
212    let selections: Array<any> = [];
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: any[]) => {
230      this.setLTableData(result);
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> = [];
288    this.getParentTree(this.nmCallTreeSource, fileMerageBean, parents);
289    let maxId = fileMerageBean.id;
290    let maxDur = 0;
291
292    function findMaxStack(merageBean: any): void {
293      if (merageBean.children.length === 0) {
294        if (merageBean.heapSize > maxDur) {
295          maxDur = merageBean.heapSize;
296          maxId = merageBean.id;
297        }
298      } else {
299        merageBean.children.map((callChild: any): void => {
300          findMaxStack(<FileMerageBean>callChild);
301        });
302      }
303    }
304
305    findMaxStack(fileMerageBean);
306    this.getChildTree(fileMerageBean.children as Array<FileMerageBean>, maxId, children);
307    let resultValue = parents.reverse().concat(children.reverse());
308    for (let data of resultValue) {
309      data.type =
310        data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1;
311    }
312    let resultLength = resultValue.length;
313    this.filesystemTbr!.dataSource = resultLength == 0 ? [] : resultValue;
314  }
315
316  //底部的筛选菜单
317  showBottomMenu(isShow: boolean): void {
318    if (isShow) {
319      this.nmCallTreeFilter?.showThird(true);
320      this.nmCallTreeFilter?.setAttribute('first', '');
321      this.nmCallTreeFilter?.setAttribute('second', '');
322      this.nmCallTreeFilter?.setAttribute('tree', '');
323      this.nmCallTreeFilter?.setAttribute('input', '');
324      this.nmCallTreeFilter?.setAttribute('inputLeftText', '');
325    } else {
326      this.nmCallTreeFilter?.showThird(false);
327      this.nmCallTreeFilter?.removeAttribute('first');
328      this.nmCallTreeFilter?.removeAttribute('second');
329      this.nmCallTreeFilter?.removeAttribute('tree');
330      this.nmCallTreeFilter?.removeAttribute('input');
331      this.nmCallTreeFilter?.removeAttribute('inputLeftText');
332    }
333  }
334
335  async initFilterTypes(): Promise<void> {
336    this.currentNMCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter');
337    let secondFilterList = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
338    let that = this;
339    function addSubType(subTypeList: any) {
340      if (!subTypeList) {
341        return;
342      }
343      that.subTypeArr = [];
344      for (let data of subTypeList) {
345        secondFilterList.push(data.subType);
346        that.subTypeArr.push(data.subTypeId);
347      }
348    }
349    if (this.currentSelection!.nativeMemory!.length > 0) {
350      let subTypeList = await queryNativeHookSubType(
351        this.currentSelection!.leftNs,
352        this.currentSelection!.rightNs,
353        this.currentSelectIPid
354      );
355      addSubType(subTypeList);
356    } else {
357      let subTypeList = await queryNativeHookStatisticSubType(
358        this.currentSelection!.leftNs,
359        this.currentSelection!.rightNs,
360        this.currentSelectIPid
361      );
362      addSubType(subTypeList);
363    }
364    this.nMCallTreeFilterExtend(secondFilterList);
365  }
366
367  private nMCallTreeFilterExtend(secondFilterList: string[]): void {
368    procedurePool.submitWithName('logic0', 'native-memory-get-responseType', {}, undefined, (res: any) => {
369      this.responseTypes = res;
370      let nullIndex = this.responseTypes.findIndex((item) => {
371        return item.key == 0;
372      });
373      if (nullIndex != -1) {
374        this.responseTypes.splice(nullIndex, 1);
375      }
376      this.currentNMCallTreeFilter!.setSelectList(
377        null,
378        secondFilterList,
379        'Allocation Lifespan',
380        'Allocation Type',
381        this.responseTypes.map((item: any) => {
382          return item.value;
383        })
384      );
385      this.currentNMCallTreeFilter!.setFilterModuleSelect('#first-select', 'width', '150px');
386      this.currentNMCallTreeFilter!.setFilterModuleSelect('#second-select', 'width', '150px');
387      this.currentNMCallTreeFilter!.setFilterModuleSelect('#third-select', 'width', '150px');
388      this.currentNMCallTreeFilter!.firstSelect = '0';
389      this.currentNMCallTreeFilter!.secondSelect = '0';
390      this.currentNMCallTreeFilter!.thirdSelect = '0';
391      this.filterAllocationType = '0';
392      this.filterNativeType = '0';
393      this.filterResponseSelect = '0';
394      this.filterResponseType = -1;
395    });
396  }
397
398  initElements(): void {
399    this.headLine = this.shadowRoot?.querySelector<LitHeadLine>('.titleBox');
400    this.nmCallTreeTbl = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-calltree');
401    this.nmCallTreeProgressEL = this.shadowRoot?.querySelector('.nm-call-tree-progress') as LitProgressBar;
402    this.nmCallTreeFrameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart');
403    this.nmCallTreeFrameChart!.mode = ChartMode.Byte;
404    this.nmCallTreeLoadingPage = this.shadowRoot?.querySelector('.nm-call-tree-loading');
405    this.nmCallTreeFrameChart!.addChartClickListener((needShowMenu: boolean): void => {
406      this.parentElement!.scrollTo(0, 0);
407      this.showBottomMenu(needShowMenu);
408      this.needShowMenu = needShowMenu;
409    });
410    this.nmCallTreeTbl!.rememberScrollTop = true;
411    this.nmCallTreeTbl!.exportTextHandleMap.set('heapSizeStr', (value) => {
412      return `${value['size']}`;
413    });
414    this.nmCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter');
415    this.filesystemTbr = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-list');
416    let filterFunc = (nmCallTreeFuncData: any): void => {
417      let nmCallTreeFuncArgs: any[] = [];
418      if (nmCallTreeFuncData.type === 'check') {
419        nmCallTreeFuncArgs = this.filterFuncByCheckType(nmCallTreeFuncData, nmCallTreeFuncArgs);
420      } else if (nmCallTreeFuncData.type == 'select') {
421        nmCallTreeFuncArgs = this.filterFuncBySelectType(nmCallTreeFuncData, nmCallTreeFuncArgs);
422      } else if (nmCallTreeFuncData.type === 'button') {
423        nmCallTreeFuncArgs = this.filterFuncByButtonType(nmCallTreeFuncData, nmCallTreeFuncArgs);
424      }
425      this.getDataByWorker(nmCallTreeFuncArgs, (result: any[]): void => {
426        this.setLTableData(result);
427        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
428        if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData();
429        this.nmCallTreeTbl!.move1px();
430        if (this.currentSelectedData) {
431          this.currentSelectedData.isSelected = false;
432          this.nmCallTreeTbl?.clearAllSelection(this.currentSelectedData);
433          this.filesystemTbr!.recycleDataSource = [];
434          this.currentSelectedData = undefined;
435        }
436      });
437    };
438    this.nmCallTreeFilter!.getDataLibrary(filterFunc.bind(this));
439    this.nmCallTreeFilter!.getDataMining(filterFunc.bind(this));
440    this.nmCallTreeFilter!.getCallTreeData(this.getCallTreeByNMCallTreeFilter.bind(this));
441    this.nmCallTreeFilter!.getCallTreeConstraintsData(this.getCallTreeConByNMCallTreeFilter.bind(this));
442    this.nmCallTreeFilter!.getFilterData(this.getFilterDataByNMCallTreeFilter.bind(this));
443    this.initCloseCallBackByHeadLine();
444  }
445
446  private getFilterDataByNMCallTreeFilter(nmCallTreeData: FilterData): void {
447    if (
448      (this.isChartShow && nmCallTreeData.icon === 'tree') ||
449      (!this.isChartShow && nmCallTreeData.icon === 'block')
450    ) {
451      this.switchFlameChart(nmCallTreeData);
452    } else {
453      this.initGetFilterByNMCallTreeFilter(nmCallTreeData);
454    }
455  }
456
457  private getCallTreeConByNMCallTreeFilter(nmCallTreeConstraintsData: any): void {
458    let nmCallTreeConstraintsArgs: any[] = [
459      {
460        funcName: 'resotreAllNode',
461        funcArgs: [[this.numRuleName]],
462      },
463      {
464        funcName: 'clearSplitMapData',
465        funcArgs: [this.numRuleName],
466      },
467    ];
468    if (nmCallTreeConstraintsData.checked) {
469      nmCallTreeConstraintsArgs.push({
470        funcName: 'hideNumMaxAndMin',
471        funcArgs: [parseInt(nmCallTreeConstraintsData.min), nmCallTreeConstraintsData.max],
472      });
473    }
474    nmCallTreeConstraintsArgs.push({
475      funcName: 'resetAllNode',
476      funcArgs: [],
477    });
478    this.getDataByWorker(nmCallTreeConstraintsArgs, (result: any[]): void => {
479      this.setLTableData(result);
480      this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
481      if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData();
482    });
483  }
484
485  private getCallTreeByNMCallTreeFilter(callTreeData: any): void {
486    if ([InvertOpyionIndex, HideSystemSoOptionIndex, HideThreadOptionIndex].includes(callTreeData.value)) {
487      this.refreshAllNode({
488        ...this.nmCallTreeFilter!.getFilterTreeData(),
489        callTree: callTreeData.checks,
490      });
491    } else {
492      let resultArgs: any[] = [];
493      if (callTreeData.checks[1]) {
494        resultArgs.push({
495          funcName: 'hideSystemLibrary',
496          funcArgs: [],
497        });
498        resultArgs.push({
499          funcName: 'resetAllNode',
500          funcArgs: [],
501        });
502      } else {
503        resultArgs.push({
504          funcName: 'resotreAllNode',
505          funcArgs: [[this.systmeRuleName]],
506        });
507        resultArgs.push({
508          funcName: 'resetAllNode',
509          funcArgs: [],
510        });
511        resultArgs.push({
512          funcName: 'clearSplitMapData',
513          funcArgs: [this.systmeRuleName],
514        });
515      }
516      this.getDataByWorker(resultArgs, (result: any[]): void => {
517        this.setLTableData(result);
518        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
519        if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData();
520      });
521    }
522  }
523
524  private filterFuncByButtonType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] {
525    if (nmCallTreeFuncData.item == 'symbol') {
526      if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
527        return nmCallTreeFuncArgs;
528      }
529      if (this.currentSelectedData !== undefined) {
530        this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.symbolName }, nmCallTreeFuncData.item);
531        nmCallTreeFuncArgs.push({
532          funcName: 'splitTree',
533          funcArgs: [this.currentSelectedData.symbolName, false, true],
534        });
535      } else {
536        return nmCallTreeFuncArgs;
537      }
538    } else if (nmCallTreeFuncData.item === 'library') {
539      if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
540        return nmCallTreeFuncArgs;
541      }
542      if (this.currentSelectedData != undefined && this.currentSelectedData.libName !== '') {
543        this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.libName }, nmCallTreeFuncData.item);
544        nmCallTreeFuncArgs.push({
545          funcName: 'splitTree',
546          funcArgs: [this.currentSelectedData.libName, false, false],
547        });
548      } else {
549        return nmCallTreeFuncArgs;
550      }
551    } else if (nmCallTreeFuncData.item === 'restore') {
552      if (nmCallTreeFuncData.remove != undefined && nmCallTreeFuncData.remove.length > 0) {
553        let list = nmCallTreeFuncData.remove.map((item: any): any => {
554          return item.name;
555        });
556        nmCallTreeFuncArgs.push({ funcName: 'resotreAllNode', funcArgs: [list] });
557        nmCallTreeFuncArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
558        list.forEach((symbolName: string): void => {
559          nmCallTreeFuncArgs.push({ funcName: 'clearSplitMapData', funcArgs: [symbolName] });
560        });
561      }
562    }
563    return nmCallTreeFuncArgs;
564  }
565
566  private filterFuncBySelectType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] {
567    nmCallTreeFuncArgs.push({
568      funcName: 'resotreAllNode',
569      funcArgs: [[nmCallTreeFuncData.item.name]],
570    });
571    nmCallTreeFuncArgs.push({
572      funcName: 'clearSplitMapData',
573      funcArgs: [nmCallTreeFuncData.item.name],
574    });
575    nmCallTreeFuncArgs.push({
576      funcName: 'splitTree',
577      funcArgs: [
578        nmCallTreeFuncData.item.name,
579        nmCallTreeFuncData.item.select === '0',
580        nmCallTreeFuncData.item.type == 'symbol',
581      ],
582    });
583    return nmCallTreeFuncArgs;
584  }
585
586  private filterFuncByCheckType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] {
587    if (nmCallTreeFuncData.item.checked) {
588      nmCallTreeFuncArgs.push({
589        funcName: 'splitTree',
590        funcArgs: [
591          nmCallTreeFuncData.item.name,
592          nmCallTreeFuncData.item.select === '0',
593          nmCallTreeFuncData.item.type === 'symbol',
594        ],
595      });
596    } else {
597      nmCallTreeFuncArgs.push({
598        funcName: 'resotreAllNode',
599        funcArgs: [[nmCallTreeFuncData.item.name]],
600      });
601      nmCallTreeFuncArgs.push({
602        funcName: 'resetAllNode',
603        funcArgs: [],
604      });
605      nmCallTreeFuncArgs.push({
606        funcName: 'clearSplitMapData',
607        funcArgs: [nmCallTreeFuncData.item.name],
608      });
609    }
610    return nmCallTreeFuncArgs;
611  }
612
613  private initGetFilterByNMCallTreeFilter(nmCallTreeData: FilterData): void {
614    if (
615      this.filterAllocationType !== nmCallTreeData.firstSelect ||
616      this.filterNativeType !== nmCallTreeData.secondSelect ||
617      this.filterResponseSelect !== nmCallTreeData.thirdSelect
618    ) {
619      this.filterAllocationType = nmCallTreeData.firstSelect || '0';
620      this.filterNativeType = nmCallTreeData.secondSelect || '0';
621      this.filterResponseSelect = nmCallTreeData.thirdSelect || '0';
622      let thirdIndex = parseInt(nmCallTreeData.thirdSelect || '0');
623      if (this.responseTypes.length > thirdIndex) {
624        this.filterResponseType = this.responseTypes[thirdIndex].key || -1;
625      }
626      this.searchValue = this.nmCallTreeFilter!.filterValue;
627      this.expressionStruct = new ParseExpression(this.searchValue).parse();
628      this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
629    } else if (this.searchValue !== this.nmCallTreeFilter!.filterValue) {
630      this.searchValue = this.nmCallTreeFilter!.filterValue;
631      this.expressionStruct = new ParseExpression(this.searchValue).parse();
632      let nmArgs = [];
633      if (this.expressionStruct) {
634        this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
635        this.lastIsExpression = true;
636        return;
637      } else {
638        if (this.lastIsExpression) {
639          this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData());
640          this.lastIsExpression = false;
641          return;
642        }
643        nmArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] });
644        nmArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
645        this.lastIsExpression = false;
646      }
647      this.getDataByWorker(nmArgs, (result: any[]): void => {
648        this.nmCallTreeTbl!.isSearch = true;
649        this.nmCallTreeTbl!.setStatus(result, true);
650        this.setLTableData(result);
651        this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
652        this.switchFlameChart(nmCallTreeData);
653      });
654    } else {
655      this.nmCallTreeTbl!.setStatus(this.nmCallTreeSource, true);
656      this.setLTableData(this.nmCallTreeSource);
657      this.switchFlameChart(nmCallTreeData);
658    }
659  }
660
661  private initCloseCallBackByHeadLine() {
662    //点击之后删除掉筛选条件  将所有重置  将目前的title隐藏 高度恢复
663    this.headLine!.closeCallback = () => {
664      this.headLine!.clear();
665      this.searchValue = '';
666      this.currentNMCallTreeFilter!.filterValue = '';
667      this._filterData = undefined;
668      this.currentNMCallTreeFilter!.firstSelect = '0';
669      this.currentNMCallTreeFilter!.secondSelect = '0';
670      this.currentNMCallTreeFilter!.thirdSelect = '0';
671      this.filterAllocationType = '0';
672      this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData(), true);
673      this.initFilterTypes();
674      this.nmCallTreeFrameChart?.resizeChange();
675    };
676  }
677
678  connectedCallback(): void {
679    super.connectedCallback();
680    this.nmCallTreeTbl!.addEventListener('row-click', this.nmCallTreeTblRowClickHandler);
681    this.filesystemTbr!.addEventListener('row-click', this.filesystemTbrRowClickHandler);
682    this.nmCallTreeTbl!.addEventListener('column-click', this.nmCallTreeTblColumnClickHandler);
683    let filterHeight = 0;
684    new ResizeObserver((entries: ResizeObserverEntry[]): void => {
685      let nmCallTreeTabFilter = this.shadowRoot!.querySelector('#nm-call-tree-filter') as HTMLElement;
686      if (nmCallTreeTabFilter.clientHeight > 0) {
687        filterHeight = nmCallTreeTabFilter.clientHeight;
688      }
689      if (this.parentElement!.clientHeight > filterHeight) {
690        nmCallTreeTabFilter.style.display = 'flex';
691      } else {
692        nmCallTreeTabFilter.style.display = 'none';
693      }
694      if (this.nmCallTreeTbl!.style.visibility === 'hidden') {
695        nmCallTreeTabFilter.style.display = 'none';
696      }
697      if (this.parentElement?.clientHeight !== 0) {
698        if (this.isChartShow) {
699          this.nmCallTreeFrameChart?.updateCanvas(false, entries[0].contentRect.width);
700          this.nmCallTreeFrameChart?.calculateChartData();
701        }
702        if (this.nmCallTreeTbl) {
703          // @ts-ignore
704          this.nmCallTreeTbl.shadowRoot.querySelector('.table').style.height = `${
705            this.parentElement!.clientHeight - 10 - 35
706          }px`;
707        }
708        this.nmCallTreeTbl?.reMeauseHeight();
709        if (this.filesystemTbr) {
710          // @ts-ignore
711          this.filesystemTbr.shadowRoot.querySelector('.table').style.height = `${
712            this.parentElement!.clientHeight - 45 - 21
713          }px`;
714        }
715        this.filesystemTbr?.reMeauseHeight();
716        this.nmCallTreeLoadingPage.style.height = `${this.parentElement!.clientHeight - 24}px`;
717      }
718    }).observe(this.parentElement!);
719    this.parentElement!.onscroll = (): void => {
720      this.nmCallTreeFrameChart!.tabPaneScrollTop = this.parentElement!.scrollTop;
721    };
722  }
723
724  disconnectedCallback() {
725    super.disconnectedCallback();
726    this.nmCallTreeTbl!.removeEventListener('row-click', this.nmCallTreeTblRowClickHandler);
727    this.filesystemTbr!.removeEventListener('row-click', this.filesystemTbrRowClickHandler);
728    this.nmCallTreeTbl!.removeEventListener('column-click', this.nmCallTreeTblColumnClickHandler);
729  }
730
731  filesystemTbrRowClickHandler = (event: any): void => {
732    // @ts-ignore
733    let data = evt.detail.data as FileMerageBean;
734    this.nmCallTreeTbl?.clearAllSelection(data);
735    (data as any).isSelected = true;
736    this.nmCallTreeTbl!.scrollToData(data);
737    // @ts-ignore
738    if ((evt.detail as any).callBack) {
739      // @ts-ignore
740      (evt.detail as any).callBack(true);
741    }
742  };
743
744  nmCallTreeTblColumnClickHandler = (event: any): void => {
745    // @ts-ignore
746    this.sortKey = evt.detail.key;
747    // @ts-ignore
748    this.sortType = evt.detail.sort;
749    // @ts-ignore
750    this.setLTableData(this.nmCallTreeSource, true);
751    this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
752  };
753
754  nmCallTreeTblRowClickHandler = (event: any): void => {
755    // @ts-ignore
756    let nmCallTreeData = event.detail.data as FileMerageBean;
757    this.setRightTableData(nmCallTreeData);
758    nmCallTreeData.isSelected = true;
759    this.currentSelectedData = nmCallTreeData;
760    this.filesystemTbr?.clearAllSelection(nmCallTreeData);
761    this.filesystemTbr?.setCurrentSelection(nmCallTreeData);
762    // @ts-ignore
763    if ((event.detail as any).callBack) {
764      // @ts-ignore
765      (event.detail as any).callBack(true);
766    }
767    document.dispatchEvent(
768      new CustomEvent('number_calibration', {
769        detail: { time: event.detail.tsArray, counts: event.detail.countArray },
770      })
771    );
772  };
773
774  private switchFlameChart(flameChartData?: any): void {
775    let nmCallTreePageTab = this.shadowRoot?.querySelector('#show_table');
776    let nmCallTreePageChart = this.shadowRoot?.querySelector('#show_chart');
777    if (!flameChartData || flameChartData.icon === 'block') {
778      nmCallTreePageChart?.setAttribute('class', 'show');
779      nmCallTreePageTab?.setAttribute('class', '');
780      this.isChartShow = true;
781      this.nmCallTreeFilter!.disabledMining = true;
782      this.showBottomMenu(this.needShowMenu);
783      this.nmCallTreeFrameChart?.calculateChartData();
784    } else if (flameChartData.icon === 'tree') {
785      nmCallTreePageChart?.setAttribute('class', '');
786      nmCallTreePageTab?.setAttribute('class', 'show');
787      this.showBottomMenu(true);
788      this.isChartShow = false;
789      this.nmCallTreeFilter!.disabledMining = false;
790      this.nmCallTreeFrameChart!.clearCanvas();
791      this.nmCallTreeTbl!.reMeauseHeight();
792    }
793  }
794
795  private refreshAllNode(filterData: any, isAnalysisReset?: boolean): void {
796    let nmCallTreeArgs: any[] = [];
797    let isTopDown: boolean = !filterData.callTree[0];
798    let isHideSystemLibrary = filterData.callTree[1];
799    this.isHideThread = filterData.callTree[3];
800    let list = filterData.dataMining.concat(filterData.dataLibrary);
801    let groupArgs = this.setGroupArgsByRefreshAllNode();
802    if ((this.lastIsExpression && !this.expressionStruct) || isAnalysisReset) {
803      nmCallTreeArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] });
804    }
805    nmCallTreeArgs.push({ funcName: 'hideThread', funcArgs: [this.isHideThread] });
806    nmCallTreeArgs.push(
807      {
808        funcName: 'groupCallchainSample',
809        funcArgs: [groupArgs],
810      },
811      {
812        funcName: 'getCallChainsBySampleIds',
813        funcArgs: [isTopDown],
814      }
815    );
816    this.filesystemTbr!.recycleDataSource = [];
817    if (isHideSystemLibrary) {
818      nmCallTreeArgs.push({
819        funcName: 'hideSystemLibrary',
820        funcArgs: [],
821      });
822    }
823    if (filterData.callTreeConstraints.checked) {
824      nmCallTreeArgs.push({
825        funcName: 'hideNumMaxAndMin',
826        funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]],
827      });
828    }
829    nmCallTreeArgs.push({ funcName: 'splitAllProcess', funcArgs: [list] });
830    nmCallTreeArgs.push({ funcName: 'resetAllNode', funcArgs: [] });
831    this.getDataByWorker(nmCallTreeArgs, (result: any[]) => {
832      this.setLTableData(result);
833      this.nmCallTreeFrameChart!.data = this.nmCallTreeSource;
834      if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData();
835    });
836  }
837
838  private setGroupArgsByRefreshAllNode(): Map<string, any> {
839    let groupArgs = new Map<string, any>();
840    groupArgs.set('filterAllocType', this.filterAllocationType);
841    groupArgs.set('filterEventType', this.filterNativeType);
842    if (this.expressionStruct) {
843      groupArgs.set('filterExpression', this.expressionStruct);
844      groupArgs.set('filterResponseType', -1);
845      this.currentNMCallTreeFilter!.thirdSelect = '0';
846    } else {
847      groupArgs.set('filterResponseType', this.filterResponseType);
848    }
849    groupArgs.set('leftNs', this.currentSelection?.leftNs || 0);
850    groupArgs.set('rightNs', this.currentSelection?.rightNs || 0);
851    let selections: Array<any> = [];
852    if (this.subTypeArr.length > 0) {
853      this.subTypeArr.map((memory): void => {
854        selections.push({
855          memoryTap: memory,
856        });
857      });
858    }
859    groupArgs.set('statisticsSelection', selections);
860    if (this._filterData) {
861      groupArgs.set('filterByTitleArr', this._filterData);
862    }
863    groupArgs.set(
864      'nativeHookType',
865      this.currentSelection!.nativeMemory.length > 0 ? 'native-hook' : 'native-hook-statistic'
866    );
867    return groupArgs;
868  }
869
870  setLTableData(resultData: any[], sort?: boolean): void {
871    if (sort) {
872      this.nmCallTreeSource = this.sortTree(resultData);
873    } else {
874      if (resultData && resultData[0]) {
875        this.nmCallTreeSource =
876          this.currentSelection!.nativeMemory.length > 0 && !this.isHideThread
877            ? this.sortTree(resultData)
878            : this.sortTree(resultData[0].children || []);
879      } else {
880        this.nmCallTreeSource = [];
881      }
882    }
883    this.nmCallTreeTbl!.recycleDataSource = this.nmCallTreeSource;
884  }
885
886  sortTree(arr: Array<any>): Array<any> {
887    let nmCallTreeSortArr = arr.sort((callTreeLeftData, callTreeRightData): number => {
888      if (this.sortKey === 'heapSizeStr' || this.sortKey === 'heapPercent') {
889        if (this.sortType === 0) {
890          return callTreeRightData.size - callTreeLeftData.size;
891        } else if (this.sortType === 1) {
892          return callTreeLeftData.size - callTreeRightData.size;
893        } else {
894          return callTreeRightData.size - callTreeLeftData.size;
895        }
896      } else {
897        if (this.sortType === 0) {
898          return callTreeRightData.count - callTreeLeftData.count;
899        } else if (this.sortType === 1) {
900          return callTreeLeftData.count - callTreeRightData.count;
901        } else {
902          return callTreeRightData.count - callTreeLeftData.count;
903        }
904      }
905    });
906    nmCallTreeSortArr.map((call): void => {
907      call.children = this.sortTree(call.children);
908    });
909    return nmCallTreeSortArr;
910  }
911
912  getDataByWorker(args: any[], handler: Function): void {
913    this.loadingList.push(1);
914    this.nmCallTreeProgressEL!.loading = true;
915    this.nmCallTreeLoadingPage.style.visibility = 'visible';
916    procedurePool.submitWithName(
917      'logic0',
918      'native-memory-calltree-action',
919      args,
920      undefined,
921      (callTreeActionResults: any): void => {
922        handler(callTreeActionResults);
923        this.loadingList.splice(0, 1);
924        if (this.loadingList.length === 0) {
925          this.nmCallTreeProgressEL!.loading = false;
926          this.nmCallTreeLoadingPage.style.visibility = 'hidden';
927        }
928      }
929    );
930  }
931
932  getDataByWorkerQuery(args: any, handler: Function): void {
933    this.loadingList.push(1);
934    this.nmCallTreeProgressEL!.loading = true;
935    this.nmCallTreeLoadingPage.style.visibility = 'visible';
936    procedurePool.submitWithName(
937      'logic0',
938      this.currentSelection!.nativeMemory!.length > 0
939        ? 'native-memory-queryCallchainsSamples'
940        : 'native-memory-queryStatisticCallchainsSamples',
941      args,
942      undefined,
943      (callChainsResults: any): void => {
944        handler(callChainsResults);
945        this.loadingList.splice(0, 1);
946        if (this.loadingList.length === 0) {
947          this.nmCallTreeProgressEL!.loading = false;
948          this.nmCallTreeLoadingPage.style.visibility = 'hidden';
949        }
950      }
951    );
952  }
953
954  initHtml(): string {
955    return TabPaneNMCallTreeHtml;
956  }
957}
958