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