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