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