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