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