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.js'; 17import { LitTable } from '../../../../../base-ui/table/lit-table.js'; 18import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; 19import '../../../../../base-ui/chart/pie/LitChartPie.js'; 20import { SelectionParam } from '../../../../bean/BoxSelection.js'; 21import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; 22import { Utils } from '../../base/Utils.js'; 23import { procedurePool } from '../../../../database/Procedure.js'; 24 25@element('tabpane-tb-vm-statistics') 26export class TabPaneIOTierStatisticsAnalysis extends BaseElement { 27 private iOTierStatisticsAnalysisPie: LitChartPie | null | undefined; 28 private currentSelection: SelectionParam | null | undefined; 29 private processData: any; 30 private pidData!: any[]; 31 private threadData!: any[]; 32 private soData!: any[]; 33 private functionData!: any[]; 34 private typeData!: any[]; 35 private ioTierTableProcess: LitTable | null | undefined; 36 private ioTierTableThread: LitTable | null | undefined; 37 private tableType: LitTable | null | undefined; 38 private ioTierTableSo: LitTable | null | undefined; 39 private tableFunction: LitTable | null | undefined; 40 private sumDur: number = 0; 41 private range: HTMLLabelElement | null | undefined; 42 private iOTierStatisticsAnalysisBack: HTMLDivElement | null | undefined; 43 private tabName: HTMLDivElement | null | undefined; 44 private progressEL: LitProgressBar | null | undefined; 45 private processName: string = ''; 46 private threadName: string = ''; 47 private sortColumn: string = ''; 48 private sortType: number = 0; 49 private typeName: string = ''; 50 private currentLevel = -1; 51 private currentLevelData!: Array<any>; 52 private processStatisticsData!: {}; 53 private typeStatisticsData!: {}; 54 private threadStatisticsData!: {}; 55 private libStatisticsData!: {}; 56 private functionStatisticsData!: {}; 57 set data(ioTierStatisticsAnalysisSelection: SelectionParam) { 58 if (ioTierStatisticsAnalysisSelection === this.currentSelection) { 59 this.pidData.unshift(this.processStatisticsData); 60 this.ioTierTableProcess!.recycleDataSource = this.pidData; 61 // @ts-ignore 62 this.pidData.shift(this.processStatisticsData); 63 return; 64 } 65 this.clearData(); 66 this.currentSelection = ioTierStatisticsAnalysisSelection; 67 this.ioTierTableProcess!.style.display = 'grid'; 68 this.tableType!.style.display = 'none'; 69 this.ioTierTableThread!.style.display = 'none'; 70 this.ioTierTableSo!.style.display = 'none'; 71 this.tableFunction!.style.display = 'none'; 72 this.iOTierStatisticsAnalysisBack!.style.visibility = 'hidden'; 73 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = ''; 74 this.tabName!.textContent = ''; 75 this.range!.textContent = 76 'Selected range: ' + 77 parseFloat( 78 ((ioTierStatisticsAnalysisSelection.rightNs - ioTierStatisticsAnalysisSelection.leftNs) / 1000000.0).toFixed(5) 79 ) + 80 ' ms'; 81 this.progressEL!.loading = true; 82 this.getIoTierDataByWorker( 83 [ 84 { 85 funcName: 'setSearchValue', 86 funcArgs: [''], 87 }, 88 { 89 funcName: 'getCurrentDataFromDb', 90 funcArgs: [{ queryFuncName: 'io', ...ioTierStatisticsAnalysisSelection }], 91 }, 92 ], 93 (results: any[]) => { 94 this.getIOTierProcess(results); 95 } 96 ); 97 } 98 initElements(): void { 99 this.range = this.shadowRoot?.querySelector('#time-range'); 100 this.iOTierStatisticsAnalysisPie = this.shadowRoot!.querySelector<LitChartPie>('#io-tier-chart-pie'); 101 this.ioTierTableProcess = this.shadowRoot!.querySelector<LitTable>('#tb-process-usage'); 102 this.ioTierTableThread = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage'); 103 this.ioTierTableSo = this.shadowRoot!.querySelector<LitTable>('#tb-so-usage'); 104 this.tableFunction = this.shadowRoot!.querySelector<LitTable>('#tb-function-usage'); 105 this.tableType = this.shadowRoot!.querySelector<LitTable>('#tb-type-usage'); 106 this.iOTierStatisticsAnalysisBack = this.shadowRoot!.querySelector<HTMLDivElement>('.io-tier-go-back'); 107 this.tabName = this.shadowRoot!.querySelector<HTMLDivElement>('.io-tier-subheading'); 108 this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; 109 this.goBack(); 110 } 111 clearData(): void { 112 this.iOTierStatisticsAnalysisPie!.dataSource = []; 113 this.ioTierTableProcess!.recycleDataSource = []; 114 this.tableType!.recycleDataSource = []; 115 this.ioTierTableThread!.recycleDataSource = []; 116 this.ioTierTableSo!.recycleDataSource = []; 117 this.tableFunction!.recycleDataSource = []; 118 } 119 goBack(): void { 120 this.iOTierStatisticsAnalysisBack!.addEventListener('click', () => { 121 if (this.tabName!.textContent === 'Statistic By type AllDuration') { 122 this.ioTierTableProcess!.style.display = 'grid'; 123 this.tableType!.style.display = 'none'; 124 this.iOTierStatisticsAnalysisBack!.style.visibility = 'hidden'; 125 this.tableType!.setAttribute('hideDownload', ''); 126 this.ioTierTableProcess?.removeAttribute('hideDownload'); 127 this.currentLevel = 0; 128 this.processPieChart(); 129 } else if (this.tabName!.textContent === 'Statistic By Thread AllDuration') { 130 this.tableType!.style.display = 'grid'; 131 this.ioTierTableThread!.style.display = 'none'; 132 this.ioTierTableThread!.setAttribute('hideDownload', ''); 133 this.tableType?.removeAttribute('hideDownload'); 134 this.currentLevel = 1; 135 this.typePieChart(); 136 } else if (this.tabName!.textContent === 'Statistic By Library AllDuration') { 137 this.ioTierTableThread!.style.display = 'grid'; 138 this.ioTierTableSo!.style.display = 'none'; 139 this.ioTierTableSo!.setAttribute('hideDownload', ''); 140 this.ioTierTableThread?.removeAttribute('hideDownload'); 141 this.currentLevel = 2; 142 this.threadPieChart(); 143 } else if (this.tabName!.textContent === 'Statistic By Function AllDuration') { 144 this.ioTierTableSo!.style.display = 'grid'; 145 this.tableFunction!.style.display = 'none'; 146 this.tableFunction!.setAttribute('hideDownload', ''); 147 this.ioTierTableSo?.removeAttribute('hideDownload'); 148 this.currentLevel = 3; 149 this.libraryPieChart(); 150 } 151 }); 152 } 153 processPieChart(): void { 154 // @ts-ignore 155 this.sumDur = this.processStatisticsData.allDuration; 156 this.iOTierStatisticsAnalysisPie!.config = { 157 appendPadding: 0, 158 data: this.getIOTierPieChartData(this.pidData), 159 angleField: 'duration', 160 colorField: 'tableName', 161 radius: 1, 162 label: { 163 type: 'outer', 164 }, 165 tip: this.getTip(), 166 angleClick: (ioTierPieItem): void => { 167 // @ts-ignore 168 if (ioTierPieItem.tableName != 'other') { 169 this.ioTierProcessLevelClickEvent(ioTierPieItem); 170 } 171 }, 172 hoverHandler: (ioTierPieData): void => { 173 if (ioTierPieData) { 174 this.ioTierTableProcess!.setCurrentHover(ioTierPieData); 175 } else { 176 this.ioTierTableProcess!.mouseOut(); 177 } 178 }, 179 interactions: [ 180 { 181 type: 'element-active', 182 }, 183 ], 184 }; 185 this.ioTierTableProcess!.addEventListener('row-hover', (event) => { 186 // @ts-ignore 187 let ioTierProcessData = event.detail; 188 if (ioTierProcessData.data) { 189 let processData = ioTierProcessData.data; 190 processData.isHover = true; 191 if (ioTierProcessData.callBack) { 192 ioTierProcessData.callBack(true); 193 } 194 } 195 this.iOTierStatisticsAnalysisPie?.showHover(); 196 this.iOTierStatisticsAnalysisPie?.hideTip(); 197 }); 198 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = ''; 199 this.tabName!.textContent = 'Statistic By Process AllDuration'; 200 this.pidData.unshift(this.processStatisticsData); 201 this.ioTierTableProcess!.recycleDataSource = this.pidData; 202 // @ts-ignore 203 this.pidData.shift(this.processStatisticsData); 204 this.currentLevelData = this.pidData; 205 this.ioTierTableProcess?.reMeauseHeight(); 206 this.ioTierTableProcess!.addEventListener('column-click', (evt) => { 207 // @ts-ignore 208 this.sortByColumn(evt.detail.key, evt.detail.sort); 209 }); 210 this.ioTierTableProcess!.addEventListener('row-click', (evt) => { 211 // @ts-ignore 212 let data = evt.detail.data; 213 if (data.tableName !== '' && data.duration !== 0) { 214 this.ioTierProcessLevelClickEvent(data); 215 } 216 }); 217 } 218 ioTierProcessLevelClickEvent(it: any): void { 219 this.clearData(); 220 this.iOTierStatisticsAnalysisBack!.style.visibility = 'visible'; 221 this.ioTierTableProcess!.style.display = 'none'; 222 this.tableType!.style.display = 'grid'; 223 this.ioTierTableProcess!.setAttribute('hideDownload', ''); 224 this.tableType?.removeAttribute('hideDownload'); 225 this.getIOTierType(it); 226 this.processName = it.tableName; 227 this.iOTierStatisticsAnalysisPie?.hideTip(); 228 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = this.processName; 229 } 230 typePieChart(): void { 231 this.iOTierStatisticsAnalysisPie!.config = { 232 appendPadding: 0, 233 data: this.typeData, 234 angleField: 'duration', 235 colorField: 'tableName', 236 radius: 1, 237 label: { 238 type: 'outer', 239 }, 240 tip: (obj): string => { 241 return this.getIoTierTip(obj); 242 }, 243 angleClick: (it): void => { 244 this.ioTierTypeLevelClickEvent(it); 245 }, 246 hoverHandler: (ioTierData): void => { 247 if (ioTierData) { 248 this.tableType!.setCurrentHover(ioTierData); 249 } else { 250 this.tableType!.mouseOut(); 251 } 252 }, 253 interactions: [ 254 { 255 type: 'element-active', 256 }, 257 ], 258 }; 259 this.tableType!.addEventListener('row-hover', (evt) => { 260 // @ts-ignore 261 let ioTypeData = evt.detail; 262 if (ioTypeData.data) { 263 let tableData = ioTypeData.data; 264 tableData.isHover = true; 265 if (ioTypeData.callBack) { 266 ioTypeData.callBack(true); 267 } 268 } 269 this.iOTierStatisticsAnalysisPie?.showHover(); 270 this.iOTierStatisticsAnalysisPie?.hideTip(); 271 }); 272 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = this.processName; 273 this.tabName!.textContent = 'Statistic By type AllDuration'; 274 this.typeData.unshift(this.typeStatisticsData); 275 this.tableType!.recycleDataSource = this.typeData; 276 // @ts-ignore 277 this.typeData.shift(this.typeStatisticsData); 278 this.currentLevelData = this.typeData; 279 this.tableType?.reMeauseHeight(); 280 this.tableType!.addEventListener('column-click', (evt) => { 281 // @ts-ignore 282 this.sortByColumn(evt.detail.key, evt.detail.sort); 283 }); 284 this.tableType!.addEventListener('row-click', (evt) => { 285 // @ts-ignore 286 let data = evt.detail.data; 287 if (data.tableName !== '' && data.duration !== 0) { 288 this.ioTierTypeLevelClickEvent(data); 289 } 290 }); 291 } 292 ioTierTypeLevelClickEvent(it: any): void { 293 this.clearData(); 294 this.tableType!.style.display = 'none'; 295 this.ioTierTableThread!.style.display = 'grid'; 296 this.tableType!.setAttribute('hideDownload', ''); 297 this.ioTierTableThread?.removeAttribute('hideDownload'); 298 this.getIOTierThread(it); 299 this.typeName = it.tableName; 300 this.iOTierStatisticsAnalysisPie?.hideTip(); 301 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = this.processName + ' / ' + this.typeName; 302 } 303 threadPieChart(): void { 304 // @ts-ignore 305 this.sumDur = this.threadStatisticsData.allDuration; 306 this.iOTierStatisticsAnalysisPie!.config = { 307 appendPadding: 0, 308 data: this.getIOTierPieChartData(this.threadData), 309 angleField: 'duration', 310 colorField: 'tableName', 311 radius: 1, 312 label: { 313 type: 'outer', 314 }, 315 tip: (obj): string => { 316 return this.getIoTierTip(obj); 317 }, 318 angleClick: (it): void => { 319 // @ts-ignore 320 if (it.tableName != 'other') { 321 this.ioTierThreadLevelClickEvent(it); 322 } 323 }, 324 hoverHandler: (data): void => { 325 if (data) { 326 this.ioTierTableThread!.setCurrentHover(data); 327 } else { 328 this.ioTierTableThread!.mouseOut(); 329 } 330 }, 331 interactions: [ 332 { 333 type: 'element-active', 334 }, 335 ], 336 }; 337 this.ioTierTableThread!.addEventListener('row-hover', (evt) => { 338 // @ts-ignore 339 let ioThreadData = evt.detail; 340 if (ioThreadData.data) { 341 let threadData = ioThreadData.data; 342 threadData.isHover = true; 343 if (ioThreadData.callBack) { 344 ioThreadData.callBack(true); 345 } 346 } 347 this.iOTierStatisticsAnalysisPie?.showHover(); 348 this.iOTierStatisticsAnalysisPie?.hideTip(); 349 }); 350 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = this.processName + ' / ' + this.typeName; 351 this.tabName!.textContent = 'Statistic By Thread AllDuration'; 352 this.threadData.unshift(this.threadStatisticsData); 353 this.ioTierTableThread!.recycleDataSource = this.threadData; 354 // @ts-ignore 355 this.threadData.shift(this.threadStatisticsData); 356 this.currentLevelData = this.threadData; 357 this.ioTierTableThread?.reMeauseHeight(); 358 this.ioTierTableThread!.addEventListener('column-click', (evt) => { 359 // @ts-ignore 360 this.sortByColumn(evt.detail.key, evt.detail.sort); 361 }); 362 this.ioTierTableThread!.addEventListener('row-click', (evt) => { 363 // @ts-ignore 364 let data = evt.detail.data; 365 if (data.tableName !== '' && data.duration !== 0) { 366 this.ioTierThreadLevelClickEvent(data); 367 } 368 }); 369 } 370 private getIoTierTip(obj: { obj: { tableName: any; durFormat: any; percent: any; }; }) { 371 return `<div> 372 <div>ThreadName:${ obj.obj.tableName }</div> 373 <div>Duration:${ obj.obj.durFormat }</div> 374 <div>Percent:${ obj.obj.percent }%</div> 375 </div> 376 `; 377 } 378 ioTierThreadLevelClickEvent(it: any): void { 379 this.clearData(); 380 this.iOTierStatisticsAnalysisBack!.style.visibility = 'visible'; 381 this.ioTierTableThread!.style.display = 'none'; 382 this.ioTierTableSo!.style.display = 'grid'; 383 this.ioTierTableThread!.setAttribute('hideDownload', ''); 384 this.ioTierTableSo?.removeAttribute('hideDownload'); 385 this.getIOTierSo(it); 386 this.threadName = it.tableName; 387 this.iOTierStatisticsAnalysisPie?.hideTip(); 388 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = 389 this.processName + ' / ' + this.typeName + ' / ' + this.threadName; 390 } 391 libraryPieChart(): void { 392 // @ts-ignore 393 this.sumDur = this.libStatisticsData.allDuration; 394 this.iOTierStatisticsAnalysisPie!.config = { 395 appendPadding: 0, 396 data: this.getIOTierPieChartData(this.soData), 397 angleField: 'duration', 398 colorField: 'tableName', 399 radius: 1, 400 label: { 401 type: 'outer', 402 }, 403 tip: (ioTierObj): string => { 404 return `<div> 405 <div>Library:${ ioTierObj.obj.tableName }</div> 406 <div>Duration:${ ioTierObj.obj.durFormat }</div> 407 <div>Percent:${ ioTierObj.obj.percent }%</div> 408 </div> 409 `; 410 }, 411 angleClick: (ioTierBean): void => { 412 // @ts-ignore 413 if (ioTierBean.tableName != 'other') { 414 this.ioTierSoLevelClickEvent(ioTierBean); 415 } 416 }, 417 hoverHandler: (data): void => { 418 if (data) { 419 this.ioTierTableSo!.setCurrentHover(data); 420 } else { 421 this.ioTierTableSo!.mouseOut(); 422 } 423 }, 424 interactions: [ 425 { 426 type: 'element-active', 427 }, 428 ], 429 }; 430 this.ioTierTableSo!.addEventListener('row-hover', (evt) => { 431 // @ts-ignore 432 let ioTierSoData = evt.detail; 433 if (ioTierSoData.data) { 434 let soData = ioTierSoData.data; 435 soData.isHover = true; 436 if (ioTierSoData.callBack) { 437 ioTierSoData.callBack(true); 438 } 439 } 440 this.iOTierStatisticsAnalysisPie?.showHover(); 441 this.iOTierStatisticsAnalysisPie?.hideTip(); 442 }); 443 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = 444 this.processName + ' / ' + this.typeName + ' / ' + this.threadName; 445 this.tabName!.textContent = 'Statistic By Library AllDuration'; 446 this.soData.unshift(this.libStatisticsData); 447 this.ioTierTableSo!.recycleDataSource = this.soData; 448 // @ts-ignore 449 this.soData.shift(this.libStatisticsData); 450 this.currentLevelData = this.soData; 451 this.ioTierTableSo?.reMeauseHeight(); 452 this.ioTierTableSo!.addEventListener('column-click', (evt) => { 453 // @ts-ignore 454 this.sortByColumn(evt.detail.key, evt.detail.sort); 455 }); 456 this.ioTierTableSo!.addEventListener('row-click', (evt) => { 457 // @ts-ignore 458 let data = evt.detail.data; 459 if (data.tableName !== '' && data.duration !== 0) { 460 this.ioTierSoLevelClickEvent(data); 461 } 462 }); 463 } 464 ioTierSoLevelClickEvent(it: any): void { 465 this.clearData(); 466 this.iOTierStatisticsAnalysisBack!.style.visibility = 'visible'; 467 this.ioTierTableSo!.style.display = 'none'; 468 this.tableFunction!.style.display = 'grid'; 469 this.ioTierTableSo!.setAttribute('hideDownload', ''); 470 this.tableFunction?.removeAttribute('hideDownload'); 471 this.getIOTierFunction(it); 472 this.iOTierStatisticsAnalysisPie?.hideTip(); 473 this.shadowRoot!.querySelector<HTMLDivElement>('.title')!.textContent = 474 this.processName + ' / ' + this.typeName + ' / ' + this.threadName + ' / ' + it.tableName; 475 } 476 sortByColumn(column: string, ioSort: number): void { 477 this.sortColumn = column; 478 this.sortType = ioSort; 479 let ioTierCurrentTable: LitTable | null | undefined; 480 switch (this.currentLevel) { 481 case 0: 482 ioTierCurrentTable = this.ioTierTableProcess; 483 break; 484 case 1: 485 ioTierCurrentTable = this.tableType; 486 break; 487 case 2: 488 ioTierCurrentTable = this.ioTierTableThread; 489 break; 490 case 3: 491 ioTierCurrentTable = this.ioTierTableSo; 492 break; 493 case 4: 494 ioTierCurrentTable = this.tableFunction; 495 break; 496 } 497 if (!ioTierCurrentTable) { 498 return; 499 } 500 if (ioSort === 0) { 501 let sortZeroIoArr = [...this.currentLevelData]; 502 switch (this.currentLevel) { 503 case 0: 504 sortZeroIoArr.unshift(this.processStatisticsData); 505 break; 506 case 1: 507 sortZeroIoArr.unshift(this.typeStatisticsData); 508 break; 509 case 2: 510 sortZeroIoArr.unshift(this.threadStatisticsData); 511 break; 512 case 3: 513 sortZeroIoArr.unshift(this.libStatisticsData); 514 break; 515 case 4: 516 sortZeroIoArr.unshift(this.functionStatisticsData); 517 break; 518 } 519 ioTierCurrentTable!.recycleDataSource = sortZeroIoArr; 520 } else { 521 let sortIoArr = [...this.currentLevelData]; 522 if (column === 'tableName') { 523 ioTierCurrentTable!.recycleDataSource = sortIoArr.sort((firstIOElement, secondIOElement) => { 524 if (ioSort === 1) { 525 if (firstIOElement.tableName > secondIOElement.tableName) { 526 return 1; 527 } else if (firstIOElement.tableName === secondIOElement.tableName) { 528 return 0; 529 } else { 530 return -1; 531 } 532 } else { 533 if (secondIOElement.tableName > firstIOElement.tableName) { 534 return 1; 535 } else if (firstIOElement.tableName === secondIOElement.tableName) { 536 return 0; 537 } else { 538 return -1; 539 } 540 } 541 }); 542 } else if (column === 'durFormat' || column === 'percent') { 543 ioTierCurrentTable!.recycleDataSource = sortIoArr.sort((a, b) => { 544 return ioSort === 1 ? a.duration - b.duration : b.duration - a.duration; 545 }); 546 } 547 switch (this.currentLevel) { 548 case 0: 549 sortIoArr.unshift(this.processStatisticsData); 550 break; 551 case 1: 552 sortIoArr.unshift(this.typeStatisticsData); 553 break; 554 case 2: 555 sortIoArr.unshift(this.threadStatisticsData); 556 break; 557 case 3: 558 sortIoArr.unshift(this.libStatisticsData); 559 break; 560 case 4: 561 sortIoArr.unshift(this.functionStatisticsData); 562 break; 563 } 564 ioTierCurrentTable!.recycleDataSource = sortIoArr; 565 } 566 } 567 getIOTierProcess(result: Array<any>): void { 568 this.processData = JSON.parse(JSON.stringify(result)); 569 if (!this.processData || this.processData.length === 0) { 570 this.pidData = []; 571 this.processStatisticsData = []; 572 this.processPieChart(); 573 return; 574 } 575 let allDur = 0; 576 let ioMap = new Map<string, Array<number | string>>(); 577 for (let itemData of result) { 578 allDur += itemData.dur; 579 if (ioMap.has(itemData.pid)) { 580 ioMap.get(itemData.pid)?.push(itemData); 581 } else { 582 let itemArray = new Array<number | string>(); 583 itemArray.push(itemData); 584 ioMap.set(itemData.pid, itemArray); 585 } 586 } 587 this.pidData = []; 588 ioMap.forEach((value: Array<any>, key: string) => { 589 let ioPidDataDur = 0; 590 let pName = ''; 591 for (let item of value) { 592 pName = item.processName = 593 item.processName === null || item.processName === undefined 594 ? `Process(${ item.pid })` 595 : `${ item.processName }(${ item.pid })`; 596 ioPidDataDur += item.dur; 597 } 598 this.pidData.push({ 599 tableName: pName, 600 pid: key, 601 percent: ((ioPidDataDur / allDur) * 100).toFixed(2), 602 durFormat: Utils.getProbablyTime(ioPidDataDur), 603 duration: ioPidDataDur, 604 }); 605 }); 606 this.pidData.sort((a, b) => b.duration - a.duration); 607 this.processStatisticsData = this.totalDurationData(allDur); 608 this.currentLevel = 0; 609 this.progressEL!.loading = false; 610 this.processPieChart(); 611 new ResizeObserver(() => { 612 if (this.parentElement?.clientHeight != 0) { 613 this.ioTierTableProcess!.style.height = this.parentElement!.clientHeight - 50 + 'px'; 614 this.ioTierTableProcess?.reMeauseHeight(); 615 this.ioTierTableThread!.style.height = this.parentElement!.clientHeight - 50 + 'px'; 616 this.ioTierTableThread?.reMeauseHeight(); 617 this.ioTierTableSo!.style.height = this.parentElement!.clientHeight - 50 + 'px'; 618 this.ioTierTableSo?.reMeauseHeight(); 619 this.tableFunction!.style.height = this.parentElement!.clientHeight - 50 + 'px'; 620 this.tableFunction?.reMeauseHeight(); 621 this.tableType!.style.height = this.parentElement!.clientHeight - 50 + 'px'; 622 this.tableType?.reMeauseHeight(); 623 } 624 }).observe(this.parentElement!); 625 } 626 getIOTierType(item: any): void { 627 this.progressEL!.loading = true; 628 let ioTypeMap = new Map<number, Array<number | string>>(); 629 let pid = item.pid; 630 let allDur = 0; 631 if (!this.processData || this.processData.length === 0) { 632 return; 633 } 634 for (let processItem of this.processData) { 635 if (processItem.pid !== pid) { 636 continue; 637 } 638 allDur += processItem.dur; 639 if (ioTypeMap.has(processItem.type)) { 640 ioTypeMap.get(processItem.type)?.push(processItem); 641 } else { 642 let itemArray = new Array<number | string>(); 643 itemArray.push(processItem); 644 ioTypeMap.set(processItem.type, itemArray); 645 } 646 } 647 this.typeData = []; 648 ioTypeMap.forEach((value: Array<any>, key: number) => { 649 let dur = 0; 650 for (let ioItem of value) { 651 dur += ioItem.dur; 652 } 653 const ioTypeData = { 654 tableName: this.typeIdToString(key), 655 pid: item.pid, 656 type: key, 657 percent: ((dur / allDur) * 100).toFixed(2), 658 durFormat: Utils.getProbablyTime(dur), 659 duration: dur, 660 }; 661 this.typeData.push(ioTypeData); 662 }); 663 this.typeData.sort((a, b) => b.duration - a.duration); 664 this.typeStatisticsData = this.totalDurationData(allDur); 665 this.currentLevel = 1; 666 this.typePieChart(); 667 this.progressEL!.loading = false; 668 } 669 getIOTierThread(item: any): void { 670 this.progressEL!.loading = true; 671 let threadMap = new Map<string, Array<number | string>>(); 672 let pid = item.pid; 673 let type = item.type; 674 let allDur = 0; 675 if (!this.processData || this.processData.length === 0) { 676 return; 677 } 678 for (let itemData of this.processData) { 679 if (itemData.pid !== pid || itemData.type !== type) { 680 continue; 681 } 682 allDur += itemData.dur; 683 if (threadMap.has(itemData.tid)) { 684 threadMap.get(itemData.tid)?.push(itemData); 685 } else { 686 let itemArray = new Array<number | string>(); 687 itemArray.push(itemData); 688 threadMap.set(itemData.tid, itemArray); 689 } 690 } 691 this.threadData = []; 692 threadMap.forEach((value: Array<any>, key: string) => { 693 let dur = 0; 694 let tName = ''; 695 for (let item of value) { 696 dur += item.dur; 697 tName = item.threadName = 698 item.threadName === null || item.threadName === undefined ? `Thread(${ item.tid })` : `${ item.threadName }`; 699 } 700 const threadData = { 701 tableName: tName, 702 pid: item.pid, 703 type: item.type, 704 tid: key, 705 percent: ((dur / allDur) * 100).toFixed(2), 706 durFormat: Utils.getProbablyTime(dur), 707 duration: dur, 708 }; 709 this.threadData.push(threadData); 710 }); 711 this.threadData.sort((a, b) => b.duration - a.duration); 712 this.threadStatisticsData = this.totalDurationData(allDur); 713 this.currentLevel = 2; 714 this.progressEL!.loading = false; 715 this.threadPieChart(); 716 } 717 getIOTierSo(item: any): void { 718 this.progressEL!.loading = true; 719 let tid = item.tid; 720 let pid = item.pid; 721 let type = item.type; 722 let allDur = 0; 723 let libMap = new Map<number, Array<number | string>>(); 724 if (!this.processData || this.processData.length === 0) { 725 return; 726 } 727 for (let processItemData of this.processData) { 728 if (processItemData.pid !== pid || processItemData.tid !== tid || processItemData.type !== type) { 729 continue; 730 } 731 allDur += processItemData.dur; 732 if (libMap.has(processItemData.libId)) { 733 libMap.get(processItemData.libId)?.push(processItemData); 734 } else { 735 let dataArray = new Array<number | string>(); 736 dataArray.push(processItemData); 737 libMap.set(processItemData.libId, dataArray); 738 } 739 } 740 this.soData = []; 741 libMap.forEach((value: any[], key: number) => { 742 let dur = 0; 743 let libName = ''; 744 for (let item of value) { 745 dur += item.dur; 746 if (key === null) { 747 item.libName = 'unknown'; 748 } 749 libName = item.libName; 750 } 751 let libPath = libName?.split('/'); 752 if (libPath) { 753 libName = libPath[libPath.length - 1]; 754 } 755 const soData = { 756 tableName: libName, 757 pid: item.pid, 758 type: item.type, 759 tid: item.tid, 760 libId: key, 761 percent: ((dur / allDur) * 100).toFixed(2), 762 durFormat: Utils.getProbablyTime(dur), 763 duration: dur, 764 }; 765 this.soData.push(soData); 766 }); 767 this.soData.sort((a, b) => b.duration - a.duration); 768 this.libStatisticsData = this.totalDurationData(allDur); 769 this.currentLevel = 3; 770 this.progressEL!.loading = false; 771 this.libraryPieChart(); 772 } 773 getIOTierFunction(item: any): void { 774 this.progressEL!.loading = true; 775 this.shadowRoot!.querySelector<HTMLDivElement>('.io-tier-subheading')!.textContent = 'Statistic By Function AllDuration'; 776 let tid = item.tid; 777 let pid = item.pid; 778 let type = item.type; 779 let libId = item.libId; 780 let allDur = 0; 781 let symbolMap = new Map<number, Array<any>>(); 782 if (!this.processData || this.processData.length === 0) { 783 return; 784 } 785 for (let processData of this.processData) { 786 if ( 787 processData.pid !== pid || 788 processData.tid !== tid || 789 processData.type !== type || 790 processData.libId !== libId 791 ) { 792 continue; 793 } 794 allDur += processData.dur; 795 if (symbolMap.has(processData.symbolId)) { 796 symbolMap.get(processData.symbolId)?.push(processData); 797 } else { 798 let dataArray = new Array<number | string>(); 799 dataArray.push(processData); 800 symbolMap.set(processData.symbolId, dataArray); 801 } 802 } 803 this.functionData = []; 804 symbolMap.forEach((symbolItems, key) => { 805 let dur = 0; 806 let funSymbolName = ''; 807 for (let symbolItem of symbolItems) { 808 funSymbolName = symbolItem.symbolName; 809 dur += symbolItem.dur; 810 } 811 let symbolPath = funSymbolName?.split('/'); 812 if (symbolPath) { 813 funSymbolName = symbolPath[symbolPath.length - 1]; 814 } 815 const symbolData = { 816 pid: item.pid, 817 tid: item.tid, 818 percent: ((dur / allDur) * 100).toFixed(2), 819 tableName: funSymbolName, 820 durFormat: Utils.getProbablyTime(dur), 821 duration: dur, 822 }; 823 this.functionData.push(symbolData); 824 }); 825 this.functionData.sort((a, b) => b.duration - a.duration); 826 this.functionStatisticsData = this.totalDurationData(allDur); 827 this.currentLevel = 4; 828 this.progressEL!.loading = false; 829 // @ts-ignore 830 this.sumDur = this.functionStatisticsData.allDuration; 831 this.iOTierStatisticsAnalysisPie!.config = { 832 appendPadding: 0, 833 data: this.getIOTierPieChartData(this.functionData), 834 angleField: 'duration', 835 colorField: 'tableName', 836 radius: 1, 837 label: { 838 type: 'outer', 839 }, 840 tip: this.getTip(), 841 hoverHandler: (data): void => { 842 if (data) { 843 this.tableFunction!.setCurrentHover(data); 844 } else { 845 this.tableFunction!.mouseOut(); 846 } 847 }, 848 interactions: [ 849 { 850 type: 'element-active', 851 }, 852 ], 853 }; 854 this.tableFunction!.addEventListener('row-hover', (evt) => { 855 // @ts-ignore 856 let ioFunctionData = evt.detail; 857 if (ioFunctionData.data) { 858 let funData = ioFunctionData.data; 859 funData.isHover = true; 860 if (ioFunctionData.callBack) { 861 ioFunctionData.callBack(true); 862 } 863 } 864 this.iOTierStatisticsAnalysisPie?.showHover(); 865 this.iOTierStatisticsAnalysisPie?.hideTip(); 866 }); 867 this.functionData.unshift(this.functionStatisticsData); 868 this.tableFunction!.recycleDataSource = this.functionData; 869 this.tableFunction?.reMeauseHeight(); 870 // @ts-ignore 871 this.functionData.shift(this.functionStatisticsData); 872 this.currentLevelData = this.functionData; 873 this.tableFunction!.addEventListener('column-click', (evt) => { 874 // @ts-ignore 875 this.sortByColumn(evt.detail.key, evt.detail.sort); 876 }); 877 } 878 879 private getTip() { 880 return (obj: { obj: { tableName: any; durFormat: any; percent: any; }; }): string => { 881 return `<div> 882 <div>Function:${obj.obj.tableName}</div> 883 <div>Duration:${obj.obj.durFormat}</div> 884 <div>percent:${obj.obj.percent}</div> 885 </div> 886 `; 887 }; 888 } 889 890 typeIdToString(type: number): string { 891 let ioTierReleaseType: string; 892 if (type === 1) { 893 ioTierReleaseType = 'DATA_READ'; 894 } else if (type === 2) { 895 ioTierReleaseType = 'DATA_WRITE'; 896 } else if (type === 3) { 897 ioTierReleaseType = 'METADATA_READ'; 898 } else if (type === 4) { 899 ioTierReleaseType = 'METADATA_WRITE'; 900 } 901 // @ts-ignore 902 return ioTierReleaseType; 903 } 904 totalDurationData(duration: number): { 905 durFormat: string; percent: string; tableName: string; 906 duration: number; allDuration: number; 907 } { 908 let allDuration; 909 allDuration = { 910 durFormat: Utils.getProbablyTime(duration), 911 percent: ((duration / duration) * 100).toFixed(2), 912 tableName: '', 913 duration: 0, 914 allDuration: duration, 915 }; 916 return allDuration; 917 } 918 getIOTierPieChartData(res: any[]): unknown[] { 919 if (res.length > 20) { 920 let IOTierPieChartArr: string[] = []; 921 let other: any = { 922 tableName: 'other', 923 duration: 0, 924 percent: 0, 925 durFormat: 0, 926 }; 927 for (let i = 0 ; i < res.length ; i++) { 928 if (i < 19) { 929 IOTierPieChartArr.push(res[i]); 930 } else { 931 other.duration += res[i].duration; 932 other.durFormat = Utils.getProbablyTime(other.duration); 933 other.percent = ((other.duration / this.sumDur) * 100).toFixed(2); 934 } 935 } 936 IOTierPieChartArr.push(other); 937 return IOTierPieChartArr; 938 } 939 return res; 940 } 941 942 getIoTierDataByWorker(args: any[], handler: Function): void { 943 procedurePool.submitWithName( 944 'logic0', 945 'fileSystem-action', 946 { args, callType: 'io', isAnalysis: true }, 947 undefined, 948 (results: any) => { 949 handler(results); 950 this.progressEL!.loading = false; 951 } 952 ); 953 } 954 955 initHtml(): string { 956 return ` 957 <style> 958 :host { 959 display: flex; 960 flex-direction: column; 961 } 962 #io-tier-chart-pie{ 963 height: 300px; 964 } 965 .io-tier-table-box{ 966 width: 60%; 967 border-left: solid 1px var(--dark-border1,#e0e0e0); 968 border-radius: 5px; 969 padding: 10px; 970 } 971 .io-tier-go-back{ 972 display:flex; 973 align-items: center; 974 cursor: pointer; 975 margin-left: 20px; 976 visibility: hidden; 977 } 978 .io-tier-back-box{ 979 background-color: var(--bark-expansion,#0C65D1); 980 border-radius: 5px; 981 color: #fff; 982 display: flex; 983 margin-right: 10px; 984 width: 40px; 985 height: 20px; 986 justify-content: center; 987 align-items: center; 988 } 989 .io-tier-subheading{ 990 font-weight: bold; 991 text-align: center; 992 } 993 .progress{ 994 position: absolute; 995 height: 1px; 996 left: 0; 997 right: 0; 998 } 999 </style> 1000 <label id="time-range" style="width: 100%;height: 20px;text-align: end;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label> 1001 <div style="display: flex;flex-direction: row;"class="d-box"> 1002 <lit-progress-bar class="progress"></lit-progress-bar> 1003 <div id="left_table" style="width: 40%;height:auto;"> 1004 <div style="display: flex;margin-bottom: 10px"> 1005 <div class="io-tier-go-back"> 1006 <div class="io-tier-back-box"> 1007 <lit-icon name="arrowleft"></lit-icon> 1008 </div> 1009 </div> 1010 <div class="title"></div> 1011 </div> 1012 <div class="io-tier-subheading"></div> 1013 <lit-chart-pie id="io-tier-chart-pie"></lit-chart-pie> 1014 </div> 1015 <div class="io-tier-table-box" style="height:auto;overflow: auto"> 1016 <lit-table id="tb-process-usage" style="max-height:565px;min-height: 350px"> 1017 <lit-table-column width="1fr" title="ProcessName" data-index="tableName" key="tableName" align="flex-start"order></lit-table-column> 1018 <lit-table-column width="1fr" title="Duration" data-index="durFormat" key="durFormat" align="flex-start" order></lit-table-column> 1019 <lit-table-column width="1fr" title="%" data-index="percent" key="percent" align="flex-start"order></lit-table-column> 1020 </lit-table> 1021 <lit-table id="tb-type-usage" class="io-analysis" style="max-height:565px;min-height: 350px"hideDownload> 1022 <lit-table-column width="1fr" title="Type" data-index="tableName" key="tableName" align="flex-start"order></lit-table-column> 1023 <lit-table-column width="1fr" title="Duration" data-index="durFormat" key="durFormat" align="flex-start" order></lit-table-column> 1024 <lit-table-column width="1fr" title="%" data-index="percent" key="percent" align="flex-start"order></lit-table-column> 1025 </lit-table> 1026 <lit-table id="tb-thread-usage" class="io-analysis" style="max-height:565px;display: none;min-height: 350px"hideDownload> 1027 <lit-table-column width="1fr" title="ThreadName" data-index="tableName" key="tableName" align="flex-start"order></lit-table-column> 1028 <lit-table-column width="1fr" title="Duration" data-index="durFormat" key="durFormat" align="flex-start" order></lit-table-column> 1029 <lit-table-column width="1fr" title="%" data-index="percent" key="percent" align="flex-start"order></lit-table-column> 1030 </lit-table> 1031 <lit-table id="tb-so-usage" class="io-analysis" style="max-height:565px;display: none;min-height: 350px"hideDownload> 1032 <lit-table-column width="1fr" title="Library" data-index="tableName" key="tableName" align="flex-start"order></lit-table-column> 1033 <lit-table-column width="1fr" title="Duration" data-index="durFormat" key="durFormat" align="flex-start" order></lit-table-column> 1034 <lit-table-column width="1fr" title="%" data-index="percent" key="percent" align="flex-start"order></lit-table-column> 1035 </lit-table> 1036 <lit-table id="tb-function-usage" class="io-analysis" style="max-height:565px;display: none;min-height: 350px"hideDownload> 1037 <lit-table-column width="1fr" title="Function" data-index="tableName" key="tableName" align="flex-start"order></lit-table-column> 1038 <lit-table-column width="1fr" title="Duration" data-index="durFormat" key="durFormat" align="flex-start" order></lit-table-column> 1039 <lit-table-column width="1fr" title="%" data-index="percent" key="percent" align="flex-start"order></lit-table-column> 1040 </lit-table> 1041 </div> 1042 1043 </div> 1044`; 1045 } 1046} 1047