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 '../TabPaneFilter'; 19import { FilterData, TabPaneFilter } from '../TabPaneFilter'; 20import { SelectionParam } from '../../../../bean/BoxSelection'; 21import { PerfCallChainMerageData, PerfLevelStruct } from '../../../../bean/PerfProfile'; 22import '../../../chart/FrameChart'; 23import { FrameChart } from '../../../chart/FrameChart'; 24import { ChartMode } from '../../../../bean/FrameChartStruct'; 25import '../../../../../base-ui/slicer/lit-slicer'; 26import '../../../../../base-ui/progress-bar/LitProgressBar'; 27import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; 28import { procedurePool } from '../../../../database/Procedure'; 29import { showButtonMenu } from '../SheetUtils'; 30import '../../../../../base-ui/headline/lit-headline'; 31import { LitHeadLine } from '../../../../../base-ui/headline/lit-headline'; 32import { TabPerfProfileHtml } from './TabPerfProfile.html'; 33 34const InvertOptionIndex: number = 0; 35const hideSystemLibraryOptionIndex: number = 1; 36const hideThreadOptionIndex: number = 3; 37const hideThreadStateOptionIndex: number = 4; 38const isOnlyKernelOptionIndex: number = 5; 39const callTreeValueNoSample: number[] = [InvertOptionIndex, hideSystemLibraryOptionIndex, hideThreadOptionIndex, 40 hideThreadStateOptionIndex, isOnlyKernelOptionIndex]; 41 42@element('tabpane-perf-profile') 43export class TabpanePerfProfile extends BaseElement { 44 private perfProfilerTbl: LitTable | null | undefined; 45 private perfProfilerList: LitTable | null | undefined; 46 private perfProfileProgressEL: LitProgressBar | null | undefined; 47 private perfProfilerRightSource: Array<PerfCallChainMerageData> = []; 48 private perfProfilerFilter: TabPaneFilter | null | undefined; 49 private perfProfilerDataSource: unknown[] = []; 50 private perfProfileSortKey: string = 'weight'; 51 private perfProfileSortType: number = 0; 52 private perfSelectedData: unknown = undefined; 53 private perfProfileFrameChart: FrameChart | null | undefined; 54 private isChartShow: boolean = false; 55 private systemRuleName: string = '/system/'; 56 private perfProfileNumRuleName: string = '/max/min/'; 57 private needShowMenu: boolean = true; 58 private searchValue: string = ''; 59 private perfProfileLoadingPage: unknown; 60 private currentSelection: SelectionParam | undefined; 61 private currentRowClickData: unknown; 62 private initWidth: number = 0; 63 private _pieTitle: string = ''; 64 private _cWidth: number = 0; 65 private _currentLevel: number = 0; 66 private _rowClickData: unknown = undefined; 67 private perfLevel: PerfLevelStruct | undefined | null; 68 private headLine: LitHeadLine | null | undefined; 69 70 set pieTitle(value: string) { 71 this._pieTitle = value; 72 if (this._pieTitle.length > 0) { 73 this.headLine!.isShow = true; 74 this.headLine!.titleTxt = this._pieTitle; 75 this.headLine!.closeCallback = (): void => { 76 this.restore(); 77 }; 78 } 79 } 80 81 set cWidth(value: number) { 82 this._cWidth = value; 83 } 84 85 set currentLevel(value: number) { 86 this._currentLevel = value; 87 } 88 89 set rowClickData(value: unknown) { 90 this._rowClickData = value; 91 } 92 93 set data(perfProfilerSelection: SelectionParam | unknown) { 94 if (perfProfilerSelection !== this.currentSelection && this._rowClickData === this.currentRowClickData) { 95 this._rowClickData = undefined; 96 } 97 if (perfProfilerSelection === this.currentSelection && !this.currentSelection?.isRowClick) { 98 return; 99 } 100 this.searchValue = ''; // @ts-ignore 101 this.currentSelection = perfProfilerSelection; 102 this.currentRowClickData = this._rowClickData; 103 this.perfProfilerTbl!.style.visibility = 'visible'; 104 if (this.parentElement!.clientHeight > this.perfProfilerFilter!.clientHeight) { 105 this.perfProfilerFilter!.style.display = 'flex'; 106 } else { 107 this.perfProfilerFilter!.style.display = 'none'; 108 } 109 procedurePool.submitWithName('logic0', 'perf-reset', [], undefined, () => { }); 110 this.perfProfilerFilter!.disabledTransfer(true); 111 this.perfProfilerFilter!.initializeFilterTree(true, true, true); 112 this.perfProfilerFilter!.filterValue = ''; 113 this.perfProfileProgressEL!.loading = true; // @ts-ignore 114 this.perfProfileLoadingPage.style.visibility = 'visible'; 115 const newPerfProfilerSelection = Object.fromEntries(// @ts-ignore 116 Object.entries(perfProfilerSelection).filter(([key, value]) => 117 !['clockMapData', 'xpowerMapData', 'hangMapData'].includes(key) 118 ) 119 ) as Partial<SelectionParam>; 120 // @ts-ignore 121 this.getDataByWorkAndUpDateCanvas(newPerfProfilerSelection); 122 } 123 124 getDataByWorkAndUpDateCanvas(perfProfilerSelection: SelectionParam): void { 125 if (this.clientWidth === 0) { 126 this.initWidth = this._cWidth; 127 } else { 128 this.initWidth = this.clientWidth; 129 } 130 if (this._rowClickData && this.currentRowClickData !== undefined && this.currentSelection?.isRowClick) { 131 // 点击表格的某一行跳转到火焰图 132 this.getDataByPieLevel(perfProfilerSelection.perfEventTypeId); 133 } else { 134 this.headLine!.isShow = false; 135 this.initGetData(perfProfilerSelection, this.initWidth, perfProfilerSelection.perfEventTypeId); 136 } 137 } 138 139 initGetData( 140 perfProfilerSelection: SelectionParam | unknown, 141 initWidth: number, 142 eventTypeId: undefined | number 143 ): void { 144 let perfProfileArgs: unknown[] = []; 145 perfProfileArgs.push( 146 { 147 funcName: 'setSearchValue', 148 funcArgs: [''], 149 }, 150 { 151 funcName: 'getCurrentDataFromDbProfile', 152 funcArgs: [perfProfilerSelection], 153 } 154 ); 155 156 this.getDataByWorker(perfProfileArgs, (results: unknown[]) => { 157 this.setPerfProfilerLeftTableData(results); 158 this.perfProfilerList!.recycleDataSource = []; 159 if (eventTypeId === undefined) { 160 this.perfProfileFrameChart!.mode = ChartMode.Count; 161 } else { 162 this.perfProfileFrameChart!.mode = ChartMode.EventCount; 163 } 164 this.perfProfileFrameChart?.updateCanvas(true, initWidth); // @ts-ignore 165 this.perfProfileFrameChart!.totalRootData = this.perfProfilerDataSource;// @ts-ignore 166 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 167 this.switchFlameChart(); 168 this.perfProfilerFilter!.icon = 'block'; 169 }); 170 } 171 172 private restore(): void { 173 this.searchValue = ''; 174 this.perfProfilerFilter!.filterValue = ''; 175 this.headLine!.isShow = false; 176 this._rowClickData = undefined; 177 this.initGetData(this.currentSelection, this.initWidth, this.currentSelection?.perfEventTypeId); 178 } 179 180 /** 181 * 根据饼图跳转过来的层级绘制对应的火焰图和表格 182 */ 183 private getDataByPieLevel(eventTypeId: number | undefined): void { 184 this.perfLevel = new PerfLevelStruct(); 185 this.perfLevel = { 186 // @ts-ignore 187 processId: this._rowClickData.pid, // @ts-ignore 188 threadId: this._rowClickData.tid, // @ts-ignore 189 libId: this._rowClickData.libId, 190 }; 191 let args = []; 192 args.push({ 193 funcName: 'getCurrentDataFromDbProfile', 194 funcArgs: [this.currentSelection, this.perfLevel], 195 }); 196 // @ts-ignore 197 if (this._rowClickData && this._rowClickData.libId !== undefined && this._currentLevel === 2) { 198 // @ts-ignore 199 this.perfLevel!.libName = this._rowClickData.tableName; 200 args.push({ 201 funcName: 'showLibLevelData', 202 funcArgs: [this.perfLevel!.libId, this.perfLevel!.libName], 203 }); // @ts-ignore 204 } else if (this._rowClickData && this._rowClickData.symbolId !== undefined && this._currentLevel === 3) { 205 // @ts-ignore 206 this.perfLevel!.symbolId = this._rowClickData.symbolId; // @ts-ignore 207 this.perfLevel!.symbolName = this._rowClickData.tableName; 208 args.push({ 209 funcName: 'showFunLevelData', 210 funcArgs: [this.perfLevel!.symbolId, this.perfLevel!.symbolName], 211 }); 212 } 213 214 this.getDataByWorker(args, (results: unknown[]) => { 215 this.perfProfileProgressEL!.loading = false; // @ts-ignore 216 this.perfProfileLoadingPage.style.visibility = 'hidden'; 217 this.setPerfProfilerLeftTableData(results); 218 this.perfProfilerList!.recycleDataSource = []; 219 if (eventTypeId === undefined) { 220 this.perfProfileFrameChart!.mode = ChartMode.Count; 221 } else { 222 this.perfProfileFrameChart!.mode = ChartMode.EventCount; 223 } 224 this.perfProfileFrameChart?.updateCanvas(true, this.initWidth); // @ts-ignore 225 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 226 this.switchFlameChart(); 227 this.perfProfilerFilter!.icon = 'block'; 228 }); 229 } 230 231 getParentTree( 232 perfCallSrc: Array<PerfCallChainMerageData>, 233 target: PerfCallChainMerageData, 234 parentsData: Array<PerfCallChainMerageData> 235 ): boolean { 236 for (let perfCall of perfCallSrc) { 237 if (perfCall.id === target.id) { 238 parentsData.push(perfCall); 239 return true; 240 } else { 241 if (this.getParentTree(perfCall.children as Array<PerfCallChainMerageData>, target, parentsData)) { 242 parentsData.push(perfCall); 243 return true; 244 } 245 } 246 } 247 return false; 248 } 249 250 getChildTree( 251 perfCallSrc: Array<PerfCallChainMerageData>, 252 id: string, 253 children: Array<PerfCallChainMerageData> 254 ): boolean { 255 for (let perfCall of perfCallSrc) { 256 if (perfCall.id === id && perfCall.children.length === 0) { 257 children.push(perfCall); 258 return true; 259 } else { 260 if (this.getChildTree(perfCall.children as Array<PerfCallChainMerageData>, id, children)) { 261 children.push(perfCall); 262 return true; 263 } 264 } 265 } 266 return false; 267 } 268 269 setRightTableData(chainMerageData: PerfCallChainMerageData): void { 270 let parentsMerageData: Array<PerfCallChainMerageData> = []; 271 let childrenMerageData: Array<PerfCallChainMerageData> = []; // @ts-ignore 272 this.getParentTree(this.perfProfilerDataSource, chainMerageData, parentsMerageData); 273 let maxId = chainMerageData.id; 274 let maxDur = 0; 275 276 function findMaxStack(call: PerfCallChainMerageData): void { 277 if (call.children.length === 0) { 278 if (call.dur > maxDur) { 279 maxDur = call.dur; 280 maxId = call.id; 281 } 282 } else { 283 call.children.map((callChild): void => { 284 findMaxStack(<PerfCallChainMerageData>callChild); 285 }); 286 } 287 } 288 289 findMaxStack(chainMerageData); 290 this.getChildTree(chainMerageData.children as Array<PerfCallChainMerageData>, maxId, childrenMerageData); 291 let perfProfileParentsList = parentsMerageData.reverse().concat(childrenMerageData.reverse()); 292 for (let data of perfProfileParentsList) { 293 data.type = data.lib.endsWith('.so.1') || data.lib.endsWith('.dll') || data.lib.endsWith('.so') ? 0 : 1; 294 } 295 let len = perfProfileParentsList.length; 296 this.perfProfilerRightSource = perfProfileParentsList; 297 let rightSource: Array<unknown> = []; 298 if (len !== 0) { 299 rightSource = this.perfProfilerRightSource.filter((item): boolean => { 300 return item.canCharge; 301 }); 302 } 303 this.perfProfilerList!.dataSource = rightSource; 304 } 305 306 initElements(): void { 307 this.headLine = this.shadowRoot?.querySelector<LitHeadLine>('.titleBox'); 308 this.perfProfilerTbl = this.shadowRoot?.querySelector<LitTable>('#tb-perf-profile'); 309 this.perfProfileProgressEL = this.shadowRoot?.querySelector('.perf-profile-progress') as LitProgressBar; 310 this.perfProfileFrameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart'); 311 this.perfProfileLoadingPage = this.shadowRoot?.querySelector('.perf-profile-loading'); 312 this.addEventListener('contextmenu', (event) => { 313 event.preventDefault(); // 阻止默认的上下文菜单弹框 314 }); 315 this.perfProfileFrameChart!.addChartClickListener((needShowMenu: boolean): void => { 316 this.parentElement!.scrollTo(0, 0); 317 showButtonMenu(this.perfProfilerFilter, needShowMenu); 318 this.needShowMenu = needShowMenu; 319 }); 320 this.perfProfilerTbl!.rememberScrollTop = true; 321 this.perfProfilerFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#filter'); 322 this.perfProfilerList = this.shadowRoot?.querySelector<LitTable>('#tb-perf-list'); 323 this.initPerfProfilerDataAndListener(); 324 } 325 326 private initPerfProfilerDataAndListener(): void { 327 this.perfProfilerTbl!.addEventListener('row-click', (evt: unknown): void => { 328 // @ts-ignore 329 let data = evt.detail.data as PerfCallChainMerageData; 330 document.dispatchEvent( 331 new CustomEvent('number_calibration', { 332 detail: { time: data.tsArray }, 333 }) 334 ); 335 this.setRightTableData(data); 336 data.isSelected = true; 337 this.perfSelectedData = data; 338 this.perfProfilerList?.clearAllSelection(data); 339 this.perfProfilerList?.setCurrentSelection(data); 340 // @ts-ignore 341 if ((evt.detail as unknown).callBack) { 342 // @ts-ignore 343 (evt.detail as unknown).callBack(true); 344 } 345 }); 346 this.perfProfilerList!.addEventListener('row-click', (evt: unknown): void => { 347 // @ts-ignore 348 let data = evt.detail.data as PerfCallChainMerageData; 349 this.perfProfilerTbl?.clearAllSelection(data); // @ts-ignore 350 (data as unknown).isSelected = true; 351 this.perfProfilerTbl!.scrollToData(data); 352 // @ts-ignore 353 if ((evt.detail as unknown).callBack) { 354 // @ts-ignore 355 (evt.detail as unknown).callBack(true); 356 } 357 }); 358 this.perfProfilerFilter!.getDataLibrary(this.filterFunc.bind(this)); 359 this.perfProfilerFilter!.getDataMining(this.filterFunc.bind(this)); 360 this.perfProfilerFilter!.getCallTreeData(this.perfProfilerFilterGetCallTree.bind(this)); 361 this.perfProfilerFilter!.getCallTreeConstraintsData(this.perfProfilerFilterGetCallTreeConstraints.bind(this)); 362 this.perfProfilerFilter!.getFilterData(this.perfProfilerFilterGetFilter.bind(this)); 363 this.perfProfilerTbl!.addEventListener('column-click', (evt): void => { 364 // @ts-ignore 365 this.perfProfileSortKey = evt.detail.key; 366 // @ts-ignore 367 this.perfProfileSortType = evt.detail.sort; 368 // @ts-ignore 369 this.setPerfProfilerLeftTableData(this.perfProfilerDataSource); // @ts-ignore 370 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 371 }); 372 } 373 374 private filterFuncByCheckType(data: unknown, perfProfileFuncArgs: unknown[]): void { 375 // @ts-ignore 376 if (data.item.checked) { 377 perfProfileFuncArgs.push({ 378 funcName: 'splitTree', // @ts-ignore 379 funcArgs: [data.item.name, data.item.select === '0', data.item.type === 'symbol'], 380 }); 381 } else { 382 perfProfileFuncArgs.push({ 383 funcName: 'resotreAllNode', // @ts-ignore 384 funcArgs: [[data.item.name]], 385 }); 386 perfProfileFuncArgs.push({ 387 funcName: 'resetAllNode', 388 funcArgs: [], 389 }); 390 perfProfileFuncArgs.push({ 391 funcName: 'clearSplitMapData', // @ts-ignore 392 funcArgs: [data.item.name], 393 }); 394 } 395 } 396 397 private filterFuncBySelect(data: unknown, perfProfileFuncArgs: unknown[]): void { 398 perfProfileFuncArgs.push({ 399 funcName: 'resotreAllNode', // @ts-ignore 400 funcArgs: [[data.item.name]], 401 }); 402 perfProfileFuncArgs.push({ 403 funcName: 'clearSplitMapData', // @ts-ignore 404 funcArgs: [data.item.name], 405 }); 406 perfProfileFuncArgs.push({ 407 funcName: 'splitTree', // @ts-ignore 408 funcArgs: [data.item.name, data.item.select === '0', data.item.type === 'symbol'], 409 }); 410 } 411 412 private filterFuncByButton(data: unknown, perfProfileFuncArgs: unknown[]): void { 413 // @ts-ignore 414 if (data.item === 'symbol') { 415 // @ts-ignore 416 if (this.perfSelectedData && !this.perfSelectedData.canCharge) { 417 return; 418 } 419 if (this.perfSelectedData !== undefined) { 420 // @ts-ignore 421 this.perfProfilerFilter!.addDataMining({ name: this.perfSelectedData.symbolName }, data.item); 422 perfProfileFuncArgs.push({ 423 funcName: 'splitTree', // @ts-ignore 424 funcArgs: [this.perfSelectedData.symbolName, false, true], 425 }); 426 } else { 427 return; 428 } // @ts-ignore 429 } else if (data.item === 'library') { 430 // @ts-ignore 431 if (this.perfSelectedData && !this.perfSelectedData.canCharge) { 432 return; 433 } // @ts-ignore 434 if (this.perfSelectedData !== undefined && this.perfSelectedData.libName !== '') { 435 // @ts-ignore 436 this.perfProfilerFilter!.addDataMining({ name: this.perfSelectedData.libName }, data.item); 437 perfProfileFuncArgs.push({ 438 funcName: 'splitTree', // @ts-ignore 439 funcArgs: [this.perfSelectedData.libName, false, false], 440 }); 441 } else { 442 return; 443 } // @ts-ignore 444 } else if (data.item === 'restore') { 445 // @ts-ignore 446 if (data.remove !== undefined && data.remove.length > 0) { 447 // @ts-ignore 448 let list = data.remove.map((item: unknown) => { 449 // @ts-ignore 450 return item.name; 451 }); 452 perfProfileFuncArgs.push({ 453 funcName: 'resotreAllNode', 454 funcArgs: [list], 455 }); 456 perfProfileFuncArgs.push({ 457 funcName: 'resetAllNode', 458 funcArgs: [], 459 }); 460 list.forEach((symbolName: string): void => { 461 perfProfileFuncArgs.push({ 462 funcName: 'clearSplitMapData', 463 funcArgs: [symbolName], 464 }); 465 }); 466 } 467 } 468 } 469 470 private filterFunc(data: unknown): void { 471 let perfProfileFuncArgs: unknown[] = []; // @ts-ignore 472 if (data.type === 'check') { 473 this.filterFuncByCheckType(data, perfProfileFuncArgs); // @ts-ignore 474 } else if (data.type === 'select') { 475 this.filterFuncBySelect(data, perfProfileFuncArgs); // @ts-ignore 476 } else if (data.type === 'button') { 477 this.filterFuncByButton(data, perfProfileFuncArgs); 478 } 479 this.getDataByWorker(perfProfileFuncArgs, (result: unknown[]): void => { 480 this.setPerfProfilerLeftTableData(result); // @ts-ignore 481 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 482 if (this.isChartShow) { 483 this.perfProfileFrameChart?.calculateChartData(); 484 } 485 this.perfProfilerTbl!.move1px(); 486 if (this.perfSelectedData) { 487 // @ts-ignore 488 this.perfSelectedData.isSelected = false; 489 this.perfProfilerTbl?.clearAllSelection(this.perfSelectedData); 490 this.perfProfilerList!.recycleDataSource = []; 491 this.perfSelectedData = undefined; 492 } 493 }); 494 } 495 496 private perfProfilerFilterGetFilter(data: FilterData): void { 497 if ((this.isChartShow && data.icon === 'tree') || (!this.isChartShow && data.icon === 'block')) { 498 this.switchFlameChart(data); 499 } else if (this.searchValue !== this.perfProfilerFilter!.filterValue) { 500 this.searchValue = this.perfProfilerFilter!.filterValue; 501 let perfArgs = [ 502 { 503 funcName: 'setSearchValue', 504 funcArgs: [this.searchValue], 505 }, 506 { 507 funcName: 'resetAllNode', 508 funcArgs: [], 509 }, 510 ]; 511 this.getDataByWorker(perfArgs, (result: unknown[]): void => { 512 this.perfProfilerTbl!.isSearch = true; 513 this.perfProfilerTbl!.setStatus(result, true); 514 this.setPerfProfilerLeftTableData(result); // @ts-ignore 515 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 516 this.switchFlameChart(data); 517 }); 518 } else { 519 this.perfProfilerTbl!.setStatus(this.perfProfilerDataSource, true); 520 this.setPerfProfilerLeftTableData(this.perfProfilerDataSource); 521 this.switchFlameChart(data); 522 } 523 } 524 525 private perfProfilerFilterGetCallTreeConstraints(data: unknown): void { 526 let perfProfilerConstraintsArgs: unknown[] = [ 527 { 528 funcName: 'resotreAllNode', 529 funcArgs: [[this.perfProfileNumRuleName]], 530 }, 531 { 532 funcName: 'clearSplitMapData', 533 funcArgs: [this.perfProfileNumRuleName], 534 }, 535 ]; // @ts-ignore 536 if (data.checked) { 537 perfProfilerConstraintsArgs.push({ 538 funcName: 'hideNumMaxAndMin', // @ts-ignore 539 funcArgs: [parseInt(data.min), data.max], 540 }); 541 } 542 perfProfilerConstraintsArgs.push({ 543 funcName: 'resetAllNode', 544 funcArgs: [], 545 }); 546 this.getDataByWorker(perfProfilerConstraintsArgs, (result: unknown[]): void => { 547 this.setPerfProfilerLeftTableData(result); // @ts-ignore 548 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 549 if (this.isChartShow) { 550 this.perfProfileFrameChart?.calculateChartData(); 551 } 552 }); 553 } 554 555 private perfProfilerFilterGetCallTree(data: unknown): void { 556 // @ts-ignore 557 if (callTreeValueNoSample.includes(data.value)) { 558 this.refreshAllNode({ 559 ...this.perfProfilerFilter!.getFilterTreeData(), // @ts-ignore 560 callTree: data.checks, 561 }); 562 } else { 563 let perfProfileArgs: unknown[] = []; // @ts-ignore 564 if (data.checks[1]) { 565 perfProfileArgs.push({ 566 funcName: 'hideSystemLibrary', 567 funcArgs: [], 568 }); 569 } else { 570 perfProfileArgs.push({ 571 funcName: 'resotreAllNode', 572 funcArgs: [[this.systemRuleName]], 573 }); 574 perfProfileArgs.push({ 575 funcName: 'clearSplitMapData', 576 funcArgs: [this.systemRuleName], 577 }); 578 } 579 perfProfileArgs.push({ 580 funcName: 'resetAllNode', 581 funcArgs: [], 582 }); 583 this.getDataByWorker(perfProfileArgs, (result: unknown[]): void => { 584 this.setPerfProfilerLeftTableData(result); // @ts-ignore 585 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 586 if (this.isChartShow) { 587 this.perfProfileFrameChart?.calculateChartData(); 588 } 589 }); 590 } 591 } 592 593 connectedCallback(): void { 594 super.connectedCallback(); 595 this.parentElement!.onscroll = (): void => { 596 this.perfProfileFrameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; 597 }; 598 let filterHeight = 0; 599 new ResizeObserver((entries): void => { 600 let perfProfileTabFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; 601 if (perfProfileTabFilter.clientHeight > 0) { 602 filterHeight = perfProfileTabFilter.clientHeight; 603 } 604 if (this.parentElement!.clientHeight > filterHeight) { 605 perfProfileTabFilter.style.display = 'flex'; 606 } else { 607 perfProfileTabFilter.style.display = 'none'; 608 } 609 if (this.perfProfilerTbl!.style.visibility === 'hidden') { 610 perfProfileTabFilter.style.display = 'none'; 611 } 612 if (this.parentElement?.clientHeight !== 0) { 613 if (this.isChartShow) { 614 this.perfProfileFrameChart?.updateCanvas(false, entries[0].contentRect.width); 615 this.perfProfileFrameChart?.calculateChartData(); 616 } 617 let headLineHeight = 0; 618 if (this.headLine?.isShow) { 619 headLineHeight = this.headLine!.clientHeight; 620 } 621 // @ts-ignore 622 this.perfProfilerTbl?.shadowRoot.querySelector('.table').style.height = 623 // @ts-ignore 624 `${this.parentElement.clientHeight - 10 - 35 - headLineHeight}px`; 625 this.perfProfilerTbl?.reMeauseHeight(); 626 // @ts-ignore 627 this.perfProfilerList?.shadowRoot.querySelector('.table').style.height = 628 // @ts-ignore 629 `${this.parentElement.clientHeight - 45 - 21 - headLineHeight}px`; 630 this.perfProfilerList?.reMeauseHeight(); // @ts-ignore 631 this.perfProfileLoadingPage.style.height = `${this.parentElement!.clientHeight - 24}px`; 632 } 633 }).observe(this.parentElement!); 634 } 635 636 switchFlameChart(data?: unknown): void { 637 let perfProfilerPageTab = this.shadowRoot?.querySelector('#show_table'); 638 let perfProfilerPageChart = this.shadowRoot?.querySelector('#show_chart'); // @ts-ignore 639 if (!data || data.icon === 'block') { 640 perfProfilerPageChart?.setAttribute('class', 'show'); 641 perfProfilerPageTab?.setAttribute('class', ''); 642 this.isChartShow = true; 643 this.perfProfilerFilter!.disabledMining = true; 644 showButtonMenu(this.perfProfilerFilter, this.needShowMenu); 645 this.perfProfileFrameChart?.calculateChartData(); // @ts-ignore 646 } else if (data.icon === 'tree') { 647 perfProfilerPageChart?.setAttribute('class', ''); 648 perfProfilerPageTab?.setAttribute('class', 'show'); 649 showButtonMenu(this.perfProfilerFilter, true); 650 this.isChartShow = false; 651 this.perfProfilerFilter!.disabledMining = false; 652 this.perfProfileFrameChart!.clearCanvas(); 653 this.perfProfilerTbl!.reMeauseHeight(); 654 } 655 } 656 657 refreshAllNode(filterData: unknown): void { 658 let perfProfileArgs: unknown[] = []; // @ts-ignore 659 let isTopDown: boolean = !filterData.callTree[0]; // @ts-ignore 660 let isHideSystemLibrary: boolean = filterData.callTree[1]; // @ts-ignore 661 let isHideThread: boolean = filterData.callTree[3]; // @ts-ignore 662 let isHideThreadState: boolean = filterData.callTree[4]; // @ts-ignore 663 let isOnlyKernel: boolean = filterData.callTree[5]; // @ts-ignore 664 let list = filterData.dataMining.concat(filterData.dataLibrary); 665 perfProfileArgs.push({ 666 funcName: 'hideThread', 667 funcArgs: [isHideThread], 668 }); 669 670 perfProfileArgs.push({ 671 funcName: 'hideThreadState', 672 funcArgs: [isHideThreadState], 673 }); 674 perfProfileArgs.push({ 675 funcName: 'onlyKernel', 676 funcArgs: [isOnlyKernel], 677 }); 678 perfProfileArgs.push({ 679 funcName: 'getCallChainsBySampleIds', 680 funcArgs: [isTopDown], 681 }); 682 this.perfProfilerList!.recycleDataSource = []; 683 if (isHideSystemLibrary) { 684 perfProfileArgs.push({ 685 funcName: 'hideSystemLibrary', 686 funcArgs: [], 687 }); 688 } // @ts-ignore 689 if (filterData.callTreeConstraints.checked) { 690 perfProfileArgs.push({ 691 funcName: 'hideNumMaxAndMin', // @ts-ignore 692 funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], 693 }); 694 } 695 perfProfileArgs.push({ 696 funcName: 'splitAllProcess', 697 funcArgs: [list], 698 }); 699 perfProfileArgs.push({ 700 funcName: 'resetAllNode', 701 funcArgs: [], 702 }); 703 // @ts-ignore 704 this.refreshAllNodeExtend(perfProfileArgs); 705 } 706 707 refreshAllNodeExtend(perfProfileArgs: unknown[]): void { 708 // @ts-ignore 709 if (this._rowClickData && this._rowClickData.libId !== undefined && this._currentLevel === 2) { 710 perfProfileArgs.push({ 711 funcName: 'showLibLevelData', 712 funcArgs: [this.perfLevel!.libId, this.perfLevel!.libName], 713 }); // @ts-ignore 714 } else if (this._rowClickData && this._rowClickData.symbolId && this._currentLevel === 3) { 715 perfProfileArgs.push({ 716 funcName: 'showFunLevelData', 717 funcArgs: [this.perfLevel!.symbolId, this.perfLevel!.symbolName], 718 }); 719 } 720 this.getDataByWorker(perfProfileArgs, (result: unknown[]): void => { 721 this.setPerfProfilerLeftTableData(result); // @ts-ignore 722 this.perfProfileFrameChart!.data = this.perfProfilerDataSource; 723 if (this.isChartShow) { 724 this.perfProfileFrameChart?.calculateChartData(); 725 } 726 }); 727 } 728 729 setPerfProfilerLeftTableData(resultData: unknown[]): void { 730 this.perfProfilerDataSource = this.sortTree(resultData); 731 this.perfProfilerTbl!.recycleDataSource = this.perfProfilerDataSource; 732 } 733 734 sortTree(arr: Array<unknown>): Array<unknown> { 735 let perfProfileSortArr = arr.sort((perfProfileA, perfProfileB): number => { 736 if (this.perfProfileSortKey === 'selfDur') { 737 if (this.perfProfileSortType === 0) { 738 // @ts-ignore 739 return perfProfileB.dur - perfProfileA.dur; 740 } else if (this.perfProfileSortType === 1) { 741 // @ts-ignore 742 return perfProfileA.selfDur - perfProfileB.selfDur; 743 } else { 744 // @ts-ignore 745 return perfProfileB.selfDur - perfProfileA.selfDur; 746 } 747 } else { 748 if (this.perfProfileSortType === 0) { 749 // @ts-ignore 750 return perfProfileB.dur - perfProfileA.dur; 751 } else if (this.perfProfileSortType === 1) { 752 // @ts-ignore 753 return perfProfileA.dur - perfProfileB.dur; 754 } else { 755 // @ts-ignore 756 return perfProfileB.dur - perfProfileA.dur; 757 } 758 } 759 }); 760 perfProfileSortArr.map((call: unknown): void => { 761 // @ts-ignore 762 call.children = this.sortTree(call.children); 763 }); 764 return perfProfileSortArr; 765 } 766 767 getDataByWorker(args: unknown[], handler: Function): void { 768 this.perfProfileProgressEL!.loading = true; // @ts-ignore 769 this.perfProfileLoadingPage.style.visibility = 'visible'; 770 procedurePool.submitWithName('logic0', 'perf-action', args, undefined, (results: unknown): void => { 771 handler(results); 772 this.perfProfileProgressEL!.loading = false; // @ts-ignore 773 this.perfProfileLoadingPage.style.visibility = 'hidden'; 774 }); 775 } 776 777 initHtml(): string { 778 return TabPerfProfileHtml; 779 } 780} 781