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