• 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 */
15import { BaseElement, element } from '../../../../../base-ui/BaseElement';
16import { LitTable } from '../../../../../base-ui/table/lit-table';
17import { SelectionParam } from '../../../../bean/BoxSelection';
18import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie';
19import '../../../../../base-ui/chart/pie/LitChartPie';
20import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar';
21import { Utils } from '../../base/Utils';
22import { SpSystemTrace } from '../../../SpSystemTrace';
23import { procedurePool } from '../../../../database/Procedure';
24import { TabPaneFilter } from '../TabPaneFilter';
25import { LitCheckBox } from '../../../../../base-ui/checkbox/LitCheckBox';
26import { initSort } from '../SheetUtils';
27import { TabpaneNMCalltree } from './TabPaneNMCallTree';
28import { FilterByAnalysis } from '../../../../bean/NativeHook';
29import { InitAnalysis } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon';
30import { TabPaneNMStatisticAnalysisHtml } from './TabPaneNMStatisticAnalysis.html';
31
32const TYPE_ALLOC_STRING = 'AllocEvent';
33const TYPE_MAP_STRING = 'MmapEvent';
34const TYPE_OTHER_MMAP = 'Other MmapEvent';
35
36const TYPE_ALLOC = 0;
37const TYPE_MAP = 1;
38const TYPE_FREE = 2;
39const TYPE_UN_MAP = 3;
40const PIE_CHART_LIMIT = 20;
41
42class AnalysisObj {
43  tName?: string;
44  tid?: number;
45  typeName?: string;
46  typeId?: number;
47  libName?: string;
48  libId?: number;
49  symbolName?: string;
50  symbolId?: number;
51
52  tableName = '';
53
54  applySize: number;
55  applySizeFormat: string;
56  applyCount: number;
57  releaseSize: number;
58  releaseSizeFormat: string;
59  releaseCount: number;
60  existSize: number;
61  existSizeFormat: string;
62  existCount: number;
63
64  applySizePercent?: string;
65  applyCountPercent?: string;
66  releaseSizePercent?: string;
67  releaseCountPercent?: string;
68  existSizePercent?: string;
69  existCountPercent?: string;
70
71  constructor(applySize: number, applyCount: number, releaseSize: number, releaseCount: number) {
72    this.applySize = applySize;
73    this.applyCount = applyCount;
74    this.releaseSize = releaseSize;
75    this.releaseCount = releaseCount;
76    this.existSize = applySize - releaseSize;
77    this.existCount = applyCount - releaseCount;
78    this.applySizeFormat = Utils.getBinaryByteWithUnit(this.applySize);
79    this.releaseSizeFormat = Utils.getBinaryByteWithUnit(this.releaseSize);
80    this.existSizeFormat = Utils.getBinaryByteWithUnit(this.existSize);
81  }
82}
83
84class SizeObj {
85  applySize = 0;
86  applyCount = 0;
87  releaseSize = 0;
88  releaseCount = 0;
89}
90
91@element('tabpane-nm-statistic-analysis')
92export class TabPaneNMStatisticAnalysis extends BaseElement {
93  private currentSelection: SelectionParam | unknown;
94  private nmPieChart: LitChartPie | null | undefined;
95  private nmTableBox: HTMLDivElement | undefined | null;
96  private processData!: Array<unknown>;
97  private eventTypeData!: Array<AnalysisObj>;
98  private threadData!: Array<AnalysisObj>;
99  private soData!: Array<AnalysisObj>;
100  private functionData!: Array<AnalysisObj>;
101  private typeUsageTbl: LitTable | null | undefined;
102  private threadUsageTbl: LitTable | null | undefined;
103  private soUsageTbl: LitTable | null | undefined;
104  private functionUsageTbl: LitTable | null | undefined;
105  private range: HTMLLabelElement | null | undefined;
106  private nmBack: HTMLDivElement | null | undefined;
107  private threadName: string = '';
108  private tabName: HTMLDivElement | null | undefined;
109  private progressEL: LitProgressBar | null | undefined;
110  private type: string = '';
111  private isStatistic = false;
112  private typeMap!: Map<number, Array<unknown>>;
113  private currentLevel = -1;
114  private currentLevelApplySize = 0;
115  private currentLevelReleaseSize = 0;
116  private currentLevelExistSize = 0;
117  private currentLevelApplyCount = 0;
118  private currentLevelReleaseCount = 0;
119  private currentLevelExistCount = 0;
120  private currentLevelData!: Array<unknown>;
121  private typeStatisticsData!: {};
122  private threadStatisticsData!: {};
123  private libStatisticsData!: {};
124  private functionStatisticsData!: {};
125  private nmTableArray: NodeListOf<LitTable> | undefined | null;
126  private nmSortColumn: string = '';
127  private nmSortType: number = 0;
128  private titleEl: HTMLDivElement | undefined | null;
129  private filterEl: TabPaneFilter | undefined | null;
130  private hideThreadCheckBox: LitCheckBox | undefined | null;
131
132  get titleTxt(): string | null {
133    return this.titleEl!.textContent;
134  }
135
136  set data(statisticAnalysisParam: SelectionParam) {
137    if (statisticAnalysisParam === this.currentSelection) {
138      // @ts-ignore
139      this.eventTypeData.unshift(this.typeStatisticsData);
140      this.typeUsageTbl!.recycleDataSource = this.eventTypeData;
141      // @ts-ignore
142      this.eventTypeData.shift(this.typeStatisticsData);
143      return;
144    }
145    if (this.nmTableArray) {
146      for (let table of this.nmTableArray) {
147        initSort(table!, this.nmSortColumn, this.nmSortType);
148      }
149    }
150    this.hideThreadCheckBox!.checked = false;
151    if (statisticAnalysisParam.nativeMemoryStatistic.length > 0) {
152      Utils.getInstance().setCurrentSelectIPid(statisticAnalysisParam.nativeMemoryCurrentIPid);
153      Utils.getInstance().initResponseTypeList(statisticAnalysisParam);
154    }
155    this.resizeTable();
156    this.reset(this.typeUsageTbl!, false);
157    this.currentSelection = statisticAnalysisParam;
158    this.titleEl!.textContent = '';
159    this.tabName!.textContent = '';
160    this.range!.textContent = `Selected range: ${parseFloat(
161      ((statisticAnalysisParam.rightNs - statisticAnalysisParam.leftNs) / 1000000.0).toFixed(5)
162    )}  ms`;
163    this.isStatistic = statisticAnalysisParam.nativeMemory.length === 0;
164    if (this.isStatistic) {
165      this.threadName = '';
166    }
167    this.getNMEventTypeSize(statisticAnalysisParam);
168    this.showAssignLevel(this.typeUsageTbl!, this.functionUsageTbl!, 0, this.eventTypeData);
169  }
170
171  initNmTableArray(): void {
172    this.nmTableArray = this.shadowRoot!.querySelectorAll('lit-table') as NodeListOf<LitTable>;
173    for (let nmTable of this.nmTableArray) {
174      nmTable!.addEventListener('contextmenu', function (event) {
175        event.preventDefault(); // 阻止默认的上下文菜单弹框
176      });
177      nmTable!.addEventListener('column-click', (evt) => {
178        // @ts-ignore
179        this.nmSortColumn = evt.detail.key;
180        // @ts-ignore
181        this.nmSortType = evt.detail.sort;
182        this.sortByColumn();
183      });
184      nmTable!.addEventListener('row-hover', (evt) => {
185        // @ts-ignore
186        let detail = evt.detail;
187        if (detail.data) {
188          let data = detail.data;
189          data.isHover = true;
190          if (detail.callBack) {
191            detail.callBack(true);
192          }
193        }
194        this.nmPieChart?.showHover();
195        this.nmPieChart?.hideTip();
196      });
197    }
198    this.threadUsageTbl!.addEventListener('row-click', (evt) => {
199      // @ts-ignore
200      let button = evt.detail.button;
201      // @ts-ignore
202      let data = evt.detail.data;
203      if (button === 0) {
204        if (data.tableName !== '' && data.existSize !== 0) {
205          this.nativeThreadLevelClickEvent(data);
206        }
207      } else if (button === 2) {
208        let title = `${this.titleEl!.textContent}/${data.tName}`;
209        this.clickRight(evt, title);
210      }
211    });
212  }
213
214  initTable(): void {
215    this.typeUsageTbl!.addEventListener('row-click', (evt) => {
216      // @ts-ignore
217      let button = evt.detail.button;
218      // @ts-ignore
219      let data = evt.detail.data;
220      if (button === 0) {
221        if (data.tableName !== '' && data.existSize !== 0) {
222          this.nativeProcessLevelClickEvent(data);
223        }
224      } else if (button === 2) {
225        const typeName = data.typeName === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : data.typeName;
226        this.clickRight(evt, typeName);
227      }
228    });
229    this.soUsageTbl!.addEventListener('row-click', (evt) => {
230      // @ts-ignore
231      let button = evt.detail.button;
232      // @ts-ignore
233      let data = evt.detail.data;
234      if (button === 0) {
235        if (data.tableName !== '' && data.existSize !== 0) {
236          this.nativeSoLevelClickEvent(data);
237        }
238      } else if (button === 2) {
239        let title = `${this.titleEl!.textContent}/${data.libName}`;
240        this.clickRight(evt, title);
241      }
242    });
243  }
244
245  initElements(): void {
246    this.range = this.shadowRoot?.querySelector('#time-range');
247    this.nmPieChart = this.shadowRoot!.querySelector<LitChartPie>('#nm-chart-pie');
248    this.nmTableBox = this.shadowRoot!.querySelector<HTMLDivElement>('.nm-table-box');
249    this.typeUsageTbl = this.shadowRoot!.querySelector<LitTable>('#tb-eventtype-usage');
250    this.threadUsageTbl = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage');
251    this.soUsageTbl = this.shadowRoot!.querySelector<LitTable>('#tb-so-usage');
252    this.functionUsageTbl = this.shadowRoot!.querySelector<LitTable>('#tb-function-usage');
253    this.nmBack = this.shadowRoot!.querySelector<HTMLDivElement>('.nm-go-back');
254    this.tabName = this.shadowRoot!.querySelector<HTMLDivElement>('.nm-subheading');
255    this.progressEL = this.shadowRoot?.querySelector('.nm-progress') as LitProgressBar;
256    this.getBack();
257    this.titleEl = this.shadowRoot!.querySelector<HTMLDivElement>('.title');
258    this.filterEl = this.shadowRoot?.querySelector('#filter');
259    this.filterEl!.setOptionsList(['Hide Thread']);
260    let popover = this.filterEl!.shadowRoot!.querySelector('#check-popover');
261    this.hideThreadCheckBox = popover!!.querySelector<LitCheckBox>('div > #hideThread');
262    this.hideThreadCheckBox?.addEventListener('change', () => {
263      this.reset(this.typeUsageTbl!, false);
264      this.showAssignLevel(this.typeUsageTbl!, this.functionUsageTbl!, 0, this.eventTypeData); // @ts-ignore
265      this.getNMTypeSize(this.currentSelection, this.processData);
266    });
267    this.initNmTableArray();
268    this.initTable();
269    this.functionUsageTbl?.addEventListener('row-click', (evt) => {
270      // @ts-ignore
271      let title = `${this.titleEl!.textContent}/${evt.detail.data.symbolName}`;
272      this.clickRight(evt, title);
273    });
274    let exportHandlerMap = new Map<string, (value: unknown) => string>();
275    exportHandlerMap.set('existSizeFormat', (value) => {
276      // @ts-ignore
277      return `${value.existSize}`;
278    });
279    exportHandlerMap.set('applySizeFormat', (value) => {
280      // @ts-ignore
281      return `${value.applySize}`;
282    });
283    exportHandlerMap.set('releaseSizeFormat', (value) => {
284      // @ts-ignore
285      return `${value.releaseSize}`;
286    });
287    this.typeUsageTbl!.exportTextHandleMap = exportHandlerMap;
288    this.threadUsageTbl!.exportTextHandleMap = exportHandlerMap;
289    this.soUsageTbl!.exportTextHandleMap = exportHandlerMap;
290    this.functionUsageTbl!.exportTextHandleMap = exportHandlerMap;
291  }
292
293  private clickRight(evt: unknown, title: string): void {
294    // @ts-ignore
295    if (evt.detail.button === 2) {
296      let treeTab = this.parentElement?.parentElement?.querySelector<TabpaneNMCalltree>(
297        '#box-native-calltree > tabpane-nm-calltree'
298      );
299      treeTab!.analysisTabWidth = this.clientWidth; // @ts-ignore
300      const data = evt.detail.data as AnalysisObj;
301      treeTab!.filterData = new FilterByAnalysis(
302        data.typeId,
303        data.typeName,
304        data.tName,
305        data.tid,
306        data.libId,
307        data.libName,
308        data.symbolId,
309        data.symbolName
310      );
311      // 首次打开初始化数据 非首次初始化UI
312      if (!InitAnalysis.getInstance().isInitAnalysis) {
313        treeTab?.initUI();
314        treeTab?.filterByAnalysis();
315      } else {
316        treeTab!.initFromAnalysis = true; // @ts-ignore
317        treeTab!.data = this.currentSelection;
318        InitAnalysis.getInstance().isInitAnalysis = false;
319      }
320
321      treeTab!.banTypeAndLidSelect();
322      treeTab!.titleBoxShow = true;
323      treeTab!.titleTxt = title;
324    }
325  }
326
327  private getDataFromWorker(val: SelectionParam, typeFilter: Array<number | string>): void {
328    this.getDataByWorkerQuery(
329      {
330        leftNs: val.leftNs,
331        rightNs: val.rightNs,
332        types: typeFilter,
333        isStatistic: this.isStatistic,
334      },
335      (results: unknown) => {
336        this.processData = JSON.parse(JSON.stringify(results));
337        this.getNMTypeSize(val, this.processData);
338      }
339    );
340  }
341
342  private getDataByWorkerQuery(args: unknown, handler: Function): void {
343    this.progressEL!.loading = true;
344    procedurePool.submitWithName('logic0', 'native-memory-queryAnalysis', args, undefined, (results: unknown) => {
345      handler(results);
346      this.progressEL!.loading = false;
347    });
348  }
349
350  private reset(showTable: LitTable, isShowBack: boolean): void {
351    this.clearData();
352    if (isShowBack) {
353      this.nmBack!.style.visibility = 'visible';
354    } else {
355      this.nmBack!.style.visibility = 'hidden';
356    }
357    if (this.nmTableArray) {
358      for (let table of this.nmTableArray) {
359        if (table === showTable) {
360          initSort(table, this.nmSortColumn, this.nmSortType);
361          table.style.display = 'grid';
362          table!.removeAttribute('hideDownload');
363        } else {
364          table!.style.display = 'none';
365          table.setAttribute('hideDownload', '');
366        }
367      }
368    }
369  }
370
371  private clearData(): void {
372    this.nmPieChart!.dataSource = [];
373    this.typeUsageTbl!.recycleDataSource = [];
374    this.threadUsageTbl!.recycleDataSource = [];
375    this.soUsageTbl!.recycleDataSource = [];
376    this.functionUsageTbl!.recycleDataSource = [];
377  }
378
379  private showAssignLevel(
380    showNMTable: LitTable,
381    hideNMTable: LitTable,
382    currentLevel: number,
383    currentLevelData: Array<unknown>
384  ): void {
385    showNMTable!.style.display = 'grid';
386    hideNMTable!.style.display = 'none';
387    hideNMTable.setAttribute('hideDownload', '');
388    showNMTable?.removeAttribute('hideDownload');
389    this.currentLevel = currentLevel;
390    this.currentLevelData = currentLevelData;
391  }
392
393  private getBack(): void {
394    this.nmBack!.addEventListener('click', () => {
395      if (this.tabName!.textContent === 'Statistic By Thread Existing') {
396        this.showAssignLevel(this.typeUsageTbl!, this.threadUsageTbl!, 0, this.eventTypeData);
397        this.nmBack!.style.visibility = 'hidden';
398        this.typePieChart();
399      } else if (this.tabName!.textContent === 'Statistic By Library Existing') {
400        if (this.hideThreadCheckBox?.checked || this.isStatistic) {
401          this.showAssignLevel(this.typeUsageTbl!, this.soUsageTbl!, 0, this.eventTypeData);
402          this.nmBack!.style.visibility = 'hidden';
403          this.typePieChart();
404        } else {
405          this.showAssignLevel(this.threadUsageTbl!, this.soUsageTbl!, 1, this.threadData);
406          this.threadPieChart();
407        }
408      } else if (this.tabName!.textContent === 'Statistic By Function Existing') {
409        this.showAssignLevel(this.soUsageTbl!, this.functionUsageTbl!, 2, this.soData);
410        this.libraryPieChart();
411      }
412    });
413  }
414
415  private typePieChart(): void {
416    this.nmPieChart!.config = {
417      appendPadding: 0,
418      data: this.getPieChartData(this.eventTypeData),
419      angleField: 'existSize',
420      colorField: 'tableName',
421      radius: 1,
422      label: {
423        type: 'outer',
424      },
425      tip: (typeTipValue): string => {
426        // @ts-ignore
427        const obj = typeTipValue.obj as AnalysisObj;
428        return `<div>
429                    <div>Memory Type:${obj.tableName}</div>
430                    <div>Existing:${obj.existSizeFormat} (${obj.existSizePercent}%)</div>
431                    <div># Existing:${obj.existCount} (${obj.existCountPercent}%)</div>
432                    <div>Total Bytes:${obj.applySizeFormat} (${obj.applySizePercent}%)</div>
433                    <div># Total:${obj.applyCount} (${obj.applyCountPercent}%)</div>
434                    <div>Transient:${obj.releaseSizeFormat} (${obj.releaseSizePercent}%)</div>
435                    <div># Transient:${obj.releaseCount} (${obj.releaseCountPercent}%)</div>
436                </div>`;
437      },
438      angleClick: (it): void => {
439        // @ts-ignore
440        if (it.tableName !== 'other') {
441          this.nativeProcessLevelClickEvent(it);
442        }
443      },
444      hoverHandler: (nmData): void => {
445        if (nmData) {
446          this.typeUsageTbl!.setCurrentHover(nmData);
447        } else {
448          this.typeUsageTbl!.mouseOut();
449        }
450      },
451      interactions: [
452        {
453          type: 'element-active',
454        },
455      ],
456    };
457
458    this.titleEl!.textContent = '';
459    this.tabName!.textContent = 'Statistic By Event Type Existing';
460    // @ts-ignore
461    this.eventTypeData.unshift(this.typeStatisticsData);
462    this.typeUsageTbl!.recycleDataSource = this.eventTypeData;
463    // @ts-ignore
464    this.eventTypeData.shift(this.typeStatisticsData);
465    this.typeUsageTbl?.reMeauseHeight();
466    this.currentLevelData = this.eventTypeData;
467  }
468
469  private threadPieChart(): void {
470    this.nmPieChart!.config = {
471      appendPadding: 0,
472      data: this.getPieChartData(this.threadData),
473      angleField: 'existSize',
474      colorField: 'tableName',
475      radius: 1,
476      label: {
477        type: 'outer',
478      },
479      tip: (threadTipValue): string => {
480        // @ts-ignore
481        const obj = threadTipValue.obj as AnalysisObj;
482        return `<div>
483                    <div>Thread:${obj.tableName}</div>
484                    <div>Existing:${obj.existSizeFormat} (${obj.existSizePercent}%)</div>
485                    <div># Existing:${obj.existCount} (${obj.existCountPercent}%)</div>
486                    <div>Total Bytes:${obj.applySizeFormat} (${obj.applySizePercent}%)</div>
487                    <div># Total:${obj.applyCount} (${obj.applyCountPercent}%)</div>
488                    <div>Transient:${obj.releaseSizeFormat} (${obj.releaseSizePercent}%)</div>
489                    <div># Transient:${obj.releaseCount} (${obj.releaseCountPercent}%)</div>
490                </div>`;
491      },
492      angleClick: (it: unknown): void => {
493        // @ts-ignore
494        if (it.tid !== 'other') {
495          // @ts-ignore
496          this.nativeThreadLevelClickEvent(it);
497        }
498      },
499      hoverHandler: (data): void => {
500        if (data) {
501          this.threadUsageTbl!.setCurrentHover(data);
502        } else {
503          this.threadUsageTbl!.mouseOut();
504        }
505      },
506      interactions: [
507        {
508          type: 'element-active',
509        },
510      ],
511    };
512    const typeName = this.type === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : this.type;
513    this.titleEl!.textContent = typeName + '';
514    this.tabName!.textContent = 'Statistic By Thread Existing';
515    // @ts-ignore
516    this.threadData.unshift(this.threadStatisticsData);
517    this.threadUsageTbl!.recycleDataSource = this.threadData;
518    // @ts-ignore
519    this.threadData.shift(this.threadStatisticsData);
520    this.currentLevelData = this.threadData;
521    this.threadUsageTbl?.reMeauseHeight();
522  }
523
524  private getLibraryTipValue(libraryTipValue: unknown): string {
525    // @ts-ignore
526    const obj = libraryTipValue.obj as AnalysisObj;
527    return `<div>
528                    <div>Library:${obj.libName}</div>
529                    <div>Existing:${obj.existSizeFormat}
530                    (${obj.existSizePercent}%)</div>
531                    <div># Existing:${obj.existCount}
532                    (${obj.existCountPercent}%)</div>
533                    <div>Total Bytes:${obj.applySizeFormat}
534                    (${obj.applySizePercent}%)</div>
535                    <div># Total:${obj.applyCount}
536                    (${obj.applyCountPercent}%)</div>
537                    <div>Transient:${obj.releaseSizeFormat}
538                    (${obj.releaseSizePercent}%)</div>
539                    <div># Transient:${obj.releaseCount}
540                    (${obj.releaseCountPercent}%)</div>
541                </div>`;
542  }
543
544  private libraryPieChart(item?: unknown): void {
545    this.nmPieChart!.config = {
546      appendPadding: 0,
547      data: this.getPieChartData(this.soData),
548      angleField: 'existSize',
549      colorField: 'tableName',
550      radius: 1,
551      label: {
552        type: 'outer',
553      },
554      tip: (libraryTipValue): string => {
555        return this.getLibraryTipValue(libraryTipValue);
556      },
557      angleClick: (it): void => {
558        // @ts-ignore
559        if (it.tableName !== 'other') {
560          this.nativeSoLevelClickEvent(it);
561        }
562      },
563      hoverHandler: (data): void => {
564        if (data) {
565          this.soUsageTbl!.setCurrentHover(data);
566        } else {
567          this.soUsageTbl!.mouseOut();
568        }
569      },
570      interactions: [
571        {
572          type: 'element-active',
573        },
574      ],
575    };
576    const typeName = this.type === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : this.type;
577    let title = typeName;
578    if (!this.hideThreadCheckBox?.checked && this.threadName.length > 0) {
579      title += ' / ' + this.threadName;
580    }
581    this.titleEl!.textContent = title;
582    this.tabName!.textContent = 'Statistic By Library Existing';
583    // @ts-ignore
584    this.soData.unshift(this.libStatisticsData);
585    this.soUsageTbl!.recycleDataSource = this.soData;
586    // @ts-ignore
587    this.soData.shift(this.libStatisticsData);
588    this.currentLevelData = this.soData;
589    this.soUsageTbl?.reMeauseHeight();
590  }
591
592  private functionPieChart(): void {
593    this.nmPieChart!.config = {
594      appendPadding: 0,
595      data: this.getPieChartData(this.functionData),
596      angleField: 'existSize',
597      colorField: 'tableName',
598      radius: 1,
599      label: {
600        type: 'outer',
601      },
602      tip: (functionTipValue): string => {
603        // @ts-ignore
604        const obj = functionTipValue.obj as AnalysisObj;
605        return `<div>
606                    <div>Function:${obj.symbolName}</div>
607                    <div>Existing:${obj.existSizeFormat}
608                    (${obj.existSizePercent}%)</div>
609                    <div># Existing:${obj.existCount}
610                    (${obj.existCountPercent}%)</div>
611                    <div>Total Bytes:${obj.applySizeFormat}
612                    (${obj.applySizePercent}%)</div>
613                    <div># Total:${obj.applyCount}
614                    (${obj.applyCountPercent}%)</div>
615                    <div>Transient:${obj.releaseSizeFormat}
616                    (${obj.releaseSizePercent}%)</div>
617                    <div># Transient:${obj.releaseCount}
618                    (${obj.releaseCountPercent}%)</div>
619                </div>`;
620      },
621      hoverHandler: (data): void => {
622        if (data) {
623          this.functionUsageTbl!.setCurrentHover(data);
624        } else {
625          this.functionUsageTbl!.mouseOut();
626        }
627      },
628      interactions: [
629        {
630          type: 'element-active',
631        },
632      ],
633    };
634    // @ts-ignore
635    this.functionData.unshift(this.functionStatisticsData);
636    this.functionUsageTbl!.recycleDataSource = this.functionData;
637    // @ts-ignore
638    this.functionData.shift(this.functionStatisticsData);
639    this.currentLevelData = this.functionData;
640    this.functionUsageTbl?.reMeauseHeight();
641  }
642
643  private nativeProcessLevelClickEvent(it: unknown): void {
644    if (this.hideThreadCheckBox?.checked || this.isStatistic) {
645      this.reset(this.soUsageTbl!, true);
646      this.showAssignLevel(this.soUsageTbl!, this.typeUsageTbl!, 1, this.eventTypeData);
647      this.getNMLibSize(it);
648    } else {
649      this.reset(this.threadUsageTbl!, true);
650      this.showAssignLevel(this.threadUsageTbl!, this.typeUsageTbl!, 1, this.eventTypeData);
651      this.getNMThreadSize(it);
652    } // @ts-ignore
653    const typeName = it.typeName === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : it.typeName;
654    this.titleEl!.textContent = typeName;
655    // @ts-ignore
656    this.type = it.typeName;
657    this.nmPieChart?.hideTip();
658  }
659
660  private nativeThreadLevelClickEvent(it: AnalysisObj): void {
661    this.reset(this.soUsageTbl!, true);
662    this.showAssignLevel(this.soUsageTbl!, this.threadUsageTbl!, 2, this.eventTypeData);
663    this.getNMLibSize(it);
664    const typeName = this.type === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : this.type;
665
666    // @ts-ignore
667    let title = typeName;
668    if (!this.hideThreadCheckBox?.checked) {
669      this.threadName = `Thread(${it.tid})`;
670      title += ` / ${this.threadName}`;
671    }
672    this.titleEl!.textContent = title;
673    this.nmPieChart?.hideTip();
674  }
675
676  private nativeSoLevelClickEvent(it: unknown): void {
677    this.reset(this.functionUsageTbl!, true);
678    this.showAssignLevel(this.functionUsageTbl!, this.soUsageTbl!, 3, this.eventTypeData);
679    this.getNMFunctionSize(it);
680    const typeName = this.type === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : this.type;
681    // @ts-ignore
682    let title = typeName || '';
683    if (!this.hideThreadCheckBox?.checked && this.threadName.length > 0) {
684      title += ` / ${this.threadName}`;
685    } // @ts-ignore
686    if (it.libName.length > 0) {
687      // @ts-ignore
688      title += ` / ${it.libName}`;
689    }
690    this.titleEl!.textContent = title;
691    this.nmPieChart?.hideTip();
692  }
693
694  private getNMEventTypeSize(val: SelectionParam): void {
695    this.progressEL!.loading = true;
696    let typeFilter = [];
697    if (this.isStatistic) {
698      for (let type of val.nativeMemoryStatistic) {
699        if (type === 'All Heap & Anonymous VM') {
700          typeFilter = [0, 1];
701          break;
702        } else if (type === 'All Heap') {
703          typeFilter.push(0);
704        } else {
705          typeFilter.push(1);
706        }
707      }
708      this.getDataFromWorker(val, typeFilter);
709    } else {
710      for (let type of val.nativeMemory) {
711        if (type === 'All Heap & Anonymous VM') {
712          typeFilter = [];
713          typeFilter.push(...["'AllocEvent'", "'FreeEvent'", "'MmapEvent'", "'MunmapEvent'"]);
714          break;
715        } else if (type === 'All Heap') {
716          typeFilter.push(...["'AllocEvent'", "'FreeEvent'"]);
717        } else {
718          typeFilter.push(...["'MmapEvent'", "'MunmapEvent'"]);
719        }
720      }
721      this.getDataFromWorker(val, typeFilter);
722    }
723  }
724
725  private getNMTypeSize(val: SelectionParam, result: unknown): void {
726    this.resetCurrentLevelData(); // @ts-ignore
727    this.typeMap = this.typeSizeGroup(this.processData);
728    this.currentLevelExistSize = this.currentLevelApplySize - this.currentLevelReleaseSize;
729    this.currentLevelExistCount = this.currentLevelApplyCount - this.currentLevelReleaseCount;
730    this.eventTypeData = [];
731    if (this.typeMap.has(TYPE_ALLOC)) {
732      let allocType = this.setTypeMap(this.typeMap, TYPE_ALLOC, TYPE_ALLOC_STRING);
733      if (allocType) {
734        this.calPercent(allocType);
735        this.eventTypeData.push(allocType);
736      }
737    }
738    if (this.typeMap.has(TYPE_MAP)) {
739      let subTypeMap = new Map<string, Array<number | string>>();
740      for (let item of this.typeMap.get(TYPE_MAP)!) {
741        // @ts-ignore
742        if (item.subType) {
743          // @ts-ignore
744          if (subTypeMap.has(item.subType)) {
745            // @ts-ignore
746            subTypeMap.get(item.subType)?.push(item);
747          } else {
748            let dataArray: Array<number | string> = []; // @ts-ignore
749            dataArray.push(item); // @ts-ignore
750            subTypeMap.set(item.subType, dataArray);
751          }
752        } else {
753          if (subTypeMap.has(TYPE_MAP_STRING)) {
754            // @ts-ignore
755            subTypeMap.get(TYPE_MAP_STRING)?.push(item);
756          } else {
757            let dataArray: Array<number | string> = []; // @ts-ignore
758            dataArray.push(item);
759            subTypeMap.set(TYPE_MAP_STRING, dataArray);
760          }
761        }
762      }
763      subTypeMap.forEach((arr: Array<number | string>, subType: string) => {
764        let mapType = this.setTypeMap(this.typeMap, TYPE_MAP, subType);
765        if (mapType) {
766          this.calPercent(mapType);
767          this.eventTypeData.push(mapType);
768        }
769      });
770    }
771    this.eventTypeData.sort((a, b) => b.existSize - a.existSize);
772    this.typeStatisticsData = this.totalData(this.typeStatisticsData);
773    this.progressEL!.loading = false;
774    this.currentLevel = 0;
775    this.typePieChart();
776  }
777
778  private getNMThreadSize(item: unknown): void {
779    this.progressEL!.loading = true;
780    let threadMap = new Map<number, Array<number | string>>(); // @ts-ignore
781    let types = this.getTypes(item); // @ts-ignore
782    let typeName = item.typeName;
783    this.resetCurrentLevelData(item);
784    for (let itemData of this.processData) {
785      // @ts-ignore
786      if (this.shouldSkipItem(typeName, types, itemData)) {
787        continue;
788      } // @ts-ignore
789      if (threadMap.has(itemData.tid)) {
790        // @ts-ignore
791        threadMap.get(itemData.tid)?.push(itemData);
792      } else {
793        let itemArray: Array<number | string> = []; // @ts-ignore
794        itemArray.push(itemData); // @ts-ignore
795        threadMap.set(itemData.tid, itemArray);
796      }
797    }
798    this.threadData = [];
799    threadMap.forEach((dbData: Array<unknown>, tid: number) => {
800      const sizeObj = this.calSizeObj(dbData);
801      let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount);
802      this.calPercent(analysis); // @ts-ignore
803      analysis.typeId = item.typeId; // @ts-ignore
804      analysis.typeName = item.typeName;
805      analysis.tid = tid; // @ts-ignore
806      if (dbData[0].threadName && dbData[0].threadName.length > 0) {
807        // @ts-ignore
808        analysis.tName = `${dbData[0].threadName}(${tid})`;
809      } else {
810        analysis.tName = `Thread ${tid}`;
811      }
812      analysis.tableName = analysis.tName;
813      this.threadData.push(analysis);
814    });
815    this.threadData.sort((a, b) => b.existSize - a.existSize);
816    this.threadStatisticsData = this.totalData(this.threadStatisticsData);
817    this.currentLevel = 1;
818    this.currentLevelData = this.threadData;
819    this.progressEL!.loading = false;
820    this.threadPieChart();
821  }
822
823  private shouldSkipItem(typeName: string, types: Array<number | string>, itemData: unknown): boolean {
824    if (typeName === TYPE_ALLOC_STRING) {
825      // @ts-ignore
826      return !types.includes(itemData.type);
827    } else if (typeName === TYPE_MAP_STRING) {
828      if (this.isStatistic) {
829        // @ts-ignore
830        if (itemData.subType) {
831          // @ts-ignore
832          return !types.includes(itemData.subType) || !types.includes(itemData.type);
833        } else {
834          return true;
835        }
836      } else {
837        // @ts-ignore
838        if (!itemData.subType) {
839          // @ts-ignore
840          return !types.includes(itemData.type);
841        } else {
842          return true;
843        }
844      }
845    } else {
846      // @ts-ignore
847      if (itemData.subType) {
848        // @ts-ignore
849        return !types.includes(itemData.subType) || !types.includes(itemData.type);
850      } else {
851        return true;
852      }
853    }
854  }
855
856  private getNMLibSize(item: unknown): void {
857    this.progressEL!.loading = true; // @ts-ignore
858    let typeId = item.typeId; // @ts-ignore
859    let typeName = item.typeName; // @ts-ignore
860    let tid = item.tid;
861    let libMap = new Map<number, Array<number | string>>();
862    this.resetCurrentLevelData(item); // @ts-ignore
863    let types = this.getTypes(item);
864    this.soData = [];
865    if (!this.processData) {
866      return;
867    }
868    for (let itemData of this.processData) {
869      if (this.shouldSkipItem(typeName, types, itemData)) {
870        continue;
871      } // @ts-ignore
872      if (tid !== undefined && tid !== itemData.tid) {
873        continue;
874      } // @ts-ignore
875      let libId = itemData.libId;
876      if (libMap.has(libId)) {
877        // @ts-ignore
878        libMap.get(libId)?.push(itemData);
879      } else {
880        let dataArray: Array<number | string> = []; // @ts-ignore
881        dataArray.push(itemData);
882        libMap.set(libId, dataArray);
883      }
884    }
885    this.soData = [];
886    libMap.forEach((libItems, libId) => {
887      let libPath = SpSystemTrace.DATA_DICT.get(libId)?.split('/');
888      let libName = '';
889      if (libPath) {
890        libName = libPath[libPath.length - 1];
891      }
892      const sizeObj = this.calSizeObj(libItems);
893      let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount);
894      this.calPercent(analysis);
895      analysis.typeId = typeId;
896      analysis.typeName = typeName;
897      analysis.tid = tid;
898      analysis.tName = 'Thread ' + tid;
899      analysis.libId = libId;
900      analysis.libName = libName;
901      analysis.tableName = analysis.libName;
902      this.soData.push(analysis);
903    });
904    this.baseSort(this.soData);
905    this.libraryPieChart(item);
906  }
907
908  private getNMFunctionSize(item: unknown): void {
909    this.progressEL!.loading = true;
910    this.shadowRoot!.querySelector<HTMLDivElement>('.nm-subheading')!.textContent = 'Statistic By Function Existing';
911    // @ts-ignore
912    let typeId = item.typeId; // @ts-ignore
913    let typeName = item.typeName; // @ts-ignore
914    let tid = item.tid; // @ts-ignore
915    let libId = item.libId; // @ts-ignore
916    let symbolMap = new Map<number, Array<number | string>>();
917    this.resetCurrentLevelData(item); // @ts-ignore
918    let types = this.getTypes(item);
919    if (!this.processData) {
920      return;
921    }
922    for (let data of this.processData) {
923      if (this.skipItemByType(typeName, types, data, libId)) {
924        continue;
925      } // @ts-ignore
926      if (tid !== undefined && tid !== data.tid) {
927        continue;
928      } // @ts-ignore
929      if (symbolMap.has(data.symbolId)) {
930        // @ts-ignore
931        symbolMap.get(data.symbolId)?.push(data);
932      } else {
933        let dataArray: Array<number | string> = []; // @ts-ignore
934        dataArray.push(data); // @ts-ignore
935        symbolMap.set(data.symbolId, dataArray);
936      }
937    }
938    this.functionData = [];
939    symbolMap.forEach((symbolItems, symbolId) => {
940      let symbolPath = SpSystemTrace.DATA_DICT.get(symbolId)?.split('/');
941      let symbolName = symbolPath ? symbolPath[symbolPath.length - 1] : 'null';
942      const sizeObj = this.calSizeObj(symbolItems);
943      let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount);
944      this.calPercent(analysis);
945      analysis.typeId = typeId;
946      analysis.typeName = typeName;
947      analysis.tid = tid;
948      analysis.tName = 'Thread ' + tid;
949      analysis.libId = libId; // @ts-ignore
950      analysis.libName = item.libName;
951      analysis.symbolId = symbolId;
952      analysis.symbolName = symbolName;
953      analysis.tableName = analysis.symbolName;
954      this.functionData.push(analysis);
955    });
956    this.baseSort(this.functionData);
957    this.functionPieChart();
958  }
959
960  private skipItemByType(typeName: string, types: Array<string | number>, data: unknown, libId: number): boolean {
961    if (typeName === TYPE_ALLOC_STRING) {
962      // @ts-ignore
963      if (!types.includes(data.type) || data.libId !== libId) {
964        return true;
965      }
966    } else if (typeName === TYPE_MAP_STRING) {
967      if (this.isStatistic) {
968        // @ts-ignore
969        if (data.subType) {
970          // @ts-ignore
971          if (!types.includes(data.subType) || !types.includes(data.type) || data.libId !== libId) {
972            return true;
973          }
974        } else {
975          return true;
976        }
977      } else {
978        // @ts-ignore
979        if (!data.subType) {
980          // @ts-ignore
981          if (!types.includes(data.type) || data.libId !== libId) {
982            return true;
983          }
984        } else {
985          return true;
986        }
987      }
988    } else {
989      // @ts-ignore
990      if (data.subType) {
991        // @ts-ignore
992        if (!types.includes(data.subType) || !types.includes(data.type) || data.libId !== libId) {
993          return true;
994        }
995      } else {
996        return true;
997      }
998    }
999    return false;
1000  }
1001  private baseSort(data: Array<AnalysisObj>): void {
1002    if (data === this.functionData) {
1003      this.functionData.sort((a, b) => b.existSize - a.existSize);
1004      // @ts-ignore
1005      this.functionStatisticsData = this.totalData(this.functionStatisticsData);
1006      this.currentLevel = 3;
1007      this.progressEL!.loading = false;
1008    }
1009    if (data === this.soData) {
1010      this.soData.sort((a, b) => b.existSize - a.existSize);
1011      this.libStatisticsData = this.totalData(this.libStatisticsData);
1012      this.currentLevel = 2;
1013      this.progressEL!.loading = false;
1014    }
1015  }
1016
1017  private getPieChartData(res: unknown[]): unknown[] {
1018    if (res.length > PIE_CHART_LIMIT) {
1019      let pieChartArr: string[] = [];
1020      let other: unknown = {
1021        tableName: 'other',
1022        tName: 'other',
1023        libName: 'other',
1024        symbolName: 'other',
1025        existSizePercent: 0,
1026        existSize: 0,
1027        existSizeFormat: '',
1028        existCount: 0,
1029        existCountPercent: 0,
1030        applySizeFormat: '',
1031        applySize: 0,
1032        applySizePercent: 0,
1033        applyCount: 0,
1034        applyCountPercent: 0,
1035        releaseSizeFormat: '',
1036        releaseSize: 0,
1037        releaseSizePercent: 0,
1038        releaseCount: 0,
1039        releaseCountPercent: 0,
1040      };
1041      for (let i = 0; i < res.length; i++) {
1042        if (i < PIE_CHART_LIMIT - 1) {
1043          // @ts-ignore
1044          pieChartArr.push(res[i]);
1045        } else {
1046          // @ts-ignore
1047          other.existCount += res[i].existCount; // @ts-ignore
1048          other.existSize += res[i].existSize; // @ts-ignore
1049          other.applySize += res[i].applySize; // @ts-ignore
1050          other.applyCount += res[i].applyCount; // @ts-ignore
1051          other.releaseSize += res[i].releaseSize; // @ts-ignore
1052          other.releaseCount += res[i].releaseCount; // @ts-ignore
1053          other.existSizeFormat = Utils.getBinaryByteWithUnit(other.existSize); // @ts-ignore
1054          other.applySizeFormat = Utils.getBinaryByteWithUnit(other.applySize); // @ts-ignore
1055          other.releaseSizeFormat = Utils.getBinaryByteWithUnit(other.releaseSize); // @ts-ignore
1056          other.existSizePercent = this.currentLevelExistSize === 0 ? 0 : ((other.existSize / this.currentLevelExistSize) * 100).toFixed(2); // @ts-ignore
1057          other.existCountPercent = this.currentLevelExistCount === 0 ? 0 : ((other.existCount / this.currentLevelExistCount) * 100).toFixed(2); // @ts-ignore
1058          other.applySizePercent = this.currentLevelApplySize === 0 ? 0 : ((other.applySize / this.currentLevelApplySize) * 100).toFixed(2); // @ts-ignore
1059          other.applyCountPercent = this.currentLevelApplyCount === 0 ? 0 : ((other.applyCount / this.currentLevelApplyCount) * 100).toFixed(2);
1060          // @ts-ignore
1061          other.releaseSizePercent = this.currentLevelReleaseSize === 0 ? 0 :
1062            // @ts-ignore
1063            ((other.releaseSize / this.currentLevelReleaseSize) * 100).toFixed(2); // @ts-ignore
1064          other.releaseCountPercent = this.currentLevelReleaseCount === 0 ? 0 : ((other.releaseCount / this.currentLevelReleaseCount) * 100).toFixed(2);
1065        }
1066      } // @ts-ignore
1067      pieChartArr.push(other);
1068      return pieChartArr;
1069    }
1070    return res;
1071  }
1072
1073  private setTypeMap(typeMap: Map<number, unknown>, tyeId: number, typeName: string): AnalysisObj | null {
1074    let applySize = 0;
1075    let releaseSize = 0;
1076    let applyCount = 0;
1077    let releaseCount = 0;
1078    let currentType = typeMap.get(tyeId);
1079    if (!currentType) {
1080      return null;
1081    }
1082
1083    // @ts-ignore
1084    for (let applySample of typeMap.get(tyeId)!) {
1085      if (
1086        tyeId === TYPE_ALLOC ||
1087        (applySample.subType && applySample.subType === typeName) ||
1088        (!applySample.subType && typeName === TYPE_MAP_STRING)
1089      ) {
1090        applySize += applySample.size;
1091        applyCount += applySample.count;
1092        if (this.isStatistic) {
1093          releaseSize += applySample.releaseSize;
1094          releaseCount += applySample.releaseCount;
1095        } else {
1096          if (applySample.isRelease) {
1097            releaseSize += applySample.size;
1098            releaseCount += applySample.count;
1099          }
1100        }
1101      }
1102    }
1103    let typeItem = new AnalysisObj(applySize, applyCount, releaseSize, releaseCount);
1104    typeItem.typeId = tyeId;
1105    typeItem.typeName = typeName;
1106    typeItem.tableName = typeName === TYPE_MAP_STRING ? TYPE_OTHER_MMAP : typeName;
1107    return typeItem;
1108  }
1109
1110  private calPercent(item: AnalysisObj): void {
1111    item.applySizePercent = this.currentLevelApplySize === 0 ? '0' : ((item.applySize / this.currentLevelApplySize) * 100).toFixed(2);
1112    item.applyCountPercent = this.currentLevelApplyCount === 0 ? '0' : ((item.applyCount / this.currentLevelApplyCount) * 100).toFixed(2);
1113    item.releaseSizePercent = this.currentLevelReleaseSize === 0 ? '0' : ((item.releaseSize / this.currentLevelReleaseSize) * 100).toFixed(2);
1114    item.releaseCountPercent = this.currentLevelReleaseCount === 0 ? '0' : ((item.releaseCount / this.currentLevelReleaseCount) * 100).toFixed(2);
1115    item.existSizePercent = this.currentLevelExistSize === 0 ? '0' : ((item.existSize / this.currentLevelExistSize) * 100).toFixed(2);
1116    item.existCountPercent = this.currentLevelExistCount === 0 ? '0' : ((item.existCount / this.currentLevelExistCount) * 100).toFixed(2);
1117  }
1118
1119  private resetCurrentLevelData(parent?: unknown): void {
1120    if (parent) {
1121      // @ts-ignore
1122      this.currentLevelApplySize = parent.applySize; // @ts-ignore
1123      this.currentLevelApplyCount = parent.applyCount; // @ts-ignore
1124      this.currentLevelExistSize = parent.existSize; // @ts-ignore
1125      this.currentLevelExistCount = parent.existCount; // @ts-ignore
1126      this.currentLevelReleaseSize = parent.releaseSize; // @ts-ignore
1127      this.currentLevelReleaseCount = parent.releaseCount;
1128    } else {
1129      this.currentLevelApplySize = 0;
1130      this.currentLevelApplyCount = 0;
1131      this.currentLevelExistSize = 0;
1132      this.currentLevelExistCount = 0;
1133      this.currentLevelReleaseSize = 0;
1134      this.currentLevelReleaseCount = 0;
1135    }
1136  }
1137
1138  private typeSizeGroup(dbArray: Array<number | string>): Map<number, Array<number | string>> {
1139    let typeMap = new Map<number, Array<number | string>>();
1140    if (!dbArray || dbArray.length === 0) {
1141      return typeMap;
1142    }
1143
1144    const setSize = (item: unknown): void => {
1145      // @ts-ignore
1146      this.currentLevelApplySize += item.size; // @ts-ignore
1147      this.currentLevelApplyCount += item.count;
1148      if (this.isStatistic) {
1149        // @ts-ignore
1150        this.currentLevelReleaseSize += item.releaseSize; // @ts-ignore
1151        this.currentLevelReleaseCount += item.releaseCount;
1152      } else {
1153        // @ts-ignore
1154        if (item.isRelease) {
1155          // @ts-ignore
1156          this.currentLevelReleaseSize += item.size; // @ts-ignore
1157          this.currentLevelReleaseCount += item.count;
1158        }
1159      }
1160    };
1161
1162    for (let itemData of dbArray) {
1163      // @ts-ignore
1164      switch (itemData.type) {
1165        case TYPE_ALLOC:
1166          setSize(itemData);
1167          if (typeMap.has(TYPE_ALLOC)) {
1168            typeMap.get(TYPE_ALLOC)?.push(itemData);
1169          } else {
1170            let itemArray: Array<number | string> = [];
1171            itemArray.push(itemData);
1172            typeMap.set(TYPE_ALLOC, itemArray);
1173          }
1174          break;
1175        case TYPE_MAP:
1176          setSize(itemData);
1177          if (typeMap.has(TYPE_MAP)) {
1178            typeMap.get(TYPE_MAP)?.push(itemData);
1179          } else {
1180            let itemArray: Array<number | string> = [];
1181            itemArray.push(itemData);
1182            typeMap.set(TYPE_MAP, itemArray);
1183          }
1184          break;
1185      }
1186    }
1187    return typeMap;
1188  }
1189
1190  private calSizeObj(dbData: Array<unknown>): SizeObj {
1191    let sizeObj = new SizeObj();
1192    for (let item of dbData) {
1193      if (this.isStatistic) {
1194        // @ts-ignore
1195        sizeObj.applyCount += item.count; // @ts-ignore
1196        sizeObj.applySize += item.size; // @ts-ignore
1197        sizeObj.releaseCount += item.releaseCount; // @ts-ignore
1198        sizeObj.releaseSize += item.releaseSize;
1199      } else {
1200        // @ts-ignore
1201        sizeObj.applyCount += item.count; // @ts-ignore
1202        sizeObj.applySize += item.size; // @ts-ignore
1203        if (item.isRelease) {
1204          // @ts-ignore
1205          sizeObj.releaseCount += item.count; // @ts-ignore
1206          sizeObj.releaseSize += item.size;
1207        }
1208      }
1209    }
1210    return sizeObj;
1211  }
1212
1213  private getTypes(parent: AnalysisObj): Array<number | string> {
1214    let types: Array<number | string> = [];
1215    types.push(parent.typeId!);
1216    types.push(parent.typeName!);
1217    if (!this.isStatistic) {
1218      let releaseType;
1219      if (parent.typeId === TYPE_ALLOC) {
1220        releaseType = TYPE_FREE;
1221      } else {
1222        releaseType = TYPE_UN_MAP;
1223      }
1224      types.push(releaseType);
1225    }
1226    return types;
1227  }
1228
1229  private totalData(total: {}): {} {
1230    total = {
1231      existSizeFormat: Utils.getBinaryByteWithUnit(this.currentLevelExistSize),
1232      existSizePercent: this.currentLevelExistSize === 0 ? 0 : ((this.currentLevelExistSize / this.currentLevelExistSize) * 100).toFixed(2),
1233      existCount: this.currentLevelExistCount,
1234      existCountPercent: this.currentLevelExistCount === 0 ? 0 : ((this.currentLevelExistCount / this.currentLevelExistCount) * 100).toFixed(2),
1235      releaseSizeFormat: Utils.getBinaryByteWithUnit(this.currentLevelReleaseSize),
1236      releaseSizePercent: this.currentLevelReleaseSize === 0 ? 0 : ((this.currentLevelReleaseSize / this.currentLevelReleaseSize) * 100).toFixed(2),
1237      releaseCount: this.currentLevelReleaseCount,
1238      releaseCountPercent: this.currentLevelReleaseCount === 0 ? 0 : ((this.currentLevelReleaseCount / this.currentLevelReleaseCount) * 100).toFixed(2),
1239      applySizeFormat: Utils.getBinaryByteWithUnit(this.currentLevelApplySize),
1240      applySizePercent: this.currentLevelApplySize === 0 ? 0 : ((this.currentLevelApplySize / this.currentLevelApplySize) * 100).toFixed(2),
1241      applyCount: this.currentLevelApplyCount,
1242      applyCountPercent: this.currentLevelApplyCount === 0 ? 0 : ((this.currentLevelApplyCount / this.currentLevelApplyCount) * 100).toFixed(2),
1243      existSize: 0,
1244      tableName: '',
1245      tName: '',
1246      libName: '',
1247      symbolName: '',
1248    };
1249    return total;
1250  }
1251
1252  private getNmCurrentTable(): LitTable | null | undefined {
1253    let nmCurrentTable: LitTable | null | undefined;
1254    switch (this.currentLevel) {
1255      case 0:
1256        nmCurrentTable = this.typeUsageTbl;
1257        break;
1258      case 1:
1259        nmCurrentTable = this.threadUsageTbl;
1260        break;
1261      case 2:
1262        nmCurrentTable = this.soUsageTbl;
1263        break;
1264      case 3:
1265        nmCurrentTable = this.functionUsageTbl;
1266        break;
1267    }
1268    return nmCurrentTable;
1269  }
1270
1271  private getSortedColumnZeroArr(data: unknown[]): unknown[] {
1272    let sortColumnZeroArr = [...data];
1273    switch (this.currentLevel) {
1274      case 0:
1275        sortColumnZeroArr.unshift(this.typeStatisticsData);
1276        break;
1277      case 1:
1278        sortColumnZeroArr.unshift(this.threadStatisticsData);
1279        break;
1280      case 2:
1281        sortColumnZeroArr.unshift(this.libStatisticsData);
1282        break;
1283      case 3:
1284        sortColumnZeroArr.unshift(this.functionStatisticsData);
1285        break;
1286    }
1287    return sortColumnZeroArr;
1288  }
1289
1290  private updateSortColumnArr(sortColumnArr: unknown[]): unknown[] {
1291    switch (this.currentLevel) {
1292      case 0:
1293        sortColumnArr.unshift(this.typeStatisticsData);
1294        break;
1295      case 1:
1296        sortColumnArr.unshift(this.threadStatisticsData);
1297        break;
1298      case 2:
1299        sortColumnArr.unshift(this.libStatisticsData);
1300        break;
1301      case 3:
1302        sortColumnArr.unshift(this.functionStatisticsData);
1303        break;
1304    }
1305    return sortColumnArr;
1306  }
1307
1308  private caseTableName(
1309    statisticAnalysisLeftData: { tableName: number },
1310    statisticAnalysisRightData: { tableName: number }
1311  ): number {
1312    if (this.nmSortType === 1) {
1313      if (statisticAnalysisLeftData.tableName > statisticAnalysisRightData.tableName) {
1314        return 1;
1315      } else if (statisticAnalysisLeftData.tableName === statisticAnalysisRightData.tableName) {
1316        return 0;
1317      } else {
1318        return -1;
1319      }
1320    } else {
1321      if (statisticAnalysisRightData.tableName > statisticAnalysisLeftData.tableName) {
1322        return 1;
1323      } else if (statisticAnalysisLeftData.tableName === statisticAnalysisRightData.tableName) {
1324        return 0;
1325      } else {
1326        return -1;
1327      }
1328    }
1329  }
1330
1331  private sortDataByExistSize(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1332    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1333      return sortType === 1 // @ts-ignore
1334        ? statisticAnalysisLeftData.existSize - statisticAnalysisRightData.existSize // @ts-ignore
1335        : statisticAnalysisRightData.existSize - statisticAnalysisLeftData.existSize;
1336    });
1337  }
1338
1339  private sortDataByExistCount(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1340    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1341      return sortType === 1 // @ts-ignore
1342        ? statisticAnalysisLeftData.existCount - statisticAnalysisRightData.existCount // @ts-ignore
1343        : statisticAnalysisRightData.existCount - statisticAnalysisLeftData.existCount;
1344    });
1345  }
1346
1347  private sortDataByReleaseSize(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1348    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1349      return sortType === 1 // @ts-ignore
1350        ? statisticAnalysisLeftData.releaseSize - statisticAnalysisRightData.releaseSize // @ts-ignore
1351        : statisticAnalysisRightData.releaseSize - statisticAnalysisLeftData.releaseSize;
1352    });
1353  }
1354
1355  private sortDataByReleaseCount(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1356    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1357      return sortType === 1 // @ts-ignore
1358        ? statisticAnalysisLeftData.releaseCount - statisticAnalysisRightData.releaseCount // @ts-ignore
1359        : statisticAnalysisRightData.releaseCount - statisticAnalysisLeftData.releaseCount;
1360    });
1361  }
1362
1363  private sortDataByApplySize(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1364    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1365      return sortType === 1 // @ts-ignore
1366        ? statisticAnalysisLeftData.applySize - statisticAnalysisRightData.applySize // @ts-ignore
1367        : statisticAnalysisRightData.applySize - statisticAnalysisLeftData.applySize;
1368    });
1369  }
1370
1371  private sortDataByApplyCount(sortType: number, sortColumnArr: Array<unknown>): unknown[] {
1372    return sortColumnArr.sort((statisticAnalysisLeftData, statisticAnalysisRightData) => {
1373      return sortType === 1 // @ts-ignore
1374        ? statisticAnalysisLeftData.applyCount - statisticAnalysisRightData.applyCount // @ts-ignore
1375        : statisticAnalysisRightData.applyCount - statisticAnalysisLeftData.applyCount;
1376    });
1377  }
1378
1379  private sortByColumn(): void {
1380    let nmCurrentTable = this.getNmCurrentTable();
1381    if (!nmCurrentTable) {
1382      return;
1383    }
1384    if (this.nmSortType === 0) {
1385      nmCurrentTable!.recycleDataSource = this.getSortedColumnZeroArr(this.currentLevelData);
1386    } else {
1387      let sortColumnArr = [...this.currentLevelData];
1388      switch (this.nmSortColumn) {
1389        case 'tableName':
1390          // @ts-ignore
1391          nmCurrentTable!.recycleDataSource = sortColumnArr.sort(this.caseTableName);
1392          break;
1393        case 'existSizeFormat':
1394        case 'existSizePercent':
1395          nmCurrentTable!.recycleDataSource = this.sortDataByExistSize(this.nmSortType, sortColumnArr);
1396          break;
1397        case 'existCount':
1398        case 'existCountPercent':
1399          nmCurrentTable!.recycleDataSource = this.sortDataByExistCount(this.nmSortType, sortColumnArr);
1400          break;
1401        case 'releaseSizeFormat':
1402        case 'releaseSizePercent':
1403          nmCurrentTable!.recycleDataSource = this.sortDataByReleaseSize(this.nmSortType, sortColumnArr);
1404          break;
1405        case 'releaseCount':
1406        case 'releaseCountPercent':
1407          nmCurrentTable!.recycleDataSource = this.sortDataByReleaseCount(this.nmSortType, sortColumnArr);
1408          break;
1409        case 'applySizeFormat':
1410        case 'applySizePercent':
1411          nmCurrentTable!.recycleDataSource = this.sortDataByApplySize(this.nmSortType, sortColumnArr);
1412          break;
1413        case 'applyCount':
1414        case 'applyCountPercent':
1415          nmCurrentTable!.recycleDataSource = this.sortDataByApplyCount(this.nmSortType, sortColumnArr);
1416          break;
1417      }
1418      sortColumnArr = this.updateSortColumnArr(sortColumnArr);
1419      nmCurrentTable!.recycleDataSource = sortColumnArr;
1420    }
1421  }
1422
1423  resizeTable(): void {
1424    this.resize(this.typeUsageTbl);
1425    this.resize(this.threadUsageTbl);
1426    this.resize(this.soUsageTbl);
1427    this.resize(this.functionUsageTbl);
1428  }
1429
1430  resize(table?: LitTable | null): void {
1431    if (table) {
1432      // @ts-ignore
1433      table.shadowRoot.querySelector('.table').style.height = `${this.parentElement.clientHeight - 65}px`;
1434      table.reMeauseHeight();
1435    }
1436  }
1437
1438  public connectedCallback(): void {
1439    new ResizeObserver(() => {
1440      this.resizeTable();
1441      // @ts-ignore
1442      if (this.parentElement?.clientHeight !== 0) {
1443        if ((this.parentElement!.clientHeight >= 0 && this.parentElement!.clientHeight <= 31) || this.isStatistic) {
1444          this.filterEl!.style.display = 'none';
1445          this.nmPieChart!.style.marginBottom = '0px';
1446          this.nmTableBox!.style.marginBottom = '0px';
1447        } else {
1448          this.filterEl!.style.display = 'flex';
1449        }
1450      }
1451    }).observe(this.parentElement!);
1452  }
1453
1454  initHtml(): string {
1455    return TabPaneNMStatisticAnalysisHtml;
1456  }
1457}
1458