• 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 { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie';
19import { SelectionParam } from '../../../../bean/BoxSelection';
20import '../../../../../base-ui/chart/pie/LitChartPie';
21import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar';
22import { Utils } from '../../base/Utils';
23import { procedurePool } from '../../../../database/Procedure';
24import { LitCheckBox } from '../../../../../base-ui/checkbox/LitCheckBox';
25import { TabPaneFilter } from '../TabPaneFilter';
26import { initSort } from '../SheetUtils';
27import { TabpaneFilesystemCalltree } from './TabPaneFileSystemCalltree';
28import { NUM_5, NUM_MILLON } from '../../../../bean/NumBean';
29import { TabPaneFilesystemStatisticsAnalysisHtml } from './TabPaneFilesystemStatisticsAnalysis.html';
30
31@element('tabpane-file-statistics-analysis')
32export class TabPaneFilesystemStatisticsAnalysis extends BaseElement {
33  private fsPieChart: LitChartPie | null | undefined;
34  private fsCurrentSelection: SelectionParam | null | undefined;
35  private fileStatisticsAnalysisProcessData: any;
36  private fileStatisticsAnalysisThreadData!: any[];
37  private fileStatisticsAnalysisSoData!: any[];
38  private fileStatisticsAnalysisPidData!: any[];
39  private fileStatisticsAnalysisTypeData!: any[];
40  private fileStatisticsAnalysisFunctionData!: any[];
41  private fileStatisticsAnalysisTableProcess: LitTable | null | undefined;
42  private fileStatisticsAnalysisTableType: LitTable | null | undefined;
43  private fileStatisticsAnalysisTableThread: LitTable | null | undefined;
44  private fileStatisticsAnalysisTableSo: LitTable | null | undefined;
45  private fileStatisticsAnalysisTableFunction: LitTable | null | undefined;
46  private sumDur: number = 0;
47  private fileStatisticsAnalysisRange: HTMLLabelElement | null | undefined;
48  private fsBack: HTMLDivElement | null | undefined;
49  private tabName: HTMLDivElement | null | undefined;
50  private fileStatisticsAnalysisProgressEL: LitProgressBar | null | undefined;
51  private fsProcessName: string = '';
52  private fileStatisticsAnalysisThreadName: string = '';
53  private fsSortColumn: string = '';
54  private fsSortType: number = 0;
55  private typeName: string = '';
56  private currentLevel = -1;
57  private currentLevelData!: Array<any>;
58  private processStatisticsData!: {};
59  private typeStatisticsData!: {};
60  private threadStatisticsData!: {};
61  private libStatisticsData!: {};
62  private functionStatisticsData!: {};
63  private fileSystemTitleEl: HTMLDivElement | undefined | null;
64  private fileSystemFilterEl: TabPaneFilter | undefined | null;
65  private hideProcessCheckBox: LitCheckBox | undefined | null;
66  private hideThreadCheckBox: LitCheckBox | undefined | null;
67  private checkBoxs: NodeListOf<LitCheckBox> | undefined | null;
68  private fsTableArray: NodeListOf<LitTable> | undefined | null;
69
70  set data(val: SelectionParam) {
71    if (val === this.fsCurrentSelection) {
72      this.fileStatisticsAnalysisPidData.unshift(this.processStatisticsData);
73      this.fileStatisticsAnalysisTableProcess!.recycleDataSource = this.fileStatisticsAnalysisPidData;
74      // @ts-ignore
75      this.fileStatisticsAnalysisPidData.shift(this.processStatisticsData);
76      return;
77    }
78    this.fsCurrentSelection = val;
79    if (this.fsTableArray && this.fsTableArray.length > 0) {
80      for (let fsTable of this.fsTableArray) {
81        initSort(fsTable!, this.fsSortColumn, this.fsSortType);
82      }
83    }
84    this.reset(this.fileStatisticsAnalysisTableProcess!, false);
85    this.hideProcessCheckBox!.checked = false;
86    this.hideThreadCheckBox!.checked = false;
87    this.fileSystemTitleEl!.textContent = '';
88    this.tabName!.textContent = '';
89    this.fileStatisticsAnalysisRange!.textContent =
90      'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / NUM_MILLON).toFixed(NUM_5)) + ' ms';
91    this.fileStatisticsAnalysisProgressEL!.loading = true;
92    this.getDataByWorker(
93      [
94        {
95          funcName: 'setSearchValue',
96          funcArgs: [''],
97        },
98        {
99          funcName: 'getCurrentDataFromDb',
100          funcArgs: [{queryFuncName: 'fileSystem', ...val}],
101        },
102      ],
103      (results: any[]) => {
104        this.getFilesystemProcess(results);
105      }
106    );
107  }
108
109  initElements(): void {
110    this.fileStatisticsAnalysisRange = this.shadowRoot?.querySelector('#time-range');
111    this.fsPieChart = this.shadowRoot!.querySelector<LitChartPie>('#fs-chart-pie');
112    this.fileStatisticsAnalysisTableProcess = this.shadowRoot!.querySelector<LitTable>('#tb-process-usage');
113    this.fileStatisticsAnalysisTableThread = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage');
114    this.fileStatisticsAnalysisTableSo = this.shadowRoot!.querySelector<LitTable>('#tb-so-usage');
115    this.fileStatisticsAnalysisTableFunction = this.shadowRoot!.querySelector<LitTable>('#tb-function-usage');
116    this.fsBack = this.shadowRoot!.querySelector<HTMLDivElement>('.fs-go-back');
117    this.tabName = this.shadowRoot!.querySelector<HTMLDivElement>('.fs-subheading');
118    this.fileStatisticsAnalysisTableType = this.shadowRoot!.querySelector<LitTable>('#tb-type-usage');
119    this.fileStatisticsAnalysisProgressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar;
120    this.goBack();
121    this.fileSystemTitleEl = this.shadowRoot!.querySelector<HTMLDivElement>('.title');
122    this.fileSystemFilterEl = this.shadowRoot?.querySelector('#filter');
123    this.fileSystemFilterEl!.setOptionsList(['Hide Process', 'Hide Thread']);
124    let popover = this.fileSystemFilterEl!.shadowRoot!.querySelector('#check-popover');
125    this.hideProcessCheckBox = popover!!.querySelector<LitCheckBox>('div > #hideProcess');
126    this.hideThreadCheckBox = popover!!.querySelector<LitCheckBox>('div > #hideThread');
127    this.checkBoxs = popover!.querySelectorAll<LitCheckBox>('.check-wrap > lit-check-box');
128    this.fsTableArray = this.shadowRoot!.querySelectorAll('lit-table') as NodeListOf<LitTable>;
129    for (let fsTable of this.fsTableArray) {
130      this.columnClickListeners(fsTable);
131      fsTable!.addEventListener('contextmenu', function (event) {
132        event.preventDefault(); // 阻止默认的上下文菜单弹框
133      });
134      this.initTableRowHoverListeners(fsTable);
135      this.initTableRowClickListeners(fsTable);
136    }
137    for (let box of this.checkBoxs) {
138      this.checkBoxListener(box);
139    }
140    const addRowClickEventListener = (fsTable: LitTable, clickEvent: Function) => {
141      fsTable.addEventListener('row-click', (evt) => {
142        // @ts-ignore
143        const detail = evt.detail;
144        if (detail.button === 0 && detail.data.tableName !== '' && detail.data.duration !== 0) {
145          clickEvent(detail.data, this.fsCurrentSelection);
146        }
147      });
148    };
149    addRowClickEventListener(this.fileStatisticsAnalysisTableProcess!, this.fileProcessLevelClickEvent.bind(this));
150    addRowClickEventListener(this.fileStatisticsAnalysisTableType!, this.fileTypeLevelClickEvent.bind(this));
151    addRowClickEventListener(this.fileStatisticsAnalysisTableThread!, this.fileThreadLevelClickEvent.bind(this));
152    addRowClickEventListener(this.fileStatisticsAnalysisTableSo!, this.fileSoLevelClickEvent.bind(this));
153  }
154
155  private checkBoxListener(box: LitCheckBox): void {
156    box!.addEventListener('change', () => {
157      if (this.hideProcessCheckBox!.checked && this.hideThreadCheckBox!.checked) {
158        this.hideThread();
159        this.fsBack!.style.visibility = 'hidden';
160      } else if (this.hideProcessCheckBox!.checked && !this.hideThreadCheckBox!.checked) {
161        this.hideProcess();
162      } else {
163        this.reset(this.fileStatisticsAnalysisTableProcess!, false);
164        this.getFilesystemProcess(this.fileStatisticsAnalysisProcessData);
165      }
166    });
167  }
168
169  private initTableRowClickListeners(fsTable: LitTable): void {
170    fsTable!.addEventListener('row-click', (evt) => {
171      // @ts-ignore
172      let detail = evt.detail;
173      if (detail.button === 2) {
174        let fsTab = this.parentElement?.parentElement?.querySelector<TabpaneFilesystemCalltree>(
175          '#box-file-system-calltree > tabpane-filesystem-calltree'
176        );
177        fsTab!.cWidth = this.clientWidth;
178        fsTab!.currentFsCallTreeLevel = this.currentLevel;
179        if (this.hideProcessCheckBox?.checked) {
180          detail.data.pid = undefined;
181        }
182        if (this.hideThreadCheckBox?.checked) {
183          detail.data.tid = undefined;
184        }
185        fsTab!.fsRowClickData = detail.data;
186        let title = '';
187        if (this.fileSystemTitleEl?.textContent === '') {
188          title = detail.data.tableName;
189        } else {
190          title = this.fileSystemTitleEl?.textContent + ' / ' + detail.data.tableName;
191        }
192        fsTab!.pieTitle = title;
193        //  是否是在表格上右键点击跳转到火焰图的
194        this.fsCurrentSelection!.isRowClick = true;
195        fsTab!.data = this.fsCurrentSelection;
196      }
197    });
198  }
199
200  private initTableRowHoverListeners(fsTable: LitTable): void {
201    fsTable!.addEventListener('row-hover', (evt) => {
202      // @ts-ignore
203      let detail = evt.detail;
204      if (detail.data) {
205        let tableData = detail.data;
206        tableData.isHover = true;
207        if (detail.callBack) {
208          detail.callBack(true);
209        }
210      }
211      this.fsPieChart?.showHover();
212      this.fsPieChart?.hideTip();
213    });
214  }
215
216  private columnClickListeners(fsTable: LitTable): void {
217    fsTable!.addEventListener('column-click', (evt) => {
218      // @ts-ignore
219      this.fsSortColumn = evt.detail.key;
220      // @ts-ignore
221      this.fsSortType = evt.detail.sort;
222      this.sortByColumn();
223    });
224  }
225
226  private reset(showTable: LitTable, isShowBack: boolean): void {
227    this.clearData();
228    if (isShowBack) {
229      this.fsBack!.style.visibility = 'visible';
230    } else {
231      this.fsBack!.style.visibility = 'hidden';
232      this.fileSystemTitleEl!.textContent = '';
233    }
234    if (this.fsTableArray) {
235      for (let fileSystemTable of this.fsTableArray) {
236        if (fileSystemTable === showTable) {
237          initSort(fileSystemTable!, this.fsSortColumn, this.fsSortType);
238          fileSystemTable.style.display = 'grid';
239          fileSystemTable.setAttribute('hideDownload', '');
240        } else {
241          fileSystemTable!.style.display = 'none';
242          fileSystemTable!.removeAttribute('hideDownload');
243        }
244      }
245    }
246  }
247
248  private clearData(): void {
249    this.fsPieChart!.dataSource = [];
250    this.fileStatisticsAnalysisTableProcess!.recycleDataSource = [];
251    this.fileStatisticsAnalysisTableThread!.recycleDataSource = [];
252    this.fileStatisticsAnalysisTableType!.recycleDataSource = [];
253    this.fileStatisticsAnalysisTableSo!.recycleDataSource = [];
254    this.fileStatisticsAnalysisTableFunction!.recycleDataSource = [];
255  }
256
257  private showAssignLevel(showFsTable: LitTable, hideFsTable: LitTable, currentLevel: number): void {
258    showFsTable!.style.display = 'grid';
259    hideFsTable!.style.display = 'none';
260    hideFsTable.setAttribute('hideDownload', '');
261    showFsTable?.removeAttribute('hideDownload');
262    this.currentLevel = currentLevel;
263  }
264
265  private goBack(): void {
266    this.fsBack!.addEventListener('click', () => {
267      if (this.tabName!.textContent === 'Statistic By type AllDuration') {
268        this.fsBack!.style.visibility = 'hidden';
269        this.showAssignLevel(this.fileStatisticsAnalysisTableProcess!, this.fileStatisticsAnalysisTableType!, 0);
270        this.processPieChart();
271      } else if (this.tabName!.textContent === 'Statistic By Thread AllDuration') {
272        if (this.hideProcessCheckBox?.checked) {
273          this.fsBack!.style.visibility = 'hidden';
274        } else {
275          this.fsBack!.style.visibility = 'visible';
276        }
277        this.showAssignLevel(this.fileStatisticsAnalysisTableType!, this.fileStatisticsAnalysisTableThread!, 1);
278        this.typePieChart();
279      } else if (this.tabName!.textContent === 'Statistic By Library AllDuration') {
280        if (this.hideThreadCheckBox?.checked) {
281          if (this.hideProcessCheckBox?.checked) {
282            this.fsBack!.style.visibility = 'hidden';
283          }
284          this.showAssignLevel(this.fileStatisticsAnalysisTableType!, this.fileStatisticsAnalysisTableSo!, 1);
285          this.typePieChart();
286        } else {
287          this.showAssignLevel(this.fileStatisticsAnalysisTableThread!, this.fileStatisticsAnalysisTableSo!, 2);
288          this.threadPieChart();
289        }
290      } else if (this.tabName!.textContent === 'Statistic By Function AllDuration') {
291        this.showAssignLevel(this.fileStatisticsAnalysisTableSo!, this.fileStatisticsAnalysisTableFunction!, 3);
292        this.libraryPieChart();
293      }
294    });
295  }
296
297  private hideProcess(): void {
298    this.reset(this.fileStatisticsAnalysisTableType!, false);
299    this.fsProcessName = '';
300    this.getFilesystemType(null);
301  }
302
303  private hideThread(it?: any): void {
304    this.reset(this.fileStatisticsAnalysisTableType!, true);
305    this.fsProcessName = '';
306    this.fileStatisticsAnalysisThreadName = '';
307    if (it) {
308      this.getFilesystemType(it);
309    } else {
310      this.getFilesystemType(null);
311    }
312  }
313
314  private processPieChart(): void {
315    // @ts-ignore
316    this.sumDur = this.processStatisticsData.allDuration;
317    this.fsPieChart!.config = {
318      appendPadding: 0,
319      data: this.getFsPieChartData(this.fileStatisticsAnalysisPidData),
320      angleField: 'duration',
321      colorField: 'tableName',
322      radius: 1,
323      label: {
324        type: 'outer',
325      },
326      tip: this.getFsTip(),
327      angleClick: (fsPieClickItem): void => {
328        // @ts-ignore
329        if (fsPieClickItem.tableName !== 'other') {
330          this.fileProcessLevelClickEvent(fsPieClickItem);
331        }
332      },
333      hoverHandler: (fsPieData): void => {
334        if (fsPieData) {
335          this.fileStatisticsAnalysisTableProcess!.setCurrentHover(fsPieData);
336        } else {
337          this.fileStatisticsAnalysisTableProcess!.mouseOut();
338        }
339      },
340      interactions: [
341        {
342          type: 'element-active',
343        },
344      ],
345    };
346    this.fileSystemTitleEl!.textContent = '';
347    this.tabName!.textContent = 'Statistic By Process AllDuration';
348    this.fileStatisticsAnalysisPidData.unshift(this.processStatisticsData);
349    this.fileStatisticsAnalysisTableProcess!.recycleDataSource = this.fileStatisticsAnalysisPidData;
350    // @ts-ignore
351    this.fileStatisticsAnalysisPidData.shift(this.processStatisticsData);
352    this.currentLevelData = this.fileStatisticsAnalysisPidData;
353    this.fileStatisticsAnalysisTableProcess?.reMeauseHeight();
354  }
355
356  private fileProcessLevelClickEvent(it: any): void {
357    this.reset(this.fileStatisticsAnalysisTableType!, true);
358    this.getFilesystemType(it);
359    // @ts-ignore
360    this.fsProcessName = it.tableName;
361    this.fileSystemTitleEl!.textContent = this.fsProcessName;
362    this.fsPieChart?.hideTip();
363  }
364
365  private typePieChart(): void {
366    this.fsPieChart!.config = {
367      appendPadding: 0,
368      data: this.fileStatisticsAnalysisTypeData,
369      angleField: 'duration',
370      colorField: 'tableName',
371      radius: 1,
372      label: {
373        type: 'outer',
374      },
375      tip: this.getFileTypeTip(),
376      angleClick: (it): void => {
377        this.fileTypeLevelClickEvent(it);
378      },
379      hoverHandler: (data): void => {
380        if (data) {
381          this.fileStatisticsAnalysisTableType!.setCurrentHover(data);
382        } else {
383          this.fileStatisticsAnalysisTableType!.mouseOut();
384        }
385      },
386      interactions: [
387        {
388          type: 'element-active',
389        },
390      ],
391    };
392    this.fileSystemTitleEl!.textContent = this.fsProcessName;
393    this.tabName!.textContent = 'Statistic By type AllDuration';
394    this.fileStatisticsAnalysisTypeData.unshift(this.typeStatisticsData);
395    this.fileStatisticsAnalysisTableType!.recycleDataSource = this.fileStatisticsAnalysisTypeData;
396    // @ts-ignore
397    this.fileStatisticsAnalysisTypeData.shift(this.typeStatisticsData);
398    this.currentLevelData = this.fileStatisticsAnalysisTypeData;
399    this.fileStatisticsAnalysisTableType?.reMeauseHeight();
400  }
401
402  private getFileTypeTip() {
403    return (obj: { obj: { tableName: any; durFormat: any; percent: any } }): string => {
404      return `<div>
405                    <div>Type:${obj.obj.tableName}</div>
406                    <div>Duration:${obj.obj.durFormat}</div>
407                    <div>Percent:${obj.obj.percent}%</div>
408                </div>
409                `;
410    };
411  }
412
413  private fileTypeLevelClickEvent(it: any): void {
414    if (this.hideThreadCheckBox!.checked) {
415      this.reset(this.fileStatisticsAnalysisTableSo!, true);
416      this.getFilesystemSo(it);
417    } else {
418      this.reset(this.fileStatisticsAnalysisTableThread!, true);
419      this.getFilesystemThread(it);
420    }
421    // @ts-ignore
422    this.typeName = it.tableName;
423    let title = '';
424    if (this.fsProcessName.length > 0) {
425      title += this.fsProcessName + ' / ';
426    }
427    if (this.typeName.length > 0) {
428      title += this.typeName;
429    }
430    this.fileSystemTitleEl!.textContent = title;
431    this.fsPieChart?.hideTip();
432  }
433
434  private threadPieChart(): void {
435    // @ts-ignore
436    this.sumDur = this.threadStatisticsData.allDuration;
437    this.fsPieChart!.config = {
438      appendPadding: 0,
439      data: this.getFsPieChartData(this.fileStatisticsAnalysisThreadData),
440      angleField: 'duration',
441      colorField: 'tableName',
442      radius: 1,
443      label: {
444        type: 'outer',
445      },
446      tip: this.getFileTypeTip(),
447      angleClick: (it): void => {
448        // @ts-ignore
449        if (it.tableName != 'other') {
450          this.fileThreadLevelClickEvent(it);
451        }
452      },
453      hoverHandler: (data): void => {
454        if (data) {
455          this.fileStatisticsAnalysisTableThread!.setCurrentHover(data);
456        } else {
457          this.fileStatisticsAnalysisTableThread!.mouseOut();
458        }
459      },
460      interactions: [
461        {
462          type: 'element-active',
463        },
464      ],
465    };
466    let title = '';
467    if (this.fsProcessName.length > 0) {
468      title += this.fsProcessName + ' / ';
469    }
470    if (this.typeName.length > 0) {
471      title += this.typeName;
472    }
473    this.fileSystemTitleEl!.textContent = title;
474    this.tabName!.textContent = 'Statistic By Thread AllDuration';
475    this.fileStatisticsAnalysisThreadData.unshift(this.threadStatisticsData);
476    this.fileStatisticsAnalysisTableThread!.recycleDataSource = this.fileStatisticsAnalysisThreadData;
477    // @ts-ignore
478    this.fileStatisticsAnalysisThreadData.shift(this.threadStatisticsData);
479    this.currentLevelData = this.fileStatisticsAnalysisThreadData;
480    this.fileStatisticsAnalysisTableThread?.reMeauseHeight();
481  }
482
483  private getFsTip() {
484    return (obj: { obj: { tableName: any; durFormat: any; percent: any } }): string => {
485      return `<div>
486                    <div>ThreadName:${obj.obj.tableName}</div>
487                    <div>Duration:${obj.obj.durFormat}</div>
488                    <div>Percent:${obj.obj.percent}%</div>
489                </div>
490                    `;
491    };
492  }
493
494  private fileThreadLevelClickEvent(it: any): void {
495    this.reset(this.fileStatisticsAnalysisTableSo!, true);
496    this.getFilesystemSo(it);
497    // @ts-ignore
498    this.fileStatisticsAnalysisThreadName = it.tableName;
499    let title = '';
500    if (this.fsProcessName.length > 0) {
501      title += this.fsProcessName + ' / ';
502    }
503    if (this.typeName.length > 0) {
504      title += this.typeName + ' / ';
505    }
506    if (this.fileStatisticsAnalysisThreadName.length > 0) {
507      title += this.fileStatisticsAnalysisThreadName;
508    }
509    this.fileSystemTitleEl!.textContent = title;
510    this.fsPieChart?.hideTip();
511  }
512
513  private libraryPieChart(): void {
514    // @ts-ignore
515    this.sumDur = this.libStatisticsData.allDuration;
516    this.setFsPieChartConfig();
517    let fileSystemTitle = '';
518    if (this.fsProcessName.length > 0) {
519      fileSystemTitle += this.fsProcessName + ' / ';
520    }
521    if (this.typeName.length > 0) {
522      if (this.hideThreadCheckBox?.checked) {
523        fileSystemTitle += this.typeName;
524      } else {
525        fileSystemTitle += this.typeName + ' / ';
526      }
527    }
528    if (this.fileStatisticsAnalysisThreadName.length > 0) {
529      fileSystemTitle += this.fileStatisticsAnalysisThreadName;
530    }
531    this.fileSystemTitleEl!.textContent = fileSystemTitle;
532    this.tabName!.textContent = 'Statistic By Library AllDuration';
533    this.fileStatisticsAnalysisSoData.unshift(this.libStatisticsData);
534    this.fileStatisticsAnalysisTableSo!.recycleDataSource = this.fileStatisticsAnalysisSoData;
535    // @ts-ignore
536    this.fileStatisticsAnalysisSoData.shift(this.libStatisticsData);
537    this.currentLevelData = this.fileStatisticsAnalysisSoData;
538    this.fileStatisticsAnalysisTableSo?.reMeauseHeight();
539  }
540
541  private setFsPieChartConfig(): void {
542    this.fsPieChart!.config = {
543      appendPadding: 0,
544      data: this.getFsPieChartData(this.fileStatisticsAnalysisSoData),
545      angleField: 'duration',
546      colorField: 'tableName',
547      radius: 1,
548      label: {
549        type: 'outer',
550      },
551      tip: (fileSysObj): string => {
552        return `<div>
553                    <div>Library:${fileSysObj.obj.tableName}</div>
554                    <div>Duration:${fileSysObj.obj.durFormat}</div>
555                    <div>Percent:${fileSysObj.obj.percent}%</div>
556                </div>
557                    `;
558      },
559      angleClick: (fileSysBean): void => {
560        // @ts-ignore
561        if (fileSysBean.tableName != 'other') {
562          this.fileSoLevelClickEvent(fileSysBean);
563        }
564      },
565      hoverHandler: (data): void => {
566        if (data) {
567          this.fileStatisticsAnalysisTableSo!.setCurrentHover(data);
568        } else {
569          this.fileStatisticsAnalysisTableSo!.mouseOut();
570        }
571      },
572      interactions: [
573        {
574          type: 'element-active',
575        },
576      ],
577    };
578  }
579
580  private fileSoLevelClickEvent(it: any): void {
581    this.reset(this.fileStatisticsAnalysisTableFunction!, true);
582    this.fileStatisticsAnalysisProgressEL!.loading = true;
583    this.shadowRoot!.querySelector<HTMLDivElement>('.fs-subheading')!.textContent = 'Statistic By Function AllDuration';
584    if (!this.fileStatisticsAnalysisProcessData || this.fileStatisticsAnalysisProcessData.length === 0) {
585      return;
586    }
587    let allDur = 0;
588    let symbolMap = new Map<number, Array<any>>();
589    allDur = this.symbolMapProcessData(it, allDur, symbolMap);
590    this.updateFunctionData(symbolMap, it, allDur);
591    this.getFilesystemFunction(allDur);
592    let title = '';
593    if (this.fsProcessName.length > 0) {
594      title += this.fsProcessName + ' / ';
595    }
596    if (this.typeName.length > 0) {
597      title += this.typeName + ' / ';
598    }
599    if (this.fileStatisticsAnalysisThreadName.length > 0 && !this.hideThreadCheckBox!.checked) {
600      title += this.fileStatisticsAnalysisThreadName + ' / ';
601    }
602    if (it.tableName.length > 0) {
603      title += it.tableName;
604    }
605    this.fileSystemTitleEl!.textContent = title;
606    this.fsPieChart?.hideTip();
607  }
608
609  private getFilesystemFunction(allDur: number): void {
610    this.fileStatisticsAnalysisFunctionData.sort((a, b) => b.duration - a.duration);
611    this.functionStatisticsData = this.totalDurationData(allDur);
612    this.currentLevel = 4;
613    this.fileStatisticsAnalysisProgressEL!.loading = false;
614    // @ts-ignore
615    this.sumDur = this.functionStatisticsData.allDuration;
616    this.fsPieChart!.config = {
617      appendPadding: 0,
618      data: this.getFsPieChartData(this.fileStatisticsAnalysisFunctionData),
619      angleField: 'duration',
620      colorField: 'tableName',
621      radius: 1,
622      label: {
623        type: 'outer',
624      },
625      tip: (fsaObj): string => {
626        return `<div>
627                    <div>Function:${fsaObj.obj.tableName}</div>
628                    <div>Duration:${fsaObj.obj.durFormat}</div>
629                    <div>percent:${fsaObj.obj.percent}</div>
630                </div>
631                `;
632      },
633      hoverHandler: (data): void => {
634        if (data) {
635          this.fileStatisticsAnalysisTableFunction!.setCurrentHover(data);
636        } else {
637          this.fileStatisticsAnalysisTableFunction!.mouseOut();
638        }
639      },
640      interactions: [
641        {
642          type: 'element-active',
643        },
644      ],
645    };
646    this.fileStatisticsAnalysisFunctionData.unshift(this.functionStatisticsData);
647    this.fileStatisticsAnalysisTableFunction!.recycleDataSource = this.fileStatisticsAnalysisFunctionData;
648    this.fileStatisticsAnalysisTableFunction?.reMeauseHeight();
649    // @ts-ignore
650    this.fileStatisticsAnalysisFunctionData.shift(this.functionStatisticsData);
651    this.currentLevelData = this.fileStatisticsAnalysisFunctionData;
652  }
653
654  private sortByColumn(): void {
655    let fsaCurrentTable: LitTable | null | undefined;
656    switch (this.currentLevel) {
657      case 0:
658        fsaCurrentTable = this.fileStatisticsAnalysisTableProcess;
659        break;
660      case 1:
661        fsaCurrentTable = this.fileStatisticsAnalysisTableType;
662        break;
663      case 2:
664        fsaCurrentTable = this.fileStatisticsAnalysisTableThread;
665        break;
666      case 3:
667        fsaCurrentTable = this.fileStatisticsAnalysisTableSo;
668        break;
669      case 4:
670        fsaCurrentTable = this.fileStatisticsAnalysisTableFunction;
671        break;
672    }
673    if (!fsaCurrentTable) {
674      return;
675    }
676    if (this.fsSortType === 0) {
677      this.sortAndRefreshTable(fsaCurrentTable);
678    } else {
679      this.sortAndRefreshTableByColumn(fsaCurrentTable);
680    }
681  }
682
683  private sortAndRefreshTableByColumn(fsaCurrentTable: LitTable): void {
684    let fsaArray = [...this.currentLevelData];
685    if (this.fsSortColumn === 'tableName') {
686      this.sortTableNameCase(fsaCurrentTable, fsaArray);
687    } else if (this.fsSortColumn === 'durFormat' || this.fsSortColumn === 'percent') {
688      fsaCurrentTable!.recycleDataSource = fsaArray.sort((a, b) => {
689        return this.fsSortType === 1 ? a.duration - b.duration : b.duration - a.duration;
690      });
691    }
692    switch (this.currentLevel) {
693      case 0:
694        fsaArray.unshift(this.processStatisticsData);
695        break;
696      case 1:
697        fsaArray.unshift(this.typeStatisticsData);
698        break;
699      case 2:
700        fsaArray.unshift(this.threadStatisticsData);
701        break;
702      case 3:
703        fsaArray.unshift(this.libStatisticsData);
704        break;
705      case 4:
706        fsaArray.unshift(this.functionStatisticsData);
707        break;
708    }
709    fsaCurrentTable!.recycleDataSource = fsaArray;
710  }
711
712  private sortAndRefreshTable(fsaCurrentTable: LitTable): void {
713    let fsaArr = [...this.currentLevelData];
714    switch (this.currentLevel) {
715      case 0:
716        fsaArr.unshift(this.processStatisticsData);
717        break;
718      case 1:
719        fsaArr.unshift(this.typeStatisticsData);
720        break;
721      case 2:
722        fsaArr.unshift(this.threadStatisticsData);
723        break;
724      case 3:
725        fsaArr.unshift(this.libStatisticsData);
726        break;
727      case 4:
728        fsaArr.unshift(this.functionStatisticsData);
729        break;
730    }
731    fsaCurrentTable!.recycleDataSource = fsaArr;
732  }
733
734  private sortTableNameCase(fsaCurrentTable: LitTable, fsaArray: any[]) {
735    fsaCurrentTable!.recycleDataSource = fsaArray.sort((firstElement, secondElement) => {
736      if (this.fsSortType === 1) {
737        if (firstElement.tableName > secondElement.tableName) {
738          return 1;
739        } else if (firstElement.tableName === secondElement.tableName) {
740          return 0;
741        } else {
742          return -1;
743        }
744      } else {
745        if (secondElement.tableName > firstElement.tableName) {
746          return 1;
747        } else if (firstElement.tableName === secondElement.tableName) {
748          return 0;
749        } else {
750          return -1;
751        }
752      }
753    });
754  }
755
756  private getFilesystemProcess(result: Array<any>): void {
757    this.fileStatisticsAnalysisProcessData = JSON.parse(JSON.stringify(result));
758    if (!this.fileStatisticsAnalysisProcessData || this.fileStatisticsAnalysisProcessData.length === 0) {
759      this.fileStatisticsAnalysisPidData = [];
760      this.processStatisticsData = [];
761      this.processPieChart();
762      return;
763    }
764    let allDur = 0;
765    let pidMap = new Map<string, Array<number | string>>();
766    for (let itemData of result) {
767      allDur += itemData.dur;
768      if (pidMap.has(itemData.pid)) {
769        pidMap.get(itemData.pid)?.push(itemData);
770      } else {
771        let itemArray = new Array<number | string>();
772        itemArray.push(itemData);
773        pidMap.set(itemData.pid, itemArray);
774      }
775    }
776    this.fileStatisticsAnalysisPidData = [];
777    pidMap.forEach((value: Array<any>, key: string) => {
778      let analysisPidDataDur = 0;
779      let pName = '';
780      for (let fileSysStatPidItem of value) {
781        if (fileSysStatPidItem.processName && fileSysStatPidItem.processName.length > 0) {
782          if (!fileSysStatPidItem.processName.endsWith(`(${fileSysStatPidItem.pid})`)) {
783            fileSysStatPidItem.processName = `${fileSysStatPidItem.processName}(${fileSysStatPidItem.pid})`;
784          }
785        } else {
786          fileSysStatPidItem.processName = `Process(${fileSysStatPidItem.pid})`;
787        }
788        pName = fileSysStatPidItem.processName;
789        analysisPidDataDur += fileSysStatPidItem.dur;
790      }
791      this.fileStatisticsAnalysisPidData.push({
792        tableName: pName,
793        pid: key,
794        percent: ((analysisPidDataDur / allDur) * 100).toFixed(2),
795        durFormat: Utils.getProbablyTime(analysisPidDataDur),
796        duration: analysisPidDataDur,
797      });
798    });
799    this.fileStatisticsAnalysisPidData.sort((a, b) => b.duration - a.duration);
800    this.processStatisticsData = this.totalDurationData(allDur);
801    this.currentLevel = 0;
802    this.fileStatisticsAnalysisProgressEL!.loading = false;
803    this.processPieChart();
804  }
805
806  private getFilesystemType(fileSysStatTypeItem: any): void {
807    this.fileStatisticsAnalysisProgressEL!.loading = true;
808    let typeMap = new Map<number, Array<number | string>>();
809    let allDur = 0;
810    if (!this.fileStatisticsAnalysisProcessData || this.fileStatisticsAnalysisProcessData.length == 0) {
811      return;
812    }
813    for (let fsItem of this.fileStatisticsAnalysisProcessData) {
814      if (fileSysStatTypeItem && fsItem.pid !== fileSysStatTypeItem.pid && !this.hideProcessCheckBox?.checked) {
815        continue;
816      }
817      allDur += fsItem.dur;
818      if (typeMap.has(fsItem.type)) {
819        typeMap.get(fsItem.type)?.push(fsItem);
820      } else {
821        let itemArray = new Array<number | string>();
822        itemArray.push(fsItem);
823        typeMap.set(fsItem.type, itemArray);
824      }
825    }
826    this.fileStatisticsAnalysisTypeData = [];
827    typeMap.forEach((value: Array<any>, key: number) => {
828      let dur = 0;
829      for (let item of value) {
830        dur += item.dur;
831      }
832      const typeData = {
833        tableName: this.typeIdToString(key),
834        pid: fileSysStatTypeItem === null ? value[0].pid : fileSysStatTypeItem.pid,
835        type: key,
836        percent: ((dur / allDur) * 100).toFixed(2),
837        durFormat: Utils.getProbablyTime(dur),
838        duration: dur,
839      };
840      this.fileStatisticsAnalysisTypeData.push(typeData);
841    });
842    this.fileStatisticsAnalysisTypeData.sort((a, b) => b.duration - a.duration);
843    this.typeStatisticsData = this.totalDurationData(allDur);
844    this.currentLevel = 1;
845    this.typePieChart();
846    this.fileStatisticsAnalysisProgressEL!.loading = false;
847  }
848
849  private getFilesystemThread(fileSysStatThreadItem: any): void {
850    this.fileStatisticsAnalysisProgressEL!.loading = true;
851    let threadMap = new Map<string, Array<number | string>>();
852    let pid = fileSysStatThreadItem.pid;
853    let type = fileSysStatThreadItem.type;
854    let allDur = 0;
855    if (!this.fileStatisticsAnalysisProcessData || this.fileStatisticsAnalysisProcessData.length === 0) {
856      return;
857    }
858    for (let fspItem of this.fileStatisticsAnalysisProcessData) {
859      if (
860        (!this.hideProcessCheckBox?.checked && fspItem.pid !== pid) ||
861        fspItem.type !== type ||
862        (fspItem.type !== type && this.hideProcessCheckBox?.checked)
863      ) {
864        continue;
865      }
866      allDur += fspItem.dur;
867      if (threadMap.has(fspItem.tid)) {
868        threadMap.get(fspItem.tid)?.push(fspItem);
869      } else {
870        let itemArray = new Array<number | string>();
871        itemArray.push(fspItem);
872        threadMap.set(fspItem.tid, itemArray);
873      }
874    }
875    this.updateThreadData(threadMap, fileSysStatThreadItem, allDur);
876    this.fileStatisticsAnalysisThreadData.sort((a, b) => b.duration - a.duration);
877    this.threadStatisticsData = this.totalDurationData(allDur);
878    this.currentLevel = 2;
879    this.fileStatisticsAnalysisProgressEL!.loading = false;
880    this.threadPieChart();
881  }
882
883  private updateThreadData(threadMap: Map<string, Array<number | string>>, fileSysStatThreadItem: any, allDur: number): void {
884    this.fileStatisticsAnalysisThreadData = [];
885    threadMap.forEach((value: Array<any>, key: string) => {
886      let dur = 0;
887      let tName = '';
888      for (let fileSysStatThreadItem of value) {
889        dur += fileSysStatThreadItem.dur;
890        tName = fileSysStatThreadItem.threadName =
891          fileSysStatThreadItem.threadName === null || fileSysStatThreadItem.threadName === undefined
892            ? `Thread(${fileSysStatThreadItem.tid})`
893            : `${fileSysStatThreadItem.threadName}`;
894      }
895      const threadData = {
896        tableName: tName,
897        pid: fileSysStatThreadItem.pid,
898        type: fileSysStatThreadItem.type,
899        tid: key,
900        percent: ((dur / allDur) * 100).toFixed(2),
901        durFormat: Utils.getProbablyTime(dur),
902        duration: dur,
903      };
904      this.fileStatisticsAnalysisThreadData.push(threadData);
905    });
906  }
907
908  private getFilesystemSo(item: any): void {
909    this.fileStatisticsAnalysisProgressEL!.loading = true;
910    let allDur = 0;
911    let libMap = new Map<number, Array<number | string>>();
912    if (!this.fileStatisticsAnalysisProcessData || this.fileStatisticsAnalysisProcessData.length === 0) {
913      return;
914    }
915    allDur = this.libMapProcessData(item, allDur, libMap);
916    this.updateSoData(libMap, item, allDur);
917    this.libStatisticsData = this.totalDurationData(allDur);
918    this.currentLevel = 3;
919    this.fileStatisticsAnalysisProgressEL!.loading = false;
920    this.libraryPieChart();
921  }
922
923  private libMapProcessData(item: any, allDur: number, libMap: Map<number, Array<number | string>>): number {
924    for (let itemData of this.fileStatisticsAnalysisProcessData) {
925      if (this.libIsAccumulationData(item, itemData)) {
926        continue;
927      }
928      allDur += itemData.dur;
929      if (libMap.has(itemData.libId)) {
930        libMap.get(itemData.libId)?.push(itemData);
931      } else {
932        let dataArray = new Array<number | string>();
933        dataArray.push(itemData);
934        libMap.set(itemData.libId, dataArray);
935      }
936    }
937    return allDur;
938  }
939
940  private libIsAccumulationData(item: any, itemData: any): boolean {
941    if (!item) {
942      return false;
943    }
944    if (!this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
945      return (itemData.pid !== item.pid || itemData.tid !== item.tid || itemData.type !== item.type);
946    }
947    if (!this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
948      return (itemData.pid !== item.pid || itemData.type !== item.type);
949    }
950    if (this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
951      return (itemData.tid !== item.tid || itemData.type !== item.type);
952    }
953    if (this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
954      return (itemData.type !== item.type);
955    }
956    return false;
957  }
958
959  private updateSoData(libMap: Map<number, Array<number | string>>, item: any, allDur: number): void {
960    this.fileStatisticsAnalysisSoData = [];
961    libMap.forEach((value: any[], key: number) => {
962      let dur = 0;
963      let soName = '';
964      for (let item of value) {
965        dur += item.dur;
966        if (key === null) {
967          item.libName = 'unknown';
968        }
969        soName = item.libName;
970      }
971      let libPath = soName?.split('/');
972      if (libPath) {
973        soName = libPath[libPath.length - 1];
974      }
975      const soData = {
976        tableName: soName,
977        pid: item === null ? value[0].pid : item.pid,
978        type: item === null ? value[0].type : item.type,
979        tid: item === null ? value[0].tid : item.tid,
980        libId: key,
981        percent: ((dur / allDur) * 100).toFixed(2),
982        durFormat: Utils.getProbablyTime(dur),
983        duration: dur,
984      };
985      this.fileStatisticsAnalysisSoData.push(soData);
986    });
987    this.fileStatisticsAnalysisSoData.sort((a, b) => b.duration - a.duration);
988  }
989
990  private symbolMapProcessData(item: any, allDur: number, symbolMap: Map<number, Array<any>>): number {
991    let tid = item.tid;
992    let pid = item.pid;
993    let type = item.type;
994    let libId = item.libId;
995    for (let fsProcessData of this.fileStatisticsAnalysisProcessData) {
996      if (this.symbolIsAccumulationData(fsProcessData, tid, pid, type, libId)) {
997        continue;
998      }
999      allDur += fsProcessData.dur;
1000      if (symbolMap.has(fsProcessData.symbolId)) {
1001        symbolMap.get(fsProcessData.symbolId)?.push(fsProcessData);
1002      } else {
1003        let dataArray = new Array<number | string>();
1004        dataArray.push(fsProcessData);
1005        symbolMap.set(fsProcessData.symbolId, dataArray);
1006      }
1007    }
1008    return allDur;
1009  }
1010
1011  private symbolIsAccumulationData(fsProcessData: any, tid: number, pid: number, type: string, libId: number): boolean {
1012    if (!fsProcessData) {
1013      return false;
1014    }
1015    if (!this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
1016      return (fsProcessData.pid !== pid || fsProcessData.tid !== tid || fsProcessData.type !== type || fsProcessData.libId !== libId);
1017    }
1018    if (!this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
1019      return (fsProcessData.pid !== pid || fsProcessData.type !== type || fsProcessData.libId !== libId);
1020    }
1021    if (this.hideProcessCheckBox?.checked && !this.hideThreadCheckBox?.checked) {
1022      return (fsProcessData.tid !== tid || fsProcessData.type !== type || fsProcessData.libId !== libId);
1023    }
1024    if (this.hideProcessCheckBox?.checked && this.hideThreadCheckBox?.checked) {
1025      return (fsProcessData.type !== type || fsProcessData.libId !== libId);
1026    }
1027    return false;
1028  }
1029
1030  private updateFunctionData(symbolMap: Map<number, Array<any>>, item: any, allDur: number): void {
1031    this.fileStatisticsAnalysisFunctionData = [];
1032    symbolMap.forEach((symbolItems, key) => {
1033      let dur = 0;
1034      let fsSymbolName = '';
1035      for (let symbolItem of symbolItems) {
1036        fsSymbolName = symbolItem.symbolName;
1037        dur += symbolItem.dur;
1038      }
1039      let symbolPath = fsSymbolName?.split('/');
1040      if (symbolPath) {
1041        fsSymbolName = symbolPath[symbolPath.length - 1];
1042      }
1043      const symbolData = {
1044        pid: item.pid,
1045        type: item.type,
1046        tid: item.tid,
1047        libId: item.libId,
1048        symbolId: key,
1049        percent: ((dur / allDur) * 100).toFixed(2),
1050        tableName: fsSymbolName,
1051        durFormat: Utils.getProbablyTime(dur),
1052        duration: dur,
1053      };
1054      this.fileStatisticsAnalysisFunctionData.push(symbolData);
1055    });
1056  }
1057
1058  private typeIdToString(transformType: number): string {
1059    let fsReleaseType: string;
1060    if (transformType === 0) {
1061      fsReleaseType = 'OPEN';
1062    } else if (transformType === 2) {
1063      fsReleaseType = 'READ';
1064    } else if (transformType === 3) {
1065      fsReleaseType = 'WRITE';
1066    } else if (transformType === 1) {
1067      fsReleaseType = 'CLOSE';
1068    }
1069    // @ts-ignore
1070    return fsReleaseType;
1071  }
1072
1073  private totalDurationData(durationTS: number): {
1074    durFormat: string;
1075    percent: string;
1076    tableName: string;
1077    duration: number;
1078  } {
1079    return {
1080      durFormat: Utils.getProbablyTime(durationTS),
1081      percent: ((durationTS / durationTS) * 100).toFixed(2),
1082      tableName: '',
1083      duration: 0,
1084    };
1085  }
1086
1087  private getFsPieChartData(fsPieChartData: any[]): unknown[] {
1088    if (fsPieChartData.length > 20) {
1089      let fsPieChartArr: string[] = [];
1090      let other: any = {
1091        tableName: 'other',
1092        duration: 0,
1093        percent: 0,
1094        durFormat: 0,
1095      };
1096      for (let pieDataIndex = 0; pieDataIndex < fsPieChartData.length; pieDataIndex++) {
1097        if (pieDataIndex < 19) {
1098          fsPieChartArr.push(fsPieChartData[pieDataIndex]);
1099        } else {
1100          other.duration += fsPieChartData[pieDataIndex].duration;
1101          other.durFormat = Utils.getProbablyTime(other.duration);
1102          other.percent = ((other.duration / this.sumDur) * 100).toFixed(2);
1103        }
1104      }
1105      fsPieChartArr.push(other);
1106      return fsPieChartArr;
1107    }
1108    return fsPieChartData;
1109  }
1110
1111  private getDataByWorker(args: any[], handler: Function): void {
1112    procedurePool.submitWithName(
1113      'logic0',
1114      'fileSystem-action',
1115      {args, callType: 'fileSystem', isAnalysis: true},
1116      undefined,
1117      (results: any) => {
1118        handler(results);
1119        this.fileStatisticsAnalysisProgressEL!.loading = false;
1120      }
1121    );
1122  }
1123
1124  public connectedCallback(): void {
1125    new ResizeObserver(() => {
1126      if (this.parentElement?.clientHeight != 0) {
1127        this.fileStatisticsAnalysisTableProcess!.style.height = this.parentElement!.clientHeight - 50 + 'px';
1128        this.fileStatisticsAnalysisTableProcess?.reMeauseHeight();
1129        this.fileStatisticsAnalysisTableThread!.style.height = this.parentElement!.clientHeight - 50 + 'px';
1130        this.fileStatisticsAnalysisTableThread?.reMeauseHeight();
1131        this.fileStatisticsAnalysisTableSo!.style.height = this.parentElement!.clientHeight - 50 + 'px';
1132        this.fileStatisticsAnalysisTableSo?.reMeauseHeight();
1133        this.fileStatisticsAnalysisTableFunction!.style.height = this.parentElement!.clientHeight - 50 + 'px';
1134        this.fileStatisticsAnalysisTableFunction?.reMeauseHeight();
1135        this.fileStatisticsAnalysisTableType!.style.height = this.parentElement!.clientHeight - 50 + 'px';
1136        this.fileStatisticsAnalysisTableType?.reMeauseHeight();
1137        if (this.parentElement!.clientHeight >= 0 && this.parentElement!.clientHeight <= 31) {
1138          this.fileSystemFilterEl!.style.display = 'none';
1139        } else {
1140          this.fileSystemFilterEl!.style.display = 'flex';
1141        }
1142      }
1143    }).observe(this.parentElement!);
1144  }
1145
1146  initHtml(): string {
1147    return TabPaneFilesystemStatisticsAnalysisHtml;
1148  }
1149}
1150