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