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 { FileMerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem'; 25import { ParseExpression } from '../SheetUtils'; 26import { FilterByAnalysis, NativeMemoryExpression } from '../../../../bean/NativeHook'; 27import { SpSystemTrace } from '../../../SpSystemTrace'; 28import '../../../../../base-ui/headline/lit-headline'; 29import { LitHeadLine } from '../../../../../base-ui/headline/lit-headline'; 30import { TabPaneNMCallTreeHtml } from './TabPaneNMCallTree.html'; 31import { queryNativeHookStatisticSubType, queryNativeHookSubType } from '../../../../database/sql/NativeHook.sql'; 32 33const InvertOpyionIndex: number = 0; 34const HideSystemSoOptionIndex: number = 1; 35const HideThreadOptionIndex: number = 3; 36 37@element('tabpane-nm-calltree') 38export class TabpaneNMCalltree extends BaseElement { 39 private nmCallTreeTbl: LitTable | null | undefined; 40 private filesystemTbr: LitTable | null | undefined; 41 private nmCallTreeProgressEL: LitProgressBar | null | undefined; 42 private nmCallTreeFilter: TabPaneFilter | null | undefined; 43 private nmCallTreeSource: any[] = []; 44 private nativeType: Array<string> = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; 45 private sortKey: string = 'heapSizeStr'; 46 private sortType: number = 0; 47 private currentSelectedData: any = undefined; 48 private nmCallTreeFrameChart: FrameChart | null | undefined; 49 private isChartShow: boolean = false; 50 private systmeRuleName: string = '/system/'; 51 private numRuleName: string = '/max/min/'; 52 private needShowMenu: boolean = true; 53 private searchValue: string = ''; 54 private loadingList: number[] = []; 55 private nmCallTreeLoadingPage: any; 56 private currentSelection: SelectionParam | undefined; 57 private filterAllocationType: string = '0'; 58 private filterNativeType: string = '0'; 59 private filterResponseType: number = -1; 60 private filterResponseSelect: string = '0'; 61 private responseTypes: any[] = []; 62 private subTypeArr: number[] = []; 63 private lastIsExpression = false; 64 private currentNMCallTreeFilter: TabPaneFilter | undefined | null; 65 private expressionStruct: NativeMemoryExpression | null = null; 66 private isHideThread: boolean = false; 67 private currentSelectIPid = 1; 68 private headLine: LitHeadLine | null | undefined; 69 private _filterData: FilterByAnalysis | undefined; 70 private _analysisTabWidth: number = 0; 71 private _initFromAnalysis = false; 72 73 set analysisTabWidth(width: number) { 74 this._analysisTabWidth = width; 75 } 76 77 set titleTxt(value: string) { 78 this.headLine!.titleTxt = value; 79 } 80 81 set filterData(data: FilterByAnalysis) { 82 // click from analysis 83 this._filterData = data; 84 } 85 86 set titleBoxShow(value: Boolean) { 87 this.headLine!.isShow = value; 88 } 89 90 set initFromAnalysis(flag: boolean) { 91 this._initFromAnalysis = flag; 92 } 93 94 set data(nmCallTreeParam: SelectionParam) { 95 if (nmCallTreeParam === this.currentSelection) { 96 return; 97 } 98 this.nmCallTreeSource = []; 99 this.currentSelection = nmCallTreeParam; 100 this.currentSelectIPid = nmCallTreeParam.nativeMemoryCurrentIPid; 101 this.init(nmCallTreeParam); 102 } 103 104 private async init(nmCallTreeParam: SelectionParam): Promise<void> { 105 this.initUI(); 106 await this.initFilterTypes(); 107 let types: Array<string | number> = []; 108 this.initTypes(nmCallTreeParam, types); 109 const initWidth = this._analysisTabWidth > 0 ? this._analysisTabWidth : this.clientWidth; 110 this.getDataByWorkerQuery( 111 { 112 leftNs: nmCallTreeParam.leftNs, 113 rightNs: nmCallTreeParam.rightNs, 114 types, 115 }, 116 (results: any[]): void => { 117 this.setLTableData(results); 118 this.filesystemTbr!.recycleDataSource = []; 119 120 this.nmCallTreeFrameChart?.updateCanvas(true, initWidth); 121 if (this._initFromAnalysis) { 122 this.filterByAnalysis(); 123 } else { 124 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 125 this.switchFlameChart(); 126 this.nmCallTreeFilter!.icon = 'block'; 127 } 128 } 129 ); 130 } 131 132 initUI(): void { 133 this.headLine!.clear(); 134 this.isHideThread = false; 135 this.searchValue = ''; 136 this.nmCallTreeTbl!.style.visibility = 'visible'; 137 if (this.parentElement!.clientHeight > this.nmCallTreeFilter!.clientHeight) { 138 this.nmCallTreeFilter!.style.display = 'flex'; 139 } else { 140 this.nmCallTreeFilter!.style.display = 'none'; 141 } 142 procedurePool.submitWithName('logic0', 'native-memory-reset', [], undefined, () => {}); 143 this.nmCallTreeFilter!.disabledTransfer(true); 144 this.nmCallTreeFilter!.initializeFilterTree(true, true, this.currentSelection!.nativeMemory.length > 0); 145 this.nmCallTreeFilter!.filterValue = ''; 146 147 this.nmCallTreeProgressEL!.loading = true; 148 this.nmCallTreeLoadingPage.style.visibility = 'visible'; 149 } 150 151 initTypes(nmCallTreeParam: SelectionParam, types: Array<string | number>): void { 152 if (nmCallTreeParam.nativeMemory.length > 0) { 153 this.nmCallTreeFilter!.isStatisticsMemory = false; 154 if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[0]) !== -1) { 155 types.push("'AllocEvent'"); 156 types.push("'MmapEvent'"); 157 } else { 158 if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[1]) !== -1) { 159 types.push("'AllocEvent'"); 160 } 161 if (nmCallTreeParam.nativeMemory.indexOf(this.nativeType[2]) !== -1) { 162 types.push("'MmapEvent'"); 163 } 164 } 165 } else { 166 this.nmCallTreeFilter!.isStatisticsMemory = true; 167 if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[0]) !== -1) { 168 types.push(0); 169 types.push(1); 170 } else { 171 if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[1]) !== -1) { 172 types.push(0); 173 } 174 if (nmCallTreeParam.nativeMemoryStatistic.indexOf(this.nativeType[2]) !== -1) { 175 types.push(1); 176 } 177 } 178 } 179 } 180 181 setFilterType(selections: Array<any>, data: FilterByAnalysis): void { 182 if (data.type === 'AllocEvent') { 183 data.type = '1'; 184 } 185 const that = this; 186 if (this.subTypeArr.length > 0) { 187 this.subTypeArr.map((memory): void => { 188 selections.push({ 189 memoryTap: memory, 190 }); 191 if (that.currentSelection?.nativeMemory && that.currentSelection.nativeMemory.length > 0) { 192 const typeName = SpSystemTrace.DATA_DICT.get(memory); 193 if ((data.type === 'MmapEvent' && memory == -1) || data.type === typeName) { 194 data.type = `${selections.length + 2}`; 195 } 196 } else { 197 if ( 198 (data.type === 'MmapEvent' && memory === 1) || 199 (data.type === 'FILE_PAGE_MSG' && memory === 2) || 200 (data.type === 'MEMORY_USING_MSG' && memory === 3) 201 ) { 202 data.type = `${selections.length + 2}`; 203 } 204 } 205 }); 206 } 207 } 208 209 filterByAnalysis(): void { 210 let filterContent: any[] = []; 211 let param = new Map<string, any>(); 212 let selections: Array<any> = []; 213 this.setFilterType(selections, this._filterData!); 214 param.set('filterByTitleArr', this._filterData); 215 param.set('filterAllocType', '0'); 216 param.set('statisticsSelection', selections); 217 param.set('leftNs', this.currentSelection?.leftNs); 218 param.set('rightNs', this.currentSelection?.rightNs); 219 filterContent.push( 220 { 221 funcName: 'groupCallchainSample', 222 funcArgs: [param], 223 }, 224 { 225 funcName: 'getCallChainsBySampleIds', 226 funcArgs: [true], 227 } 228 ); 229 this.getDataByWorker(filterContent, (result: any[]) => { 230 this.setLTableData(result); 231 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 232 this.switchFlameChart(); 233 this.nmCallTreeFilter!.icon = 'block'; 234 this.initFromAnalysis = false; 235 }); 236 this.banTypeAndLidSelect(); 237 } 238 239 banTypeAndLidSelect(): void { 240 this.currentNMCallTreeFilter!.firstSelect = '0'; 241 let secondSelect = this.shadowRoot 242 ?.querySelector('#nm-call-tree-filter')! 243 .shadowRoot!.querySelector('#second-select'); 244 let thirdSelect = this.shadowRoot 245 ?.querySelector('#nm-call-tree-filter')! 246 .shadowRoot!.querySelector('#third-select'); 247 thirdSelect?.setAttribute('disabled', ''); 248 secondSelect?.setAttribute('disabled', ''); 249 } 250 251 getParentTree( 252 nmCallTreeSrc: Array<FileMerageBean>, 253 nmCallTreeTarget: FileMerageBean, 254 parents: Array<FileMerageBean> 255 ): boolean { 256 for (let nmCallTreeBean of nmCallTreeSrc) { 257 if (nmCallTreeBean.id === nmCallTreeTarget.id) { 258 parents.push(nmCallTreeBean); 259 return true; 260 } else { 261 if (this.getParentTree(nmCallTreeBean.children as Array<FileMerageBean>, nmCallTreeTarget, parents)) { 262 parents.push(nmCallTreeBean); 263 return true; 264 } 265 } 266 } 267 return false; 268 } 269 270 getChildTree(nmCallTreeSrc: Array<FileMerageBean>, id: string, children: Array<FileMerageBean>): boolean { 271 for (let nmCallTreeBean of nmCallTreeSrc) { 272 if (nmCallTreeBean.id === id && nmCallTreeBean.children.length === 0) { 273 children.push(nmCallTreeBean); 274 return true; 275 } else { 276 if (this.getChildTree(nmCallTreeBean.children as Array<FileMerageBean>, id, children)) { 277 children.push(nmCallTreeBean); 278 return true; 279 } 280 } 281 } 282 return false; 283 } 284 285 setRightTableData(fileMerageBean: FileMerageBean): void { 286 let parents: Array<FileMerageBean> = []; 287 let children: Array<FileMerageBean> = []; 288 this.getParentTree(this.nmCallTreeSource, fileMerageBean, parents); 289 let maxId = fileMerageBean.id; 290 let maxDur = 0; 291 292 function findMaxStack(merageBean: any): void { 293 if (merageBean.children.length === 0) { 294 if (merageBean.heapSize > maxDur) { 295 maxDur = merageBean.heapSize; 296 maxId = merageBean.id; 297 } 298 } else { 299 merageBean.children.map((callChild: any): void => { 300 findMaxStack(<FileMerageBean>callChild); 301 }); 302 } 303 } 304 305 findMaxStack(fileMerageBean); 306 this.getChildTree(fileMerageBean.children as Array<FileMerageBean>, maxId, children); 307 let resultValue = parents.reverse().concat(children.reverse()); 308 for (let data of resultValue) { 309 data.type = 310 data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1; 311 } 312 let resultLength = resultValue.length; 313 this.filesystemTbr!.dataSource = resultLength == 0 ? [] : resultValue; 314 } 315 316 //底部的筛选菜单 317 showBottomMenu(isShow: boolean): void { 318 if (isShow) { 319 this.nmCallTreeFilter?.showThird(true); 320 this.nmCallTreeFilter?.setAttribute('first', ''); 321 this.nmCallTreeFilter?.setAttribute('second', ''); 322 this.nmCallTreeFilter?.setAttribute('tree', ''); 323 this.nmCallTreeFilter?.setAttribute('input', ''); 324 this.nmCallTreeFilter?.setAttribute('inputLeftText', ''); 325 } else { 326 this.nmCallTreeFilter?.showThird(false); 327 this.nmCallTreeFilter?.removeAttribute('first'); 328 this.nmCallTreeFilter?.removeAttribute('second'); 329 this.nmCallTreeFilter?.removeAttribute('tree'); 330 this.nmCallTreeFilter?.removeAttribute('input'); 331 this.nmCallTreeFilter?.removeAttribute('inputLeftText'); 332 } 333 } 334 335 async initFilterTypes(): Promise<void> { 336 this.currentNMCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter'); 337 let secondFilterList = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; 338 let that = this; 339 function addSubType(subTypeList: any) { 340 if (!subTypeList) { 341 return; 342 } 343 that.subTypeArr = []; 344 for (let data of subTypeList) { 345 secondFilterList.push(data.subType); 346 that.subTypeArr.push(data.subTypeId); 347 } 348 } 349 if (this.currentSelection!.nativeMemory!.length > 0) { 350 let subTypeList = await queryNativeHookSubType( 351 this.currentSelection!.leftNs, 352 this.currentSelection!.rightNs, 353 this.currentSelectIPid 354 ); 355 addSubType(subTypeList); 356 } else { 357 let subTypeList = await queryNativeHookStatisticSubType( 358 this.currentSelection!.leftNs, 359 this.currentSelection!.rightNs, 360 this.currentSelectIPid 361 ); 362 addSubType(subTypeList); 363 } 364 this.nMCallTreeFilterExtend(secondFilterList); 365 } 366 367 private nMCallTreeFilterExtend(secondFilterList: string[]): void { 368 procedurePool.submitWithName('logic0', 'native-memory-get-responseType', {}, undefined, (res: any) => { 369 this.responseTypes = res; 370 let nullIndex = this.responseTypes.findIndex((item) => { 371 return item.key == 0; 372 }); 373 if (nullIndex != -1) { 374 this.responseTypes.splice(nullIndex, 1); 375 } 376 this.currentNMCallTreeFilter!.setSelectList( 377 null, 378 secondFilterList, 379 'Allocation Lifespan', 380 'Allocation Type', 381 this.responseTypes.map((item: any) => { 382 return item.value; 383 }) 384 ); 385 this.currentNMCallTreeFilter!.setFilterModuleSelect('#first-select', 'width', '150px'); 386 this.currentNMCallTreeFilter!.setFilterModuleSelect('#second-select', 'width', '150px'); 387 this.currentNMCallTreeFilter!.setFilterModuleSelect('#third-select', 'width', '150px'); 388 this.currentNMCallTreeFilter!.firstSelect = '0'; 389 this.currentNMCallTreeFilter!.secondSelect = '0'; 390 this.currentNMCallTreeFilter!.thirdSelect = '0'; 391 this.filterAllocationType = '0'; 392 this.filterNativeType = '0'; 393 this.filterResponseSelect = '0'; 394 this.filterResponseType = -1; 395 }); 396 } 397 398 initElements(): void { 399 this.headLine = this.shadowRoot?.querySelector<LitHeadLine>('.titleBox'); 400 this.nmCallTreeTbl = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-calltree'); 401 this.nmCallTreeProgressEL = this.shadowRoot?.querySelector('.nm-call-tree-progress') as LitProgressBar; 402 this.nmCallTreeFrameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart'); 403 this.nmCallTreeFrameChart!.mode = ChartMode.Byte; 404 this.nmCallTreeLoadingPage = this.shadowRoot?.querySelector('.nm-call-tree-loading'); 405 this.nmCallTreeFrameChart!.addChartClickListener((needShowMenu: boolean): void => { 406 this.parentElement!.scrollTo(0, 0); 407 this.showBottomMenu(needShowMenu); 408 this.needShowMenu = needShowMenu; 409 }); 410 this.nmCallTreeTbl!.rememberScrollTop = true; 411 this.nmCallTreeTbl!.exportTextHandleMap.set('heapSizeStr', (value) => { 412 return `${value['size']}`; 413 }); 414 this.nmCallTreeFilter = this.shadowRoot?.querySelector<TabPaneFilter>('#nm-call-tree-filter'); 415 this.filesystemTbr = this.shadowRoot?.querySelector<LitTable>('#tb-filesystem-list'); 416 let filterFunc = (nmCallTreeFuncData: any): void => { 417 let nmCallTreeFuncArgs: any[] = []; 418 if (nmCallTreeFuncData.type === 'check') { 419 nmCallTreeFuncArgs = this.filterFuncByCheckType(nmCallTreeFuncData, nmCallTreeFuncArgs); 420 } else if (nmCallTreeFuncData.type == 'select') { 421 nmCallTreeFuncArgs = this.filterFuncBySelectType(nmCallTreeFuncData, nmCallTreeFuncArgs); 422 } else if (nmCallTreeFuncData.type === 'button') { 423 nmCallTreeFuncArgs = this.filterFuncByButtonType(nmCallTreeFuncData, nmCallTreeFuncArgs); 424 } 425 this.getDataByWorker(nmCallTreeFuncArgs, (result: any[]): void => { 426 this.setLTableData(result); 427 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 428 if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData(); 429 this.nmCallTreeTbl!.move1px(); 430 if (this.currentSelectedData) { 431 this.currentSelectedData.isSelected = false; 432 this.nmCallTreeTbl?.clearAllSelection(this.currentSelectedData); 433 this.filesystemTbr!.recycleDataSource = []; 434 this.currentSelectedData = undefined; 435 } 436 }); 437 }; 438 this.nmCallTreeFilter!.getDataLibrary(filterFunc.bind(this)); 439 this.nmCallTreeFilter!.getDataMining(filterFunc.bind(this)); 440 this.nmCallTreeFilter!.getCallTreeData(this.getCallTreeByNMCallTreeFilter.bind(this)); 441 this.nmCallTreeFilter!.getCallTreeConstraintsData(this.getCallTreeConByNMCallTreeFilter.bind(this)); 442 this.nmCallTreeFilter!.getFilterData(this.getFilterDataByNMCallTreeFilter.bind(this)); 443 this.initCloseCallBackByHeadLine(); 444 } 445 446 private getFilterDataByNMCallTreeFilter(nmCallTreeData: FilterData): void { 447 if ( 448 (this.isChartShow && nmCallTreeData.icon === 'tree') || 449 (!this.isChartShow && nmCallTreeData.icon === 'block') 450 ) { 451 this.switchFlameChart(nmCallTreeData); 452 } else { 453 this.initGetFilterByNMCallTreeFilter(nmCallTreeData); 454 } 455 } 456 457 private getCallTreeConByNMCallTreeFilter(nmCallTreeConstraintsData: any): void { 458 let nmCallTreeConstraintsArgs: any[] = [ 459 { 460 funcName: 'resotreAllNode', 461 funcArgs: [[this.numRuleName]], 462 }, 463 { 464 funcName: 'clearSplitMapData', 465 funcArgs: [this.numRuleName], 466 }, 467 ]; 468 if (nmCallTreeConstraintsData.checked) { 469 nmCallTreeConstraintsArgs.push({ 470 funcName: 'hideNumMaxAndMin', 471 funcArgs: [parseInt(nmCallTreeConstraintsData.min), nmCallTreeConstraintsData.max], 472 }); 473 } 474 nmCallTreeConstraintsArgs.push({ 475 funcName: 'resetAllNode', 476 funcArgs: [], 477 }); 478 this.getDataByWorker(nmCallTreeConstraintsArgs, (result: any[]): void => { 479 this.setLTableData(result); 480 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 481 if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData(); 482 }); 483 } 484 485 private getCallTreeByNMCallTreeFilter(callTreeData: any): void { 486 if ([InvertOpyionIndex, HideSystemSoOptionIndex, HideThreadOptionIndex].includes(callTreeData.value)) { 487 this.refreshAllNode({ 488 ...this.nmCallTreeFilter!.getFilterTreeData(), 489 callTree: callTreeData.checks, 490 }); 491 } else { 492 let resultArgs: any[] = []; 493 if (callTreeData.checks[1]) { 494 resultArgs.push({ 495 funcName: 'hideSystemLibrary', 496 funcArgs: [], 497 }); 498 resultArgs.push({ 499 funcName: 'resetAllNode', 500 funcArgs: [], 501 }); 502 } else { 503 resultArgs.push({ 504 funcName: 'resotreAllNode', 505 funcArgs: [[this.systmeRuleName]], 506 }); 507 resultArgs.push({ 508 funcName: 'resetAllNode', 509 funcArgs: [], 510 }); 511 resultArgs.push({ 512 funcName: 'clearSplitMapData', 513 funcArgs: [this.systmeRuleName], 514 }); 515 } 516 this.getDataByWorker(resultArgs, (result: any[]): void => { 517 this.setLTableData(result); 518 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 519 if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData(); 520 }); 521 } 522 } 523 524 private filterFuncByButtonType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] { 525 if (nmCallTreeFuncData.item == 'symbol') { 526 if (this.currentSelectedData && !this.currentSelectedData.canCharge) { 527 return nmCallTreeFuncArgs; 528 } 529 if (this.currentSelectedData !== undefined) { 530 this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.symbolName }, nmCallTreeFuncData.item); 531 nmCallTreeFuncArgs.push({ 532 funcName: 'splitTree', 533 funcArgs: [this.currentSelectedData.symbolName, false, true], 534 }); 535 } else { 536 return nmCallTreeFuncArgs; 537 } 538 } else if (nmCallTreeFuncData.item === 'library') { 539 if (this.currentSelectedData && !this.currentSelectedData.canCharge) { 540 return nmCallTreeFuncArgs; 541 } 542 if (this.currentSelectedData != undefined && this.currentSelectedData.libName !== '') { 543 this.nmCallTreeFilter!.addDataMining({ name: this.currentSelectedData.libName }, nmCallTreeFuncData.item); 544 nmCallTreeFuncArgs.push({ 545 funcName: 'splitTree', 546 funcArgs: [this.currentSelectedData.libName, false, false], 547 }); 548 } else { 549 return nmCallTreeFuncArgs; 550 } 551 } else if (nmCallTreeFuncData.item === 'restore') { 552 if (nmCallTreeFuncData.remove != undefined && nmCallTreeFuncData.remove.length > 0) { 553 let list = nmCallTreeFuncData.remove.map((item: any): any => { 554 return item.name; 555 }); 556 nmCallTreeFuncArgs.push({ funcName: 'resotreAllNode', funcArgs: [list] }); 557 nmCallTreeFuncArgs.push({ funcName: 'resetAllNode', funcArgs: [] }); 558 list.forEach((symbolName: string): void => { 559 nmCallTreeFuncArgs.push({ funcName: 'clearSplitMapData', funcArgs: [symbolName] }); 560 }); 561 } 562 } 563 return nmCallTreeFuncArgs; 564 } 565 566 private filterFuncBySelectType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] { 567 nmCallTreeFuncArgs.push({ 568 funcName: 'resotreAllNode', 569 funcArgs: [[nmCallTreeFuncData.item.name]], 570 }); 571 nmCallTreeFuncArgs.push({ 572 funcName: 'clearSplitMapData', 573 funcArgs: [nmCallTreeFuncData.item.name], 574 }); 575 nmCallTreeFuncArgs.push({ 576 funcName: 'splitTree', 577 funcArgs: [ 578 nmCallTreeFuncData.item.name, 579 nmCallTreeFuncData.item.select === '0', 580 nmCallTreeFuncData.item.type == 'symbol', 581 ], 582 }); 583 return nmCallTreeFuncArgs; 584 } 585 586 private filterFuncByCheckType(nmCallTreeFuncData: any, nmCallTreeFuncArgs: any[]): any[] { 587 if (nmCallTreeFuncData.item.checked) { 588 nmCallTreeFuncArgs.push({ 589 funcName: 'splitTree', 590 funcArgs: [ 591 nmCallTreeFuncData.item.name, 592 nmCallTreeFuncData.item.select === '0', 593 nmCallTreeFuncData.item.type === 'symbol', 594 ], 595 }); 596 } else { 597 nmCallTreeFuncArgs.push({ 598 funcName: 'resotreAllNode', 599 funcArgs: [[nmCallTreeFuncData.item.name]], 600 }); 601 nmCallTreeFuncArgs.push({ 602 funcName: 'resetAllNode', 603 funcArgs: [], 604 }); 605 nmCallTreeFuncArgs.push({ 606 funcName: 'clearSplitMapData', 607 funcArgs: [nmCallTreeFuncData.item.name], 608 }); 609 } 610 return nmCallTreeFuncArgs; 611 } 612 613 private initGetFilterByNMCallTreeFilter(nmCallTreeData: FilterData): void { 614 if ( 615 this.filterAllocationType !== nmCallTreeData.firstSelect || 616 this.filterNativeType !== nmCallTreeData.secondSelect || 617 this.filterResponseSelect !== nmCallTreeData.thirdSelect 618 ) { 619 this.filterAllocationType = nmCallTreeData.firstSelect || '0'; 620 this.filterNativeType = nmCallTreeData.secondSelect || '0'; 621 this.filterResponseSelect = nmCallTreeData.thirdSelect || '0'; 622 let thirdIndex = parseInt(nmCallTreeData.thirdSelect || '0'); 623 if (this.responseTypes.length > thirdIndex) { 624 this.filterResponseType = this.responseTypes[thirdIndex].key || -1; 625 } 626 this.searchValue = this.nmCallTreeFilter!.filterValue; 627 this.expressionStruct = new ParseExpression(this.searchValue).parse(); 628 this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData()); 629 } else if (this.searchValue !== this.nmCallTreeFilter!.filterValue) { 630 this.searchValue = this.nmCallTreeFilter!.filterValue; 631 this.expressionStruct = new ParseExpression(this.searchValue).parse(); 632 let nmArgs = []; 633 if (this.expressionStruct) { 634 this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData()); 635 this.lastIsExpression = true; 636 return; 637 } else { 638 if (this.lastIsExpression) { 639 this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData()); 640 this.lastIsExpression = false; 641 return; 642 } 643 nmArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] }); 644 nmArgs.push({ funcName: 'resetAllNode', funcArgs: [] }); 645 this.lastIsExpression = false; 646 } 647 this.getDataByWorker(nmArgs, (result: any[]): void => { 648 this.nmCallTreeTbl!.isSearch = true; 649 this.nmCallTreeTbl!.setStatus(result, true); 650 this.setLTableData(result); 651 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 652 this.switchFlameChart(nmCallTreeData); 653 }); 654 } else { 655 this.nmCallTreeTbl!.setStatus(this.nmCallTreeSource, true); 656 this.setLTableData(this.nmCallTreeSource); 657 this.switchFlameChart(nmCallTreeData); 658 } 659 } 660 661 private initCloseCallBackByHeadLine() { 662 //点击之后删除掉筛选条件 将所有重置 将目前的title隐藏 高度恢复 663 this.headLine!.closeCallback = () => { 664 this.headLine!.clear(); 665 this.searchValue = ''; 666 this.currentNMCallTreeFilter!.filterValue = ''; 667 this._filterData = undefined; 668 this.currentNMCallTreeFilter!.firstSelect = '0'; 669 this.currentNMCallTreeFilter!.secondSelect = '0'; 670 this.currentNMCallTreeFilter!.thirdSelect = '0'; 671 this.filterAllocationType = '0'; 672 this.refreshAllNode(this.nmCallTreeFilter!.getFilterTreeData(), true); 673 this.initFilterTypes(); 674 this.nmCallTreeFrameChart?.resizeChange(); 675 }; 676 } 677 678 connectedCallback(): void { 679 super.connectedCallback(); 680 this.nmCallTreeTbl!.addEventListener('row-click', this.nmCallTreeTblRowClickHandler); 681 this.filesystemTbr!.addEventListener('row-click', this.filesystemTbrRowClickHandler); 682 this.nmCallTreeTbl!.addEventListener('column-click', this.nmCallTreeTblColumnClickHandler); 683 let filterHeight = 0; 684 new ResizeObserver((entries: ResizeObserverEntry[]): void => { 685 let nmCallTreeTabFilter = this.shadowRoot!.querySelector('#nm-call-tree-filter') as HTMLElement; 686 if (nmCallTreeTabFilter.clientHeight > 0) { 687 filterHeight = nmCallTreeTabFilter.clientHeight; 688 } 689 if (this.parentElement!.clientHeight > filterHeight) { 690 nmCallTreeTabFilter.style.display = 'flex'; 691 } else { 692 nmCallTreeTabFilter.style.display = 'none'; 693 } 694 if (this.nmCallTreeTbl!.style.visibility === 'hidden') { 695 nmCallTreeTabFilter.style.display = 'none'; 696 } 697 if (this.parentElement?.clientHeight !== 0) { 698 if (this.isChartShow) { 699 this.nmCallTreeFrameChart?.updateCanvas(false, entries[0].contentRect.width); 700 this.nmCallTreeFrameChart?.calculateChartData(); 701 } 702 if (this.nmCallTreeTbl) { 703 // @ts-ignore 704 this.nmCallTreeTbl.shadowRoot.querySelector('.table').style.height = `${ 705 this.parentElement!.clientHeight - 10 - 35 706 }px`; 707 } 708 this.nmCallTreeTbl?.reMeauseHeight(); 709 if (this.filesystemTbr) { 710 // @ts-ignore 711 this.filesystemTbr.shadowRoot.querySelector('.table').style.height = `${ 712 this.parentElement!.clientHeight - 45 - 21 713 }px`; 714 } 715 this.filesystemTbr?.reMeauseHeight(); 716 this.nmCallTreeLoadingPage.style.height = `${this.parentElement!.clientHeight - 24}px`; 717 } 718 }).observe(this.parentElement!); 719 this.parentElement!.onscroll = (): void => { 720 this.nmCallTreeFrameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; 721 }; 722 } 723 724 disconnectedCallback() { 725 super.disconnectedCallback(); 726 this.nmCallTreeTbl!.removeEventListener('row-click', this.nmCallTreeTblRowClickHandler); 727 this.filesystemTbr!.removeEventListener('row-click', this.filesystemTbrRowClickHandler); 728 this.nmCallTreeTbl!.removeEventListener('column-click', this.nmCallTreeTblColumnClickHandler); 729 } 730 731 filesystemTbrRowClickHandler = (event: any): void => { 732 // @ts-ignore 733 let data = evt.detail.data as FileMerageBean; 734 this.nmCallTreeTbl?.clearAllSelection(data); 735 (data as any).isSelected = true; 736 this.nmCallTreeTbl!.scrollToData(data); 737 // @ts-ignore 738 if ((evt.detail as any).callBack) { 739 // @ts-ignore 740 (evt.detail as any).callBack(true); 741 } 742 }; 743 744 nmCallTreeTblColumnClickHandler = (event: any): void => { 745 // @ts-ignore 746 this.sortKey = evt.detail.key; 747 // @ts-ignore 748 this.sortType = evt.detail.sort; 749 // @ts-ignore 750 this.setLTableData(this.nmCallTreeSource, true); 751 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 752 }; 753 754 nmCallTreeTblRowClickHandler = (event: any): void => { 755 // @ts-ignore 756 let nmCallTreeData = event.detail.data as FileMerageBean; 757 this.setRightTableData(nmCallTreeData); 758 nmCallTreeData.isSelected = true; 759 this.currentSelectedData = nmCallTreeData; 760 this.filesystemTbr?.clearAllSelection(nmCallTreeData); 761 this.filesystemTbr?.setCurrentSelection(nmCallTreeData); 762 // @ts-ignore 763 if ((event.detail as any).callBack) { 764 // @ts-ignore 765 (event.detail as any).callBack(true); 766 } 767 document.dispatchEvent( 768 new CustomEvent('number_calibration', { 769 detail: { time: event.detail.tsArray, counts: event.detail.countArray }, 770 }) 771 ); 772 }; 773 774 private switchFlameChart(flameChartData?: any): void { 775 let nmCallTreePageTab = this.shadowRoot?.querySelector('#show_table'); 776 let nmCallTreePageChart = this.shadowRoot?.querySelector('#show_chart'); 777 if (!flameChartData || flameChartData.icon === 'block') { 778 nmCallTreePageChart?.setAttribute('class', 'show'); 779 nmCallTreePageTab?.setAttribute('class', ''); 780 this.isChartShow = true; 781 this.nmCallTreeFilter!.disabledMining = true; 782 this.showBottomMenu(this.needShowMenu); 783 this.nmCallTreeFrameChart?.calculateChartData(); 784 } else if (flameChartData.icon === 'tree') { 785 nmCallTreePageChart?.setAttribute('class', ''); 786 nmCallTreePageTab?.setAttribute('class', 'show'); 787 this.showBottomMenu(true); 788 this.isChartShow = false; 789 this.nmCallTreeFilter!.disabledMining = false; 790 this.nmCallTreeFrameChart!.clearCanvas(); 791 this.nmCallTreeTbl!.reMeauseHeight(); 792 } 793 } 794 795 private refreshAllNode(filterData: any, isAnalysisReset?: boolean): void { 796 let nmCallTreeArgs: any[] = []; 797 let isTopDown: boolean = !filterData.callTree[0]; 798 let isHideSystemLibrary = filterData.callTree[1]; 799 this.isHideThread = filterData.callTree[3]; 800 let list = filterData.dataMining.concat(filterData.dataLibrary); 801 let groupArgs = this.setGroupArgsByRefreshAllNode(); 802 if ((this.lastIsExpression && !this.expressionStruct) || isAnalysisReset) { 803 nmCallTreeArgs.push({ funcName: 'setSearchValue', funcArgs: [this.searchValue] }); 804 } 805 nmCallTreeArgs.push({ funcName: 'hideThread', funcArgs: [this.isHideThread] }); 806 nmCallTreeArgs.push( 807 { 808 funcName: 'groupCallchainSample', 809 funcArgs: [groupArgs], 810 }, 811 { 812 funcName: 'getCallChainsBySampleIds', 813 funcArgs: [isTopDown], 814 } 815 ); 816 this.filesystemTbr!.recycleDataSource = []; 817 if (isHideSystemLibrary) { 818 nmCallTreeArgs.push({ 819 funcName: 'hideSystemLibrary', 820 funcArgs: [], 821 }); 822 } 823 if (filterData.callTreeConstraints.checked) { 824 nmCallTreeArgs.push({ 825 funcName: 'hideNumMaxAndMin', 826 funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], 827 }); 828 } 829 nmCallTreeArgs.push({ funcName: 'splitAllProcess', funcArgs: [list] }); 830 nmCallTreeArgs.push({ funcName: 'resetAllNode', funcArgs: [] }); 831 this.getDataByWorker(nmCallTreeArgs, (result: any[]) => { 832 this.setLTableData(result); 833 this.nmCallTreeFrameChart!.data = this.nmCallTreeSource; 834 if (this.isChartShow) this.nmCallTreeFrameChart?.calculateChartData(); 835 }); 836 } 837 838 private setGroupArgsByRefreshAllNode(): Map<string, any> { 839 let groupArgs = new Map<string, any>(); 840 groupArgs.set('filterAllocType', this.filterAllocationType); 841 groupArgs.set('filterEventType', this.filterNativeType); 842 if (this.expressionStruct) { 843 groupArgs.set('filterExpression', this.expressionStruct); 844 groupArgs.set('filterResponseType', -1); 845 this.currentNMCallTreeFilter!.thirdSelect = '0'; 846 } else { 847 groupArgs.set('filterResponseType', this.filterResponseType); 848 } 849 groupArgs.set('leftNs', this.currentSelection?.leftNs || 0); 850 groupArgs.set('rightNs', this.currentSelection?.rightNs || 0); 851 let selections: Array<any> = []; 852 if (this.subTypeArr.length > 0) { 853 this.subTypeArr.map((memory): void => { 854 selections.push({ 855 memoryTap: memory, 856 }); 857 }); 858 } 859 groupArgs.set('statisticsSelection', selections); 860 if (this._filterData) { 861 groupArgs.set('filterByTitleArr', this._filterData); 862 } 863 groupArgs.set( 864 'nativeHookType', 865 this.currentSelection!.nativeMemory.length > 0 ? 'native-hook' : 'native-hook-statistic' 866 ); 867 return groupArgs; 868 } 869 870 setLTableData(resultData: any[], sort?: boolean): void { 871 if (sort) { 872 this.nmCallTreeSource = this.sortTree(resultData); 873 } else { 874 if (resultData && resultData[0]) { 875 this.nmCallTreeSource = 876 this.currentSelection!.nativeMemory.length > 0 && !this.isHideThread 877 ? this.sortTree(resultData) 878 : this.sortTree(resultData[0].children || []); 879 } else { 880 this.nmCallTreeSource = []; 881 } 882 } 883 this.nmCallTreeTbl!.recycleDataSource = this.nmCallTreeSource; 884 } 885 886 sortTree(arr: Array<any>): Array<any> { 887 let nmCallTreeSortArr = arr.sort((callTreeLeftData, callTreeRightData): number => { 888 if (this.sortKey === 'heapSizeStr' || this.sortKey === 'heapPercent') { 889 if (this.sortType === 0) { 890 return callTreeRightData.size - callTreeLeftData.size; 891 } else if (this.sortType === 1) { 892 return callTreeLeftData.size - callTreeRightData.size; 893 } else { 894 return callTreeRightData.size - callTreeLeftData.size; 895 } 896 } else { 897 if (this.sortType === 0) { 898 return callTreeRightData.count - callTreeLeftData.count; 899 } else if (this.sortType === 1) { 900 return callTreeLeftData.count - callTreeRightData.count; 901 } else { 902 return callTreeRightData.count - callTreeLeftData.count; 903 } 904 } 905 }); 906 nmCallTreeSortArr.map((call): void => { 907 call.children = this.sortTree(call.children); 908 }); 909 return nmCallTreeSortArr; 910 } 911 912 getDataByWorker(args: any[], handler: Function): void { 913 this.loadingList.push(1); 914 this.nmCallTreeProgressEL!.loading = true; 915 this.nmCallTreeLoadingPage.style.visibility = 'visible'; 916 procedurePool.submitWithName( 917 'logic0', 918 'native-memory-calltree-action', 919 args, 920 undefined, 921 (callTreeActionResults: any): void => { 922 handler(callTreeActionResults); 923 this.loadingList.splice(0, 1); 924 if (this.loadingList.length === 0) { 925 this.nmCallTreeProgressEL!.loading = false; 926 this.nmCallTreeLoadingPage.style.visibility = 'hidden'; 927 } 928 } 929 ); 930 } 931 932 getDataByWorkerQuery(args: any, handler: Function): void { 933 this.loadingList.push(1); 934 this.nmCallTreeProgressEL!.loading = true; 935 this.nmCallTreeLoadingPage.style.visibility = 'visible'; 936 procedurePool.submitWithName( 937 'logic0', 938 this.currentSelection!.nativeMemory!.length > 0 939 ? 'native-memory-queryCallchainsSamples' 940 : 'native-memory-queryStatisticCallchainsSamples', 941 args, 942 undefined, 943 (callChainsResults: any): void => { 944 handler(callChainsResults); 945 this.loadingList.splice(0, 1); 946 if (this.loadingList.length === 0) { 947 this.nmCallTreeProgressEL!.loading = false; 948 this.nmCallTreeLoadingPage.style.visibility = 'hidden'; 949 } 950 } 951 ); 952 } 953 954 initHtml(): string { 955 return TabPaneNMCallTreeHtml; 956 } 957} 958