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.js'; 17import { LitTabs } from '../../../../base-ui/tabs/lit-tabs.js'; 18import { LitTabpane } from '../../../../base-ui/tabs/lit-tabpane.js'; 19import { BoxJumpParam, SelectionParam } from '../../../bean/BoxSelection.js'; 20import { TabPaneCurrentSelection } from '../sheet/TabPaneCurrentSelection.js'; 21import { TabPaneFlag } from '../timer-shaft/TabPaneFlag.js'; 22import { Flag } from '../timer-shaft/Flag.js'; 23import { WakeupBean } from '../../../bean/WakeupBean.js'; 24import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; 25import { tabConfig } from './TraceSheetConfig.js'; 26import { TabPaneBoxChild } from '../sheet/cpu/TabPaneBoxChild.js'; 27import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; 28import { CpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerFreq.js'; 29import { CpuFreqLimitsStruct } from '../../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; 30import { ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread.js'; 31import { FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc.js'; 32import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem.js'; 33import { CpuStateStruct } from '../../../database/ui-worker/ProcedureWorkerCpuState.js'; 34import { ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock.js'; 35import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq.js'; 36import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank.js'; 37import { HeapStruct } from '../../../database/ui-worker/ProcedureWorkerHeap.js'; 38import { LitTable } from '../../../../base-ui/table/lit-table.js'; 39import { queryNativeHookResponseTypes, threadPool } from '../../../database/SqlLite.js'; 40import { HeapSnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; 41import { TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis.js'; 42import { TabPaneCurrent } from '../sheet/TabPaneCurrent.js'; 43import { SlicesTime } from '../timer-shaft/SportRuler.js'; 44import { AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup.js'; 45import { SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit.js'; 46import { FrameAnimationStruct } from '../../../database/ui-worker/ProcedureWorkerFrameAnimation.js'; 47import { TraceRow } from './TraceRow.js'; 48import { FrameDynamicStruct } from '../../../database/ui-worker/ProcedureWorkerFrameDynamic.js'; 49import { TabPaneFrameDynamic } from '../sheet/frame/TabPaneFrameDynamic.js'; 50import { FrameSpacingStruct } from '../../../database/ui-worker/ProcedureWorkerFrameSpacing.js'; 51import { TabFrameSpacing } from '../sheet/frame/TabFrameSpacing.js'; 52import { procedurePool } from '../../../database/Procedure.js'; 53import { JsCpuProfilerChartFrame } from '../../../bean/JsStruct.js'; 54import { TabPaneJsCpuTopDown } from '../sheet/ark-ts/TabPaneJsCpuCallTree.js'; 55import { TabPaneComparison } from '../sheet/ark-ts/TabPaneComparison.js'; 56import { TabPaneSummary } from '../sheet/ark-ts/TabPaneSummary.js'; 57import { TabPaneGpuClickSelect } from '../sheet/gpu/TabPaneGpuClickSelect.js'; 58import { TabPanePurgTotalSelection } from '../sheet/ability/TabPanePurgTotalSelection.js'; 59import { TabPanePurgPinSelection } from '../sheet/ability/TabPanePurgPinSelection.js'; 60import { TabPaneVmTrackerShmSelection } from '../sheet/vmtracker/TabPaneVmTrackerShmSelection.js'; 61import { TabPaneSmapsStatistics } from '../sheet/smaps/TabPaneSmapsStatistics.js'; 62import { TabPaneSmapsComparison } from '../sheet/smaps/TabPaneSmapsComparison.js'; 63import { SnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerSnapshot.js'; 64import { TabPaneDmaSelectAbility } from '../sheet/ability/TabPaneDmaSelectAbility.js'; 65import { TabPaneGpuMemorySelectAbility } from '../sheet/ability/TabPaneGpuMemorySelectAbility.js'; 66import { TabPaneDmaSelectVmTracker } from '../sheet/vmtracker/TabPaneDmaSelectVmTracker.js'; 67import { TabPanePurgTotalComparisonAbility } from '../sheet/ability/TabPanePurgTotalComparisonAbility.js'; 68import { TabPanePurgPinComparisonAbility } from '../sheet/ability/TabPanePurgPinComparisonAbility.js'; 69import { TabPanePurgTotalComparisonVM } from '../sheet/vmtracker/TabPanePurgTotalComparisonVM.js'; 70import { TabPanePurgPinComparisonVM } from '../sheet/vmtracker/TabPanePurgPinComparisonVM.js'; 71import { TabPaneDmaAbilityComparison } from '../sheet/ability/TabPaneDmaAbilityComparison.js'; 72import { TabPaneGpuMemoryComparison } from '../sheet/ability/TabPaneGpuMemoryComparison.js'; 73import { TabPaneDmaVmTrackerComparison } from '../sheet/vmtracker/TabPaneDmaVmTrackerComparison.js'; 74import { TabPaneGpuMemorySelectVmTracker } from '../sheet/vmtracker/TabPaneGpuMemorySelectVmTracker.js'; 75import { TabPaneGpuMemoryVmTrackerComparison } from '../sheet/vmtracker/TabPaneGpuMemoryVmTrackerComparison.js'; 76import { TabPaneVmTrackerShmComparison } from '../sheet/vmtracker/TabPaneVmTrackerShmComparison.js'; 77import { TabPaneJsCpuStatistics } from '../sheet/ark-ts/TabPaneJsCpuStatistics.js'; 78import { TabPaneGpuClickSelectComparison } from '../sheet/gpu/TabPaneGpuClickSelectComparison.js'; 79 80@element('trace-sheet') 81export class TraceSheet extends BaseElement { 82 private litTabs: LitTabs | undefined | null; 83 private importDiv: HTMLDivElement | undefined | null; 84 private nav: HTMLDivElement | undefined | null; 85 private selection: SelectionParam | undefined | null; 86 private currentPaneID: string = 'current-selection'; 87 private fragment: DocumentFragment | undefined; 88 89 static get observedAttributes(): string[] { 90 return ['mode']; 91 } 92 93 buildTabs(litTabs: LitTabs | undefined | null): void { 94 this.fragment = document.createDocumentFragment(); 95 Reflect.ownKeys(tabConfig).forEach((key, index) => { 96 let pane = new LitTabpane(); 97 pane.id = key.toString(); 98 pane.className = 'tabHeight'; 99 pane.tab = tabConfig[key].title; 100 pane.hidden = true; 101 pane.key = `${tabConfig[key].key || index}`; 102 let cls = tabConfig[key].type; 103 let node = new cls(); 104 pane.append(node); 105 this.fragment?.appendChild(pane); 106 }); 107 litTabs!.appendChild(this.fragment); 108 } 109 110 displayTab<T>(...names: string[]): T { 111 this.setAttribute('mode', 'max'); 112 this.showUploadSoBt(null); 113 this.shadowRoot 114 ?.querySelectorAll<LitTabpane>('#tabs lit-tabpane') 115 .forEach((it) => (it.hidden = !names.some((k) => k === it.id))); 116 let litTabpane = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[id='${names[0]}']`); 117 this.shadowRoot?.querySelector<LitTabs>('#tabs')?.activePane(litTabpane!.key); 118 return litTabpane!.children.item(0) as unknown as T; 119 } 120 121 getComponentByID<T>(id: string): T { 122 return this.getPaneByID(id)!.children.item(0) as unknown as T; 123 } 124 125 getPaneByID(id: string): LitTabpane { 126 return this.shadowRoot!.querySelector(`#${id}`)!; 127 } 128 129 initElements(): void { 130 this.litTabs = this.shadowRoot?.querySelector('#tabs'); 131 this.importDiv = this.shadowRoot?.querySelector('#import_div'); 132 this.buildTabs(this.litTabs); 133 let minBtn = this.shadowRoot?.querySelector('#min-btn'); 134 minBtn?.addEventListener('click', () => {}); 135 this.litTabs!.onTabClick = (e: any): void => this.loadTabPaneData(e.detail.key); 136 this.litTabs!.addEventListener('close-handler', () => { 137 Reflect.ownKeys(tabConfig) 138 .reverse() 139 .forEach((id) => { 140 let element = tabConfig[id]; 141 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 142 if (element.require) { 143 pane!.hidden = !element.require(this.selection); 144 } else { 145 pane!.hidden = true; 146 } 147 }); 148 this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`); 149 }); 150 this.getComponentByID<any>('box-spt')!.addEventListener('row-click', this.rowClickHandler.bind(this)); 151 this.getComponentByID<any>('box-pts')!.addEventListener('row-click', this.rowClickHandler.bind(this)); 152 this.getComponentByID<any>('box-native-statstics')!.addEventListener('row-click', (e: any) => { 153 this.selection!.statisticsSelectData = e.detail; 154 let pane = this.getPaneByID('box-native-memory'); 155 this.litTabs?.activeByKey(pane.key); 156 (pane.children.item(0) as any)!.fromStastics(this.selection); 157 }); 158 this.getComponentByID<any>('box-virtual-memory-statistics')!.addEventListener('row-click', (e: any) => { 159 this.selection!.fileSystemVMData = { path: e.detail.path }; 160 let pane = this.getPaneByID('box-vm-events'); 161 this.litTabs?.activeByKey(pane.key); 162 if (e.detail.path) { 163 (pane.children.item(0) as any)!.fromStastics(this.selection); 164 } 165 }); 166 this.getComponentByID<any>('box-io-tier-statistics')!.addEventListener('row-click', (e: any) => { 167 this.selection!.fileSystemIoData = { path: e.detail.path }; 168 let pane = this.getPaneByID('box-io-events'); 169 this.litTabs?.activeByKey(pane.key); 170 if (e.detail.path) { 171 (pane.children.item(0) as any)!.fromStastics(this.selection); 172 } 173 }); 174 this.getComponentByID<any>('box-file-system-statistics')!.addEventListener('row-click', (e: any) => { 175 this.selection!.fileSystemFsData = e.detail.data; 176 let pane = this.getPaneByID('box-file-system-event'); 177 this.litTabs?.activeByKey(pane.key); 178 if (e.detail.data) { 179 (pane.children.item(0) as any)!.fromStastics(this.selection); 180 } 181 }); 182 } 183 connectedCallback(): void { 184 this.nav = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.tab-nav-container'); 185 let tabs: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#tabs'); 186 let navRoot: HTMLDivElement | null | undefined = this.shadowRoot 187 ?.querySelector('#tabs') 188 ?.shadowRoot?.querySelector('.nav-root'); 189 let search: HTMLDivElement | undefined | null = document 190 .querySelector('body > sp-application') 191 ?.shadowRoot?.querySelector('div > div.search-container'); 192 let timerShaft: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.timer-shaft'); 193 let spacer: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.spacer'); 194 let rowsPaneEL: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.rows-pane'); 195 196 let borderTop: number = 1; 197 let initialHeight = { tabs: `calc(30vh + 39px)`, node: '30vh' }; 198 this.nav!.onmousedown = (event): void => { 199 (window as any).isSheetMove = true; 200 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 201 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 202 let preY = event.pageY; 203 let preHeight = tabs!.offsetHeight; 204 document.onmousemove = function (event): void { 205 let moveY: number = preHeight - (event.pageY - preY); 206 litTabpane!.forEach((node: HTMLDivElement) => { 207 if (spacer!.offsetHeight > rowsPaneEL!.offsetHeight) { 208 tabs!.style.height = moveY + 'px'; 209 node!.style.height = moveY - navRoot!.offsetHeight + 'px'; 210 tabsPackUp!.name = 'down'; 211 } else if ( 212 navRoot!.offsetHeight <= moveY && 213 search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight <= 214 window.innerHeight - moveY 215 ) { 216 tabs!.style.height = moveY + 'px'; 217 node!.style.height = moveY - navRoot!.offsetHeight + 'px'; 218 tabsPackUp!.name = 'down'; 219 } else if (navRoot!.offsetHeight >= moveY) { 220 tabs!.style.height = navRoot!.offsetHeight + 'px'; 221 node!.style.height = '0px'; 222 tabsPackUp!.name = 'up'; 223 } else if ( 224 search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight >= 225 window.innerHeight - moveY 226 ) { 227 tabs!.style.height = 228 window.innerHeight - 229 search!.offsetHeight - 230 timerShaft!.offsetHeight - 231 borderTop - 232 spacer!.offsetHeight + 233 'px'; 234 node!.style.height = 235 window.innerHeight - 236 search!.offsetHeight - 237 timerShaft!.offsetHeight - 238 navRoot!.offsetHeight - 239 borderTop - 240 spacer!.offsetHeight + 241 'px'; 242 tabsPackUp!.name = 'down'; 243 } 244 }); 245 }; 246 document.onmouseup = function (): void { 247 setTimeout(() => { 248 (window as any).isSheetMove = false; 249 }, 100); 250 litTabpane!.forEach((node: HTMLDivElement) => { 251 if (node!.style.height !== '0px' && tabs!.style.height != '') { 252 initialHeight.node = node!.style.height; 253 initialHeight.tabs = tabs!.style.height; 254 } 255 }); 256 this.onmousemove = null; 257 this.onmouseup = null; 258 }; 259 }; 260 let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#max-btn'); 261 let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#min-btn'); 262 let importFileBt: HTMLInputElement | undefined | null = 263 this.shadowRoot?.querySelector<HTMLInputElement>('#import-file'); 264 let exportDataBt: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#export-btn'); 265 tabsOpenUp!.onclick = (): void => { 266 tabs!.style.height = window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - borderTop + 'px'; 267 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 268 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 269 litTabpane!.forEach((node: HTMLDivElement) => { 270 node!.style.height = 271 window.innerHeight - 272 search!.offsetHeight - 273 timerShaft!.offsetHeight - 274 navRoot!.offsetHeight - 275 borderTop + 276 'px'; 277 initialHeight.node = node!.style.height; 278 }); 279 initialHeight.tabs = tabs!.style.height; 280 tabsPackUp!.name = 'down'; 281 }; 282 tabsPackUp!.onclick = (): void => { 283 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 284 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 285 if (tabsPackUp!.name == 'down') { 286 tabs!.style.height = navRoot!.offsetHeight + 'px'; 287 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = '0px')); 288 tabsPackUp!.name = 'up'; 289 (window as any).isPackUpTable = true; 290 } else { 291 tabsPackUp!.name = 'down'; 292 tabs!.style.height = initialHeight.tabs; 293 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = initialHeight.node)); 294 } 295 }; 296 importFileBt!.addEventListener('change', (event) => { 297 let files = importFileBt?.files; 298 if (files) { 299 let fileList: Array<File> = []; 300 for (let file of files) { 301 if (file.name.endsWith('.so')) { 302 fileList.push(file); 303 } 304 } 305 if (fileList.length > 0) { 306 importFileBt!.disabled = true; 307 window.publish(window.SmartEvent.UI.Loading, true); 308 threadPool.submit( 309 'upload-so', 310 '', 311 fileList, 312 (res: string) => { 313 importFileBt!.disabled = false; 314 if (res === 'ok') { 315 window.publish(window.SmartEvent.UI.UploadSOFile, {}); 316 } else { 317 window.publish(window.SmartEvent.UI.Error, 'parse so file failed!'); 318 } 319 }, 320 'upload-so' 321 ); 322 } 323 fileList.length = 0; 324 } 325 importFileBt!.files = null; 326 importFileBt!.value = ''; 327 }); 328 exportDataBt!.onclick = (): void => { 329 let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!); 330 if (currentTab) { 331 let tables = Array.from( 332 (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 333 ); 334 for (let table of tables) { 335 if (!table.hasAttribute('hideDownload')) { 336 table.exportData(); 337 } 338 } 339 } 340 }; 341 } 342 343 getTabpaneByKey(key: string): LitTabpane | undefined { 344 let tabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 345 return tabs.find((it) => it.key === key); 346 } 347 348 initHtml(): string { 349 return ` 350 <style> 351 :host([mode='hidden']){ 352 display: none; 353 } 354 :host{ 355 display: block; 356 background-color: rebeccapurple; 357 } 358 .tabHeight{ 359 height: 30vh; 360 background-color: var(--dark-background,#FFFFFF); 361 } 362 </style> 363 <div id="container" style="border-top: 1px solid var(--dark-border1,#D5D5D5);"> 364 <lit-tabs id="tabs" position="top-left" activekey="1" mode="card" > 365 <div slot="right" style="margin: 0 10px; color: var(--dark-icon,#606060);display: flex;align-items: center;"> 366 <div title="SO导入" id="import_div" style="width: 20px;height: 20px;display: flex;flex-direction: row;margin-right: 10px"> 367 <input id="import-file" style="display: none;pointer-events: none" type="file" webkitdirectory> 368 <label style="width: 20px;height: 20px;cursor: pointer;" for="import-file"> 369 <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20"> 370 </lit-icon> 371 </label> 372 </div> 373 <lit-icon title="下载数据" id="export-btn" name="import-so" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 374 </lit-icon> 375 <lit-icon title="最大化" id="max-btn" name="vertical-align-top" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 376 </lit-icon> 377 <lit-icon title="最小化" id="min-btn" name="down" style="font-weight: bold;cursor: pointer;" size="20"> 378 </lit-icon> 379 </div> 380 </lit-tabs> 381 </div>`; 382 } 383 displayCurrent = (data: SlicesTime): void => 384 this.displayTab<TabPaneCurrent>('tabpane-current').setCurrentSlicesTime(data); 385 displayThreadData = ( 386 data: ThreadStruct, 387 scrollCallback: ((e: ThreadStruct) => void) | undefined, 388 scrollWakeUp: (d: any) => void | undefined, 389 scrollPreviousData: (d: ThreadStruct) => void, 390 scrollNextData: (d: ThreadStruct) => void 391 ) => 392 this.displayTab<TabPaneCurrentSelection>('current-selection').setThreadData( 393 data, 394 scrollCallback, 395 scrollWakeUp, 396 scrollPreviousData, 397 scrollNextData 398 ); 399 displayMemData = (data: ProcessMemStruct): void => 400 this.displayTab<TabPaneCurrentSelection>('current-selection').setMemData(data); 401 displayClockData = (data: ClockStruct): void => 402 this.displayTab<TabPaneCurrentSelection>('current-selection').setClockData(data); 403 displayIrqData = (data: IrqStruct): void => 404 this.displayTab<TabPaneCurrentSelection>('current-selection').setIrqData(data); 405 displayStartupData = (data: AppStartupStruct, scrollCallback: Function): void => 406 this.displayTab<TabPaneCurrentSelection>('current-selection').setStartupData(data, scrollCallback); 407 displayStaticInitData = (data: SoStruct, scrollCallback: Function): void => 408 this.displayTab<TabPaneCurrentSelection>('current-selection').setStaticInitData(data, scrollCallback); 409 410 displayNativeHookData = (data: HeapStruct, rowType: string): void => { 411 let val = new SelectionParam(); 412 val.nativeMemoryStatistic.push(rowType); 413 val.nativeMemory = []; 414 val.leftNs = data.startTime!; 415 val.rightNs = data.startTime! + data.dur! - 1; 416 this.selection = val; 417 this.displayTab<TabPaneNMStatisticAnalysis>('box-native-statistic-analysis', 'box-native-calltree').data = val; 418 this.showUploadSoBt(val); 419 }; 420 421 displayGpuSelectedData = (type: string, startTs: number, dataList: Array<SnapshotStruct>) => { 422 this.displayTab<TabPaneGpuClickSelectComparison>('gpu-click-select-comparison').getGpuClickDataByDB( 423 type, 424 startTs, 425 dataList 426 ); 427 let dataObject = { type: type, startTs: startTs }; 428 this.displayTab<TabPaneGpuClickSelect>('gpu-click-select', 'gpu-click-select-comparison').gpuClickData(dataObject); 429 }; 430 431 displayFuncData = (names: string[], data: FuncStruct, scrollCallback: Function): void => 432 this.displayTab<TabPaneCurrentSelection>(...names).setFunctionData(data, scrollCallback); 433 displayCpuData = ( 434 data: CpuStruct, 435 callback: ((data: WakeupBean | null) => void) | undefined = undefined, 436 scrollCallback?: (data: CpuStruct) => void 437 ): void => this.displayTab<TabPaneCurrentSelection>('current-selection').setCpuData(data, callback, scrollCallback); 438 displayJankData = ( 439 data: JankStruct, 440 callback: ((data: Array<any>) => void) | undefined = undefined, 441 scrollCallback: ((e: JankStruct) => void) | undefined 442 ) => this.displayTab<TabPaneCurrentSelection>('current-selection').setJankData(data, callback, scrollCallback); 443 displayShmData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 444 this.displayTab<TabPaneVmTrackerShmComparison>('box-vmtracker-shm-comparison').setShmData(data, dataList); 445 this.displayTab<TabPaneVmTrackerShmSelection>( 446 'box-vmtracker-shm-selection', 447 'box-vmtracker-shm-comparison' 448 ).setShmData(data, dataList); 449 }; 450 displaySmapsData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 451 let val = new SelectionParam(); 452 val.smapsType = []; 453 val.leftNs = data.startNs; 454 this.selection = val; 455 val.smapsType = []; 456 this.displayTab<TabPaneSmapsComparison>('box-smaps-comparison').setData(val, dataList); 457 this.displayTab<TabPaneSmapsStatistics>('box-smaps-statistics', 'box-smaps-record', 'box-smaps-comparison').data = 458 val; 459 }; 460 displaySnapshotData = ( 461 data: HeapSnapshotStruct, 462 dataList: Array<HeapSnapshotStruct>, 463 scrollCallback?: (data: HeapSnapshotStruct, dataList: Array<HeapSnapshotStruct>) => void 464 ): void => { 465 if (dataList.length > 1) { 466 this.displayTab<TabPaneSummary>('box-heap-summary', 'box-heap-comparison').setSnapshotData( 467 data, 468 dataList, 469 scrollCallback 470 ); 471 let nav = this.shadowRoot!.querySelector('#tabs')!.shadowRoot!.querySelector( 472 '#nav > #nav-comparison' 473 ) as HTMLDivElement; 474 let tabPaneComparison = this.shadowRoot!.querySelector( 475 '#box-heap-comparison > tabpane-comparison' 476 ) as TabPaneComparison; 477 nav!.onclick = (): void => { 478 tabPaneComparison.initComparison(data, dataList); 479 }; 480 } else { 481 this.displayTab<TabPaneSummary>('box-heap-summary').setSnapshotData(data, dataList, scrollCallback); 482 } 483 }; 484 displayFlagData = (flagObj: Flag): void => this.displayTab<TabPaneFlag>('box-flag').setFlagObj(flagObj); 485 displayFreqData = (): CpuFreqStruct | undefined => 486 (this.displayTab<TabPaneCurrentSelection>('box-freq').data = CpuFreqStruct.selectCpuFreqStruct); 487 displayCpuStateData = (): CpuStateStruct | undefined => 488 (this.displayTab<TabPaneCurrentSelection>('cpu-state-click').data = CpuStateStruct.selectStateStruct); 489 displayFreqLimitData = (): CpuFreqLimitsStruct | undefined => 490 (this.displayTab<TabPaneCurrentSelection>('box-freq-limit').data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct); 491 492 displayFrameAnimationData = (data: FrameAnimationStruct): Promise<void> => 493 this.displayTab<TabPaneCurrentSelection>('current-selection').setFrameAnimationData(data); 494 displayFrameDynamicData = (row: TraceRow<FrameDynamicStruct>, data: FrameDynamicStruct): void => 495 this.displayTab<TabPaneFrameDynamic>('box-frame-dynamic').buildDynamicTable([data], true); 496 displayFrameSpacingData = (data: FrameSpacingStruct): void => 497 this.displayTab<TabFrameSpacing>('box-frames-spacing').setFrameSpacingData(data); 498 displayJsProfilerData = (data: Array<JsCpuProfilerChartFrame>): void => { 499 let val = new SelectionParam(); 500 val.jsCpuProfilerData = data; 501 this.selection = val; 502 this.displayTab<TabPaneJsCpuStatistics>( 503 'box-js-Profiler-statistics', 504 'box-js-Profiler-bottom-up', 505 'box-js-Profiler-top-down' 506 ).data = data; 507 }; 508 displayPurgTotalAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 509 data.type = 'ability'; 510 this.displayTab<TabPanePurgTotalComparisonAbility>('box-purgeable-total-comparison-ability').totalData( 511 data, 512 dataList 513 ); 514 this.displayTab<TabPanePurgTotalSelection>( 515 'box-purgeable-total-selection', 516 'box-purgeable-total-comparison-ability' 517 ).data = data; 518 }; 519 displayPurgPinAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 520 data.type = 'ability'; 521 this.displayTab<TabPanePurgPinComparisonAbility>('box-purgeable-pin-comparison-ability').totalData(data, dataList); 522 this.displayTab<TabPanePurgPinSelection>( 523 'box-purgeable-pin-selection', 524 'box-purgeable-pin-comparison-ability' 525 ).data = data; 526 }; 527 displayPurgTotalVMData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 528 data.type = 'VM'; 529 this.displayTab<TabPanePurgTotalComparisonVM>('box-purgeable-total-comparison-vm').totalData(data, dataList); 530 this.displayTab<TabPanePurgTotalSelection>( 531 'box-purgeable-total-selection', 532 'box-purgeable-total-comparison-vm' 533 ).data = data; 534 }; 535 displayPurgPinVMData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>) => { 536 data.type = 'VM'; 537 this.displayTab<TabPanePurgPinComparisonVM>('box-purgeable-pin-comparison-vm').totalData(data, dataList); 538 this.displayTab<TabPanePurgPinSelection>('box-purgeable-pin-selection', 'box-purgeable-pin-comparison-vm').data = 539 data; 540 }; 541 displayDmaAbility = (data: number, dataList: Array<SnapshotStruct>) => { 542 if (dataList.length > 0) { 543 this.displayTab<TabPaneDmaAbilityComparison>('box-dma-ability-comparison').comparisonDataByDB(data, dataList); 544 this.displayTab<TabPaneDmaSelectAbility>( 545 'box-dma-selection-ability', 546 'box-dma-ability-comparison' 547 ).queryDmaClickDataByDB(data); 548 } else { 549 this.displayTab<TabPaneDmaSelectAbility>('box-dma-selection-ability').queryDmaClickDataByDB(data); 550 } 551 }; 552 displayDmaVmTracker = (data: number, dataList: Array<SnapshotStruct>) => { 553 if (dataList.length > 0) { 554 this.displayTab<TabPaneDmaVmTrackerComparison>('box-vmTracker-comparison').comparisonDataByDB(data, dataList); 555 this.displayTab<TabPaneDmaSelectVmTracker>( 556 'box-dma-selection-vmTracker', 557 'box-vmTracker-comparison' 558 ).queryDmaVmTrackerClickDataByDB(data); 559 } else { 560 this.displayTab<TabPaneDmaSelectVmTracker>('box-dma-selection-vmTracker').queryDmaVmTrackerClickDataByDB(data); 561 } 562 }; 563 displayGpuMemoryAbility = (data: number, dataList: Array<SnapshotStruct>) => { 564 if (dataList.length > 0) { 565 this.displayTab<TabPaneGpuMemoryComparison>('box-gpu-memory-comparison').comparisonDataByDB(data, dataList); 566 this.displayTab<TabPaneGpuMemorySelectAbility>( 567 'box-gpu-memory-selection-ability', 568 'box-gpu-memory-comparison' 569 ).queryGpuMemoryClickDataByDB(data); 570 } else { 571 this.displayTab<TabPaneGpuMemorySelectAbility>('box-gpu-memory-selection-ability').data = data; 572 } 573 }; 574 displayGpuMemoryVmTracker = (data: number, dataList: Array<SnapshotStruct>) => { 575 if (dataList.length > 0) { 576 this.displayTab<TabPaneGpuMemoryVmTrackerComparison>('box-gpu-memory-vmTracker-comparison').comparisonDataByDB( 577 data, 578 dataList 579 ); 580 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 581 'box-gpu-memory-selection-vmTracker', 582 'box-gpu-memory-vmTracker-comparison' 583 ).queryGpuMemoryVmTrackerClickDataByDB(data); 584 } else { 585 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 586 'box-gpu-memory-selection-vmTracker' 587 ).queryGpuMemoryVmTrackerClickDataByDB(data); 588 } 589 }; 590 591 rangeSelect(selection: SelectionParam, restore = false): boolean { 592 this.selection = selection; 593 this.showUploadSoBt(selection); 594 Reflect.ownKeys(tabConfig) 595 .reverse() 596 .forEach((id) => { 597 let element = tabConfig[id]; 598 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 599 if (pane) { 600 pane.hidden = !(element.require && element.require(selection)); 601 } 602 }); 603 if (restore) { 604 if (this.litTabs?.activekey) { 605 this.loadTabPaneData(this.litTabs?.activekey); 606 this.setAttribute('mode', 'max'); 607 return true; 608 } else { 609 this.setAttribute('mode', 'hidden'); 610 return false; 611 } 612 } else { 613 let firstPane = this.shadowRoot!.querySelector<LitTabpane>(`lit-tabpane[hidden='false']`); 614 if (firstPane) { 615 this.litTabs?.activeByKey(firstPane.key); 616 this.loadTabPaneData(firstPane.key); 617 this.setAttribute('mode', 'max'); 618 return true; 619 } else { 620 this.setAttribute('mode', 'hidden'); 621 return false; 622 } 623 } 624 } 625 626 updateRangeSelect(): boolean { 627 if ( 628 this.selection && 629 (this.selection.nativeMemory.length > 0 || 630 this.selection.nativeMemoryStatistic.length > 0 || 631 this.selection.perfSampleIds.length > 0 || 632 this.selection.fileSystemType.length > 0 || 633 this.selection.fsCount > 0 || 634 this.selection.fileSysVirtualMemory || 635 this.selection.vmCount > 0 || 636 this.selection.diskIOLatency || 637 this.selection.diskIOipids.length > 0) 638 ) { 639 let param: SelectionParam = new SelectionParam(); 640 Object.assign(param, this.selection); 641 if (param.nativeMemory.length > 0 || param.nativeMemoryStatistic.length > 0) { 642 this.initFilterLibList(param); 643 } 644 this.rangeSelect(param, true); 645 return true; 646 } else { 647 return false; 648 } 649 } 650 651 initFilterLibList(param: SelectionParam | any) { 652 let nmTypes: Array<string> = []; 653 if (param.nativeMemory.indexOf('All Heap & Anonymous VM') != -1) { 654 nmTypes.push("'AllocEvent'"); 655 nmTypes.push("'MmapEvent'"); 656 } else { 657 if (param.nativeMemory.indexOf('All Heap') != -1) { 658 nmTypes.push("'AllocEvent'"); 659 } 660 if (param.nativeMemory.indexOf('All Anonymous VM') != -1) { 661 nmTypes.push("'MmapEvent'"); 662 } 663 } 664 queryNativeHookResponseTypes(param.leftNs, param.rightNs, nmTypes).then((res) => { 665 procedurePool.submitWithName('logic1', 'native-memory-init-responseType', res, undefined, () => {}); 666 }); 667 } 668 669 showUploadSoBt(selection: SelectionParam | null | undefined): void { 670 if ( 671 selection && 672 (selection.nativeMemory.length > 0 || 673 selection.nativeMemoryStatistic.length > 0 || 674 selection.perfSampleIds.length > 0 || 675 selection.fileSystemType.length > 0 || 676 selection.fsCount > 0 || 677 selection.fileSysVirtualMemory || 678 selection.vmCount > 0 || 679 selection.diskIOLatency || 680 selection.diskIOipids.length > 0) 681 ) { 682 this.importDiv!.style.display = 'flex'; 683 } else { 684 this.importDiv!.style.display = 'none'; 685 } 686 } 687 688 loadTabPaneData(key: string): void { 689 let component: any = this.shadowRoot 690 ?.querySelector<LitTabpane>(`#tabs lit-tabpane[key='${key}']`) 691 ?.children.item(0); 692 if (component) { 693 component.data = this.selection; 694 } 695 } 696 697 rowClickHandler(e: any): void { 698 this.currentPaneID = e.target.parentElement.id; 699 this.shadowRoot!.querySelectorAll<LitTabpane>(`lit-tabpane`).forEach((it) => 700 it.id != this.currentPaneID ? (it.hidden = true) : (it.hidden = false) 701 ); 702 let pane = this.getPaneByID('box-cpu-child'); 703 pane.closeable = true; 704 pane.hidden = false; 705 this.litTabs!.activeByKey(pane.key); 706 pane.tab = e.detail.title; 707 let param = new BoxJumpParam(); 708 param.leftNs = this.selection!.leftNs; 709 param.rightNs = this.selection!.rightNs; 710 param.state = e.detail.state; 711 param.threadId = e.detail.threadId; 712 param.processId = e.detail.processId; 713 (pane.children.item(0) as TabPaneBoxChild).data = param; 714 } 715 716 clearMemory(): void { 717 let allTabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 718 allTabs.forEach((tab) => { 719 if (tab) { 720 let tables = Array.from( 721 (tab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 722 ); 723 for (let table of tables) { 724 table.recycleDataSource = []; 725 } 726 } 727 }); 728 } 729} 730