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