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