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 { type LitTabs } from '../../../../base-ui/tabs/lit-tabs'; 18import { LitTabpane } from '../../../../base-ui/tabs/lit-tabpane'; 19import { BoxJumpParam, SelectionParam, SliceBoxJumpParam } from '../../../bean/BoxSelection'; 20import { type TabPaneCurrentSelection } from '../sheet/TabPaneCurrentSelection'; 21import { type TabPaneFlag } from '../timer-shaft/TabPaneFlag'; 22import { type Flag } from '../timer-shaft/Flag'; 23import { type WakeupBean } from '../../../bean/WakeupBean'; 24import { type LitIcon } from '../../../../base-ui/icon/LitIcon'; 25import { tabConfig } from './TraceSheetConfig'; 26import { type TabPaneBoxChild } from '../sheet/cpu/TabPaneBoxChild'; 27import { type CpuStruct } from '../../../database/ui-worker/cpu/ProcedureWorkerCPU'; 28import { CpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerFreq'; 29import { CpuFreqLimitsStruct } from '../../../database/ui-worker/cpu/ProcedureWorkerCpuFreqLimits'; 30import { type ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread'; 31import { type FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc'; 32import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem'; 33import { CpuStateStruct } from '../../../database/ui-worker/cpu/ProcedureWorkerCpuState'; 34import { type HangStruct } from '../../../database/ui-worker/ProcedureWorkerHang'; 35import { type ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock'; 36import { type DmaFenceStruct } from '../../../database/ui-worker/ProcedureWorkerDmaFence'; 37import { type XpowerStruct } from '../../../database/ui-worker/ProcedureWorkerXpower'; 38import { type IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq'; 39import { type JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank'; 40import { type HeapStruct } from '../../../database/ui-worker/ProcedureWorkerHeap'; 41import { type LitTable } from '../../../../base-ui/table/lit-table'; 42import { threadPool } from '../../../database/SqlLite'; 43import { type HeapSnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerHeapSnapshot'; 44import { type TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis'; 45import { type TabPaneCurrent } from '../sheet/TabPaneCurrent'; 46import { type SlicesTime } from '../timer-shaft/SportRuler'; 47import { type AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup'; 48import { type AllAppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAllAppStartup'; 49import { type SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit'; 50import { type FrameAnimationStruct } from '../../../database/ui-worker/ProcedureWorkerFrameAnimation'; 51import { type TraceRow } from './TraceRow'; 52import { type FrameDynamicStruct } from '../../../database/ui-worker/ProcedureWorkerFrameDynamic'; 53import { type TabPaneFrameDynamic } from '../sheet/frame/TabPaneFrameDynamic'; 54import { type FrameSpacingStruct } from '../../../database/ui-worker/ProcedureWorkerFrameSpacing'; 55import { type TabFrameSpacing } from '../sheet/frame/TabFrameSpacing'; 56import { type JsCpuProfilerChartFrame } from '../../../bean/JsStruct'; 57import { type TabPaneComparison } from '../sheet/ark-ts/TabPaneComparison'; 58import { type TabPaneSummary } from '../sheet/ark-ts/TabPaneSummary'; 59import { type TabPaneGpuClickSelect } from '../sheet/gpu/TabPaneGpuClickSelect'; 60import { type TabPanePurgTotalSelection } from '../sheet/ability/TabPanePurgTotalSelection'; 61import { type TabPanePurgPinSelection } from '../sheet/ability/TabPanePurgPinSelection'; 62import { type TabPaneVmTrackerShmSelection } from '../sheet/vmtracker/TabPaneVmTrackerShmSelection'; 63import { type TabPaneSmapsStatistics } from '../sheet/smaps/TabPaneSmapsStatistics'; 64import { type TabPaneSmapsComparison } from '../sheet/smaps/TabPaneSmapsComparison'; 65import { type SnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerSnapshot'; 66import { type TabPaneDmaSelectAbility } from '../sheet/ability/TabPaneDmaSelectAbility'; 67import { type TabPaneGpuMemorySelectAbility } from '../sheet/ability/TabPaneGpuMemorySelectAbility'; 68import { type TabPaneDmaSelectVmTracker } from '../sheet/vmtracker/TabPaneDmaSelectVmTracker'; 69import { type TabPanePurgTotalComparisonAbility } from '../sheet/ability/TabPanePurgTotalComparisonAbility'; 70import { type TabPanePurgPinComparisonAbility } from '../sheet/ability/TabPanePurgPinComparisonAbility'; 71import { type TabPanePurgTotalComparisonVM } from '../sheet/vmtracker/TabPanePurgTotalComparisonVM'; 72import { type TabPanePurgPinComparisonVM } from '../sheet/vmtracker/TabPanePurgPinComparisonVM'; 73import { type TabPaneDmaAbilityComparison } from '../sheet/ability/TabPaneDmaAbilityComparison'; 74import { type TabPaneGpuMemoryComparison } from '../sheet/ability/TabPaneGpuMemoryComparison'; 75import { type TabPaneDmaVmTrackerComparison } from '../sheet/vmtracker/TabPaneDmaVmTrackerComparison'; 76import { type TabPaneGpuMemorySelectVmTracker } from '../sheet/vmtracker/TabPaneGpuMemorySelectVmTracker'; 77import { type TabPaneGpuMemoryVmTrackerComparison } from '../sheet/vmtracker/TabPaneGpuMemoryVmTrackerComparison'; 78import { type TabPaneVmTrackerShmComparison } from '../sheet/vmtracker/TabPaneVmTrackerShmComparison'; 79import { type TabPaneJsCpuStatistics } from '../sheet/ark-ts/TabPaneJsCpuStatistics'; 80import { type TabPaneGpuClickSelectComparison } from '../sheet/gpu/TabPaneGpuClickSelectComparison'; 81import { Utils } from './Utils'; 82import { TabPaneHiLogs } from '../sheet/hilog/TabPaneHiLogs'; 83import { TabPaneGpuResourceVmTracker } from '../sheet/vmtracker/TabPaneGpuResourceVmTracker'; 84import { type LitPageTable } from '../../../../base-ui/table/LitPageTable'; 85import '../../../../base-ui/popover/LitPopoverV'; 86import { LitPopover } from '../../../../base-ui/popover/LitPopoverV'; 87import { LitTree, TreeItemData } from '../../../../base-ui/tree/LitTree'; 88import { SampleStruct } from '../../../database/ui-worker/ProcedureWorkerBpftrace'; 89import { TabPaneUserPlugin } from '../sheet/userPlugin/TabPaneUserPlugin'; 90import { TabPaneSampleInstruction } from '../sheet/bpftrace/TabPaneSampleInstruction'; 91import { TabPaneFreqStatesDataCut } from '../sheet/states/TabPaneFreqStatesDataCut'; 92import { TabPaneDataCut } from '../sheet/TabPaneDataCut'; 93import { SpSystemTrace } from '../../SpSystemTrace'; 94import { PerfToolStruct } from '../../../database/ui-worker/ProcedureWorkerPerfTool'; 95import { GpuCounterStruct } from '../../../database/ui-worker/ProcedureWorkerGpuCounter'; 96import { TabPaneGpuCounter } from '../sheet/gpu-counter/TabPaneGpuCounter'; 97import { TabPaneSliceChild } from '../sheet/process/TabPaneSliceChild'; 98import { TabPerfFuncAsm } from '../sheet/hiperf/TabPerfFuncAsm'; 99import { XpowerStatisticStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerStatistic'; 100import { XpowerAppDetailStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerAppDetail'; 101import { XpowerWifiStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerWifi'; 102import { TabPaneXpowerStatisticCurrentData } from '../sheet/xpower/TabPaneXpowerStatisticCurrentData'; 103import { XpowerThreadInfoStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerThreadInfo'; 104import { TabPaneXpowerThreadInfoSelection } from '../sheet/xpower/TabPaneXpowerThreadInfoSelection'; 105import { TabPaneXpowerGpuFreqSelection } from '../sheet/xpower/TabPaneXpowerGpuFreqSelection'; 106import { XpowerGpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerGpuFreq'; 107import { WebSocketManager} from '../../../../webSocket/WebSocketManager'; 108import { Constants, TypeConstants} from '../../../../webSocket/Constants'; 109import { PerfFunctionAsmParam } from '../../../bean/PerfAnalysis'; 110import { info, error } from '../../../../log/Log'; 111 112 113@element('trace-sheet') 114export class TraceSheet extends BaseElement { 115 systemLogFlag: Flag | undefined | null; 116 private litTabs: LitTabs | undefined | null; 117 private switchDiv: LitPopover | undefined | null; 118 private processTree: LitTree | undefined | null; 119 private importDiv: HTMLDivElement | undefined | null; 120 private exportBt: LitIcon | undefined | null; 121 private nav: HTMLDivElement | undefined | null; 122 private tabs: HTMLDivElement | undefined | null; 123 private navRoot: HTMLDivElement | null | undefined; 124 private search: HTMLDivElement | undefined | null; 125 private timerShaft: HTMLDivElement | undefined | null; 126 private spacer: HTMLDivElement | undefined | null; 127 private rowsPaneEL: HTMLDivElement | undefined | null; 128 private selection: SelectionParam | undefined | null; 129 private currentPaneID: string = 'current-selection'; 130 private fragment: DocumentFragment | undefined; 131 private lastSelectIPid: number = -1; 132 private lastProcessSet: Set<number> = new Set<number>(); 133 private optionsDiv: LitPopover | undefined | null; 134 private optionsSettingTree: LitTree | undefined | null; 135 private tabPaneHeight: string = ''; 136 private REQ_BUF_SIZE = 1024 * 1024; 137 138 static get observedAttributes(): string[] { 139 return ['mode']; 140 } 141 142 buildTabs(litTabs: LitTabs | undefined | null): void { 143 this.fragment = document.createDocumentFragment(); // @ts-ignore 144 Reflect.ownKeys(tabConfig).forEach((key, index): void => { 145 let pane = new LitTabpane(); 146 pane.id = key.toString(); 147 pane.className = 'tabHeight'; // @ts-ignore 148 pane.tab = tabConfig[key].title; 149 pane.hidden = true; // @ts-ignore 150 pane.key = `${tabConfig[key].key || index}`; // @ts-ignore 151 let cls = tabConfig[key].type; 152 // @ts-ignore 153 let node = new cls(); 154 pane.append(node); 155 this.fragment?.appendChild(pane); 156 }); 157 litTabs!.appendChild(this.fragment); 158 } 159 160 displayTab<T>(...names: string[]): T { 161 this.setMode('max'); 162 this.showOptionsBt(this.selection); 163 this.showUploadSoBt(this.selection); 164 this.showSwitchProcessBt(this.selection); 165 this.shadowRoot 166 ?.querySelectorAll<LitTabpane>('#tabs lit-tabpane') 167 .forEach((it) => (it.hidden = !names.some((k) => k === it.id))); 168 let litTabpane = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[id='${names[0]}']`); 169 if (names[0] === 'current-selection') { 170 this.exportBt!.style.display = 'none'; 171 } else { 172 this.exportBt!.style.display = 'flex'; 173 } 174 this.shadowRoot?.querySelector<LitTabs>('#tabs')?.activePane(litTabpane!.key); 175 return litTabpane!.children.item(0) as unknown as T; 176 } 177 178 getComponentByID<T>(id: string): T { 179 return this.getPaneByID(id)?.children.item(0) as unknown as T; 180 } 181 182 getPaneByID(id: string): LitTabpane { 183 return this.shadowRoot!.querySelector(`#${id}`)!; 184 } 185 186 initElements(): void { 187 this.litTabs = this.shadowRoot?.querySelector('#tabs'); 188 this.litTabs!.addEventListener('contextmenu', (e): void => { 189 e.preventDefault(); 190 }); 191 this.importDiv = this.shadowRoot?.querySelector('#import_div'); 192 this.switchDiv = this.shadowRoot?.querySelector('#select-process'); 193 this.processTree = this.shadowRoot?.querySelector('#processTree'); 194 this.optionsDiv = this.shadowRoot?.querySelector('#options'); 195 this.optionsSettingTree = this.shadowRoot?.querySelector('#optionsSettingTree'); 196 this.optionsSettingTree!.onChange = (e: unknown): void => { 197 const select = this.optionsSettingTree!.getCheckdKeys(); 198 document.dispatchEvent( 199 new CustomEvent('sample-popver-change', { 200 detail: { 201 select: select[0], 202 }, 203 }) 204 ); 205 }; 206 this.processTree!.onChange = (e: unknown): void => { 207 const select = this.processTree!.getCheckdKeys(); 208 const selectIPid = Number(select[0]); 209 this.switchDiv!.visible = 'false'; 210 this.updateRangeSelect(selectIPid); 211 this.lastSelectIPid = selectIPid; 212 }; 213 this.buildTabs(this.litTabs); // @ts-ignore 214 this.litTabs!.onTabClick = (e: unknown): void => this.loadTabPaneData(e.detail.key); 215 this.tableCloseHandler(); 216 this.rowClickEvent(); 217 this.tdClickEvent(); 218 } 219 private rowClickEvent(): void { 220 // @ts-ignore 221 this.getComponentByID<unknown>('box-perf-analysis')?.addEventListener('row-click', (evt: MouseEvent) => { 222 this.perfAnalysisListener(evt); 223 }); 224 // @ts-ignore 225 this.getComponentByID<unknown>('box-perf-analysis')?.addFunctionRowClickEventListener(this.functionAnalysisListener.bind(this)); 226 // @ts-ignore 227 this.getComponentByID<unknown>('box-native-statistic-analysis')?.addEventListener('row-click', (e: MouseEvent) => { 228 this.nativeAnalysisListener(e); 229 }); 230 // @ts-ignore 231 this.getComponentByID<unknown>('box-io-tier-statistics-analysis')?.addEventListener( 232 'row-click', 233 (evt: MouseEvent) => { 234 // @ts-ignore 235 if (evt.detail.button === 2 && evt.detail.tableName) { 236 let pane = this.getPaneByID('box-io-calltree'); 237 this.litTabs!.activeByKey(pane.key); 238 } 239 } 240 ); 241 // @ts-ignore 242 this.getComponentByID<unknown>('box-virtual-memory-statistics-analysis')?.addEventListener( 243 'row-click', 244 (evt: MouseEvent) => { 245 // @ts-ignore 246 if (evt.detail.button === 2 && evt.detail.tableName) { 247 let pane = this.getPaneByID('box-vm-calltree'); 248 this.litTabs!.activeByKey(pane.key); 249 } 250 } 251 ); 252 // @ts-ignore 253 this.getComponentByID<unknown>('box-file-system-statistics-analysis')?.addEventListener( 254 'row-click', 255 (evt: MouseEvent) => { 256 // @ts-ignore 257 if (evt.detail.button === 2 && evt.detail.tableName) { 258 let pane = this.getPaneByID('box-file-system-calltree'); 259 this.litTabs!.activeByKey(pane.key); 260 } 261 } 262 ); 263 // @ts-ignore 264 this.getComponentByID<unknown>('box-native-statstics')?.addEventListener('row-click', (e: unknown) => { 265 this.nativeStatsticsListener(e); 266 }); 267 // @ts-ignore 268 this.getComponentByID<unknown>('box-virtual-memory-statistics')?.addEventListener('row-click', (e: unknown) => { 269 this.virtualMemoryListener(e); 270 }); 271 // @ts-ignore 272 this.getComponentByID<unknown>('box-io-tier-statistics')?.addEventListener('row-click', (e: unknown) => { 273 this.ioTierListener(e); 274 }); 275 // @ts-ignore 276 this.getComponentByID<unknown>('box-file-system-statistics')?.addEventListener('row-click', (e: unknown) => { 277 this.fileSystemListener(e); 278 }); 279 } 280 281 private tdClickEvent(): void { 282 // @ts-ignore 283 this.getComponentByID<unknown>('box-spt')?.addEventListener('td-click', (evt: unknown) => { 284 this.tdClickHandler(evt); 285 }); 286 // @ts-ignore 287 this.getComponentByID<unknown>('box-pts')?.addEventListener('td-click', (evt: unknown) => { 288 this.tdClickHandler(evt); 289 }); 290 // @ts-ignore 291 this.getComponentByID<unknown>('box-thread-states')?.addEventListener('td-click', (evt: unknown) => { 292 this.tdClickHandler(evt, false); 293 }); 294 // @ts-ignore 295 this.getComponentByID<unknown>('box-slices')?.addEventListener('td-click', (evt: unknown) => { 296 this.tdSliceClickHandler(evt); 297 }); 298 } 299 300 private perfAnalysisListener(evt: MouseEvent): void { 301 // @ts-ignore 302 if (evt.detail.button === 2 && evt.detail.pid) { 303 let pane = this.getPaneByID('box-perf-profile'); 304 this.litTabs!.activeByKey(pane.key); 305 } 306 } 307 308 private functionAnalysisListener(evt: unknown, vaddrList: Array<unknown>): void { 309 // @ts-ignore 310 this.currentPaneID = 'box-perf-analysis'; 311 //隐藏除了当前Tab页的其他Tab页 312 this.shadowRoot!.querySelectorAll<LitTabpane>('lit-tabpane').forEach( 313 (it): boolean => 314 it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) 315 ); 316 let asmPane = this.getPaneByID('tab-perf-func-asm'); //通过Id找到需要展示的Tab页 317 asmPane.closeable = true; 318 asmPane.hidden = false; 319 // @ts-ignore 320 asmPane.tab = evt.tableName; //设置Tab页标题 321 let param = new PerfFunctionAsmParam(); 322 param.vaddrList = vaddrList; 323 // @ts-ignore 324 param.functionName = evt.tableName; 325 // @ts-ignore 326 param.totalCount = evt.count; 327 (asmPane.children.item(0) as TabPerfFuncAsm)!.data = param; 328 this.litTabs!.activeByKey(asmPane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 329 } 330 331 private nativeAnalysisListener(e: MouseEvent): void { 332 //@ts-ignore 333 if (e.detail.button === 2 && e.detail.tableName) { 334 let pane = this.getPaneByID('box-native-calltree'); 335 pane.hidden = false; 336 this.litTabs!.activeByKey(pane.key); 337 } 338 } 339 340 private nativeStatsticsListener(e: unknown): void { 341 // @ts-ignore 342 if (e.detail.button === 0) { 343 // @ts-ignore 344 this.selection!.statisticsSelectData = e.detail; 345 let pane = this.getPaneByID('box-native-memory'); 346 this.litTabs?.activeByKey(pane.key); 347 // @ts-ignore 348 (pane.children.item(0) as unknown)!.fromStastics(this.selection); 349 } 350 } 351 352 private virtualMemoryListener(e: unknown): void { 353 // @ts-ignore 354 if (e.detail.button === 0) { 355 // @ts-ignore 356 this.selection!.fileSystemVMData = { path: e.detail.path }; 357 let pane = this.getPaneByID('box-vm-events'); 358 this.litTabs?.activeByKey(pane.key); 359 // @ts-ignore 360 if (e.detail.path) { 361 // @ts-ignore 362 (pane.children.item(0) as unknown)!.fromStastics(this.selection); 363 } 364 } 365 } 366 367 private ioTierListener(e: unknown): void { 368 // @ts-ignore 369 if (e.detail.button === 0) { 370 // @ts-ignore 371 this.selection!.fileSystemIoData = { path: e.detail.path }; 372 let pane = this.getPaneByID('box-io-events'); 373 this.litTabs?.activeByKey(pane.key); 374 // @ts-ignore 375 if (e.detail.path) { 376 // @ts-ignore 377 (pane.children.item(0) as unknown)!.fromStastics(this.selection); 378 } 379 } 380 } 381 382 private fileSystemListener(e: unknown): void { 383 // @ts-ignore 384 if (e.detail.button === 0) { 385 // @ts-ignore 386 this.selection!.fileSystemFsData = e.detail.data; 387 let pane = this.getPaneByID('box-file-system-event'); 388 this.litTabs?.activeByKey(pane.key); 389 // @ts-ignore 390 if (e.detail.data) { 391 // @ts-ignore 392 (pane.children.item(0) as unknown)!.fromStastics(this.selection); 393 } 394 } 395 } 396 397 private tableCloseHandler(): void { 398 this.litTabs!.addEventListener('close-handler', () => { 399 // @ts-ignore 400 Reflect.ownKeys(tabConfig) 401 .reverse() 402 .forEach((id) => { 403 // @ts-ignore 404 let element = tabConfig[id]; 405 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 406 if (element.require) { 407 pane!.hidden = !element.require(this.selection!); 408 } else { 409 pane!.hidden = true; 410 } 411 }); 412 this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`); 413 }); 414 } 415 416 connectedCallback(): void { 417 this.nav = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.tab-nav-vessel'); 418 this.tabs = this.shadowRoot?.querySelector('#tabs'); 419 this.navRoot = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.nav-root'); 420 this.search = document.querySelector('body > sp-application')?.shadowRoot?.querySelector('div > div.search-vessel'); 421 this.timerShaft = this.parentElement?.querySelector('.timer-shaft'); 422 this.spacer = this.parentElement?.querySelector('.spacer'); 423 this.rowsPaneEL = this.parentElement?.querySelector('.rows-pane'); 424 let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#max-btn'); 425 let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#min-btn'); 426 let borderTop: number = 1; 427 let initialHeight = { tabs: 'calc(30vh + 39px)', node: '30vh' }; 428 this.initNavElements(tabsPackUp!, borderTop, initialHeight); 429 this.exportBt = this.shadowRoot?.querySelector<LitIcon>('#export-btn'); 430 tabsOpenUp!.onclick = (): void => { 431 this.tabs!.style.height = `${ 432 window.innerHeight - this.search!.offsetHeight - this.timerShaft!.offsetHeight - borderTop 433 }px`; 434 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 435 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 436 litTabpane!.forEach((node: HTMLDivElement): void => { 437 node!.style.height = `${ 438 window.innerHeight - 439 this.search!.offsetHeight - 440 this.timerShaft!.offsetHeight - 441 this.navRoot!.offsetHeight - 442 borderTop 443 }px`; 444 initialHeight.node = node!.style.height; 445 }); 446 initialHeight.tabs = this.tabs!.style.height; 447 tabsPackUp!.name = 'down'; 448 }; 449 tabsPackUp!.onclick = (): void => { 450 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 451 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 452 if (tabsPackUp!.name === 'down') { 453 let beforeHeight = this.clientHeight; 454 this.tabs!.style.height = `${this.navRoot!.offsetHeight}px`; 455 window.publish(window.SmartEvent.UI.ShowBottomTab, { show: 2, delta: beforeHeight - this.clientHeight }); 456 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = '0px')); 457 tabsPackUp!.name = 'up'; 458 tabsPackUp!.title = 'Reset Tab'; // @ts-ignore 459 (window as unknown).isPackUpTable = true; 460 } else { 461 tabsPackUp!.name = 'down'; 462 tabsPackUp!.title = 'Minimize Tab'; 463 this.tabs!.style.height = initialHeight.tabs; 464 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = initialHeight.node)); 465 } 466 }; 467 this.importClickEvent(); 468 this.exportClickEvent(); 469 } 470 471 private initNavElements(tabsPackUp: LitIcon, borderTop: number, initialHeight: { node: string; tabs: string }): void { 472 let that = this; 473 // 节点挂载时给Tab面板绑定鼠标按下事件 474 this.nav!.onmousedown = (event): void => { 475 // @ts-ignore 476 (window as unknown).isSheetMove = true; 477 // 获取所有标签页的节点数组 478 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 479 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 480 // 获取当前选中面板的key值,后续用来确定当前面板是哪一个。 对于用户来说,直观看到的只有当前面板,其他面板可以在拖动完成后一次性设置好新的高度 481 // @ts-ignore 482 let litTabNavKey: string = this.nav!.querySelector('.nav-item[data-selected=true]').dataset.key; 483 let currentPane: HTMLDivElement = this.shadowRoot?.querySelector(`#tabs > lit-tabpane[key="${litTabNavKey}"]`)!; 484 // 原函数 绑定鼠标移动事件,动态获取鼠标位置信息 485 this.navMouseMove(event, currentPane!, that, tabsPackUp, borderTop); 486 document.onmouseup = function (): void { 487 setTimeout(() => { 488 // @ts-ignore 489 (window as unknown).isSheetMove = false; 490 }, 100); 491 litTabpane!.forEach((node: HTMLDivElement): void => { 492 node!.style.height = that.tabPaneHeight; 493 }); 494 if (that.tabPaneHeight !== '0px' && that.tabs!.style.height !== '') { 495 // 每次都会重新记录上次拖动完成后的面板高度,下次重新显示tab页时,会以上次拖动后的高度显示 496 initialHeight.node = that.tabPaneHeight; 497 initialHeight.tabs = that.tabs!.style.height; 498 } 499 // 将绑定的事件置空,需要时重新绑定 500 this.onmousemove = null; 501 this.onmouseup = null; 502 }; 503 }; 504 } 505 506 private navMouseMove( 507 event: MouseEvent, 508 litTabpane: HTMLDivElement, 509 that: this, 510 tabsPackUp: LitIcon, 511 borderTop: number 512 ): void { 513 // 鼠标移动前记录此时的鼠标位置信息,后续根据新值与前次值作比对 514 let preY = event.pageY; 515 // 获取此时tab组件的偏移高度 需要包含水平滚动条的高度等 516 let preHeight = this.tabs!.offsetHeight; 517 // 获取此时整个滚动区域高度 518 let scrollH = that.rowsPaneEL!.scrollHeight; 519 // 获取此时滚动区域上方被隐藏的高度 520 let scrollT = that.rowsPaneEL!.scrollTop; 521 // 获取当前内容区高度加上上下内边距高度,即面板组件高度 522 let ch = that.clientHeight; 523 // 鼠标移动事件 524 document.onmousemove = function (event): void { 525 // 移动前的面板高度 - 移动前后鼠标的坐标差值 = 新的面板高度 526 let newHeight: number = preHeight - (event.pageY - preY); 527 // that指向的是tracesheet节点 spacer为垫片 rowsPaneEl为泳道 tabs为tab页组件 528 // litTabpane为当前面板 navRoot为面板头部区的父级容器 search为顶部搜索区整个区域 529 // 这四个判断条件中,第一个尚未找到触发条件 后续和润和确认是否会触发 530 if (that.spacer!.offsetHeight > that.rowsPaneEL!.offsetHeight) { 531 that.tabs!.style.height = `${newHeight}px`; 532 litTabpane!.style.height = `${newHeight - that.navRoot!.offsetHeight}px`; 533 // 设置右上角面板大小化的箭头样式,面板在移动到最底部时,箭头向上,其余情况箭头向下 534 tabsPackUp!.name = 'down'; 535 } else if ( 536 // 只要没有移动到边界区域都会进入该条件 537 that.navRoot!.offsetHeight <= newHeight && 538 that.search!.offsetHeight + that.timerShaft!.offsetHeight + borderTop + that.spacer!.offsetHeight <= 539 window.innerHeight - newHeight 540 ) { 541 that.tabs!.style.height = `${newHeight}px`; 542 litTabpane!.style.height = `${newHeight - that.navRoot!.offsetHeight}px`; 543 tabsPackUp!.name = 'down'; 544 } else if (that.navRoot!.offsetHeight >= newHeight) { 545 // 该条件在面板置底时触发 546 that.tabs!.style.height = `${that.navRoot!.offsetHeight}px`; 547 litTabpane!.style.height = '0px'; 548 tabsPackUp!.name = 'up'; 549 } else if ( 550 that.search!.offsetHeight + that.timerShaft!.offsetHeight + borderTop + that.spacer!.offsetHeight >= 551 window.innerHeight - newHeight 552 ) { 553 // 该条件在面板高度置顶时触发 554 that.tabs!.style.height = `${ 555 window.innerHeight - 556 that.search!.offsetHeight - 557 that.timerShaft!.offsetHeight - 558 borderTop - 559 that.spacer!.offsetHeight 560 }px`; 561 litTabpane!.style.height = `${ 562 window.innerHeight - 563 that.search!.offsetHeight - 564 that.timerShaft!.offsetHeight - 565 that.navRoot!.offsetHeight - 566 borderTop - 567 that.spacer!.offsetHeight 568 }px`; 569 tabsPackUp!.name = 'down'; 570 } 571 that.tabPaneHeight = litTabpane!.style.height; 572 let currentSH = that.rowsPaneEL!.scrollHeight; 573 // 第一个判断条件尚未确定如何触发,currentSH与scrollH始终相等 574 if (currentSH > scrollH && currentSH > that.rowsPaneEL!.scrollTop + that.clientHeight) { 575 that.rowsPaneEL!.scrollTop = scrollT - (ch - that.clientHeight); 576 } 577 }; 578 } 579 580 private importClickEvent(): void { 581 let importFileBt: HTMLInputElement | undefined | null = 582 this.shadowRoot?.querySelector<HTMLInputElement>('#import-file'); 583 importFileBt!.addEventListener('change', (event): void => { 584 let files = importFileBt?.files; 585 if (files) { 586 let fileList: Array<File> = []; 587 for (let file of files) { 588 fileList.push(file); 589 } 590 if (fileList.length > 0) { 591 importFileBt!.disabled = true; 592 window.publish(window.SmartEvent.UI.Loading, { loading: true, text: 'Import So File' }); 593 this.uploadSoOrAN(fileList).then(r => 594 threadPool.submit( 595 'upload-so', 596 '', 597 fileList, 598 (res: unknown) => { 599 importFileBt!.disabled = false; // @ts-ignore 600 if (res.result === 'ok') { 601 window.publish(window.SmartEvent.UI.UploadSOFile, {}); 602 } else { 603 // @ts-ignore 604 const failedList = res.failedArray.join(','); 605 window.publish(window.SmartEvent.UI.Error, `parse so file ${failedList} failed!`); 606 } 607 }, 608 'upload-so' 609 )).finally(() => { 610 fileList.length = 0; 611 }); 612 } 613 } 614 importFileBt!.files = null; 615 importFileBt!.value = ''; 616 }); 617 } 618 619 private async uploadSoOrAN(fileList: Array<File>): Promise<void> { 620 if (fileList) { 621 fileList.sort((a, b) => { 622 return b.size - a.size; 623 }); 624 await this.uploadAllFiles(fileList); 625 } 626 } 627 628 629 // 上传文件 630 private async uploadAllFiles(fileList: Array<File>): Promise<void> { 631 // 创建一个副本,避免修改原始的 fileList 632 const filesToUpload = [...fileList]; 633 634 for (let i = 0; i < filesToUpload.length; i++) { 635 const file = filesToUpload[i]; 636 try { 637 await this.uploadSingleFile(file); 638 info(`File ${file.name} uploaded successfully.`); 639 } catch (err) { 640 error(`Failed to upload file: ${file.name}, error: `, err); 641 } 642 } 643 info(`All files have been uploaded.`); 644 } 645 646 647 private uploadSingleFile = async (file: File | null): Promise<void> => { 648 if (file) { 649 let writeSize = 0; 650 let wsInstance = WebSocketManager.getInstance(); 651 const fileName = file.name; 652 let bufferIndex = 0; 653 654 // 定义一个 ACK 回调函数的等待机制 655 const waitForAck = (): Promise<void> => { 656 return new Promise<void>((resolve, reject) => { 657 wsInstance!.registerCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); 658 // 定义超时定时器 659 const timeout = setTimeout(() => { 660 // 超时后注销回调并拒绝 Promise 661 wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); 662 reject(new Error('等待 ACK 超时:文件 ${fileName},索引 ${bufferIndex})')); 663 }, 10000); 664 function onAckReceived(cmd: number, result: Uint8Array): void { 665 const decoder = new TextDecoder(); 666 const jsonString = decoder.decode(result); 667 let jsonRes = JSON.parse(jsonString); 668 if (cmd === Constants.DISASSEMBLY_SAVE_BACK_CMD) { 669 if (jsonRes.fileName === fileName && jsonRes.bufferIndex === bufferIndex) { 670 wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); 671 clearTimeout(timeout); 672 if (jsonRes.resultCode === 0) { 673 bufferIndex++; 674 // 当收到对应分片的 ACK 时,resolve Promise,继续上传下一个分片 675 resolve(); 676 } else { 677 // 上传失败,拒绝 Promise 并返回 678 reject(new Error(`Upload failed for file: ${fileName}, index: ${jsonRes.bufferIndex})`)); 679 } 680 } 681 } 682 } 683 }); 684 }; 685 686 while (writeSize < file.size) { 687 let sliceLen = Math.min(file.size - writeSize, this.REQ_BUF_SIZE); 688 let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); 689 let buffer: ArrayBuffer | null = await blob.arrayBuffer(); 690 let data: Uint8Array | null = new Uint8Array(buffer); 691 692 const dataObject = { 693 file_name: fileName, 694 buffer_index: bufferIndex, 695 buffer_size: sliceLen, 696 total_size: file.size, 697 is_last: writeSize + sliceLen >= file.size, 698 buffer: Array.from(data), 699 }; 700 701 702 const dataString = JSON.stringify(dataObject); 703 const textEncoder = new TextEncoder(); 704 const encodedData = textEncoder.encode(dataString); 705 wsInstance!.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); 706 writeSize += sliceLen; 707 // 等待服务器端确认当前分片的 ACK 708 await waitForAck(); 709 data = null; 710 buffer = null; 711 blob = null; 712 } 713 } 714 }; 715 716 private exportClickEvent(): void { 717 this.exportBt!.onclick = (): void => { 718 let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!); 719 if (currentTab) { 720 let table1 = Array.from( 721 (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitPageTable>('lit-page-table') || [] 722 ); 723 let table2 = Array.from( 724 (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 725 ); 726 let componentTopTable = undefined; 727 if ( 728 (currentTab.firstChild as BaseElement).shadowRoot?.querySelector('#tb-counter') && 729 ((currentTab.firstChild as BaseElement).shadowRoot?.querySelector('#tb-counter')?.firstChild as BaseElement) 730 ) { 731 componentTopTable = ((currentTab.firstChild as BaseElement).shadowRoot?.querySelector('#tb-counter') 732 ?.firstChild as BaseElement)!.shadowRoot?.querySelectorAll<LitTable>('lit-table'); 733 } 734 735 let table3 = Array.from(componentTopTable || []); 736 let tables = [...table1, ...table2, ...table3]; 737 738 for (let table of tables) { 739 if (!table.hasAttribute('hideDownload')) { 740 table.exportData(); 741 } 742 } 743 } 744 }; 745 } 746 747 getTabpaneByKey(key: string): LitTabpane | undefined { 748 let tabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 749 return tabs.find((it) => it.key === key); 750 } 751 752 initHtml(): string { 753 return ` 754 <style> 755 :host([mode='hidden']){ 756 display: none; 757 } 758 :host{ 759 display: block; 760 background-color: rebeccapurple; 761 } 762 .tabHeight{ 763 height: 30vh; 764 background-color: var(--dark-background,#FFFFFF); 765 } 766 #check-popover[visible="true"] #check-des{ 767 color: #0A59F7; 768 } 769 .popover{ 770 color: var(--dark-color1,#4b5766); 771 justify-content: center; 772 align-items: center; 773 margin-right: 10px; 774 z-index: 2; 775 } 776 .option { 777 display: flex; 778 margin-right: 10px; 779 cursor: pointer; 780 } 781 </style> 782 <div id="vessel" style="border-top: 1px solid var(--dark-border1,#D5D5D5);"> 783 <lit-tabs id="tabs" position="top-left" activekey="1" mode="card" > 784 <div class="option" slot="options"> 785 <lit-popover placement="bottom" class="popover" haveRadio="true" trigger="click" id="options"> 786 <div slot="content"> 787 <lit-tree id="optionsSettingTree" checkable="true"></lit-tree> 788 </div> 789 <lit-icon name="setting" size="21" id="setting"></lit-icon> 790 </lit-popover> 791 </div> 792 <div slot="right" style="margin: 0 10px; color: var(--dark-icon,#606060);display: flex;align-items: center;"> 793 <lit-popover placement="bottomRight" class="popover" haveRadio="true" trigger="click" id="select-process"> 794 <div slot="content"> 795 <lit-tree id="processTree" checkable="true"></lit-tree> 796 </div> 797 <lit-icon name="setting" size="20" id="setting"></lit-icon> 798 </lit-popover> 799 <div title="Import SO" id="import_div" style="width: 20px;height: 20px;display: flex;flex-direction: row;margin-right: 10px"> 800 <input id="import-file" style="display: none;pointer-events: none" type="file" webkitdirectory> 801 <label style="width: 20px;height: 20px;cursor: pointer;" for="import-file"> 802 <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20"> 803 </lit-icon> 804 </label> 805 </div> 806 <lit-icon title="Download Table" id="export-btn" name="import-so" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 807 </lit-icon> 808 <lit-icon title="Maximize Tab" id="max-btn" name="vertical-align-top" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 809 </lit-icon> 810 <lit-icon title="Minimize Tab" id="min-btn" name="down" style="font-weight: bold;cursor: pointer;" size="20"> 811 </lit-icon> 812 </div> 813 </lit-tabs> 814 </div>`; 815 } 816 displayCurrent = (data: SlicesTime): void => 817 this.displayTab<TabPaneCurrent>('tabpane-current').setCurrentSlicesTime(data); 818 displayThreadData = ( 819 data: ThreadStruct, 820 scrollCallback: ((e: ThreadStruct) => void) | undefined, 821 scrollWakeUp: (d: unknown) => void | undefined, 822 scrollPrio: (d: unknown) => void | undefined, 823 callback?: (data: Array<unknown>, str: string) => void 824 ): Promise<void> => 825 this.displayTab<TabPaneCurrentSelection>('current-selection').setThreadData( 826 data, 827 // @ts-ignore 828 scrollCallback, 829 scrollWakeUp, 830 scrollPrio, 831 callback 832 ); 833 displayMemData = (data: ProcessMemStruct): void => 834 this.displayTab<TabPaneCurrentSelection>('current-selection').setMemData(data); 835 displayHangData = (data: HangStruct, sp: SpSystemTrace, scrollCallback: Function): Promise<void> => 836 this.displayTab<TabPaneCurrentSelection>('current-selection').setHangData(data, sp, scrollCallback); 837 displayClockData = (data: ClockStruct): Promise<void> => 838 this.displayTab<TabPaneCurrentSelection>('current-selection').setClockData(data); 839 displayDmaFenceData = ( 840 data: DmaFenceStruct, 841 rowData: unknown 842 ): void => //展示tab页内容 843 // @ts-ignore 844 this.displayTab<TabPaneCurrentSelection>('current-selection').setDmaFenceData(data, rowData); 845 displayXpowerData = (data: XpowerStruct): Promise<void> => 846 this.displayTab<TabPaneCurrentSelection>('current-selection').setXpowerData(data); 847 displayXpowerDisplayData = (data: XpowerAppDetailStruct): Promise<void> => 848 this.displayTab<TabPaneCurrentSelection>('current-selection').setXpowerDisplayData(data); 849 displayXpowerWifiPacketsData = (data: XpowerWifiStruct): Promise<void> => 850 this.displayTab<TabPaneCurrentSelection>('current-selection').setXpowerWifiPacketsData(data); 851 displayXpowerBytesWifiData = (data: XpowerWifiStruct): Promise<void> => 852 this.displayTab<TabPaneCurrentSelection>('current-selection').setXpowerWifiBytesData(data); 853 displayXpowerStatisticData = (data: XpowerStatisticStruct): void => 854 this.displayTab<TabPaneXpowerStatisticCurrentData>( 855 'box-xpower-statistic-current-data' 856 ).setXpowerStatisticCurrentData(data); 857 displayXpowerThreadInfoData = (dataList: Array<XpowerThreadInfoStruct>): void => { 858 this.displayTab<TabPaneXpowerThreadInfoSelection>('box-xpower-thread-info-selection').setThreadInfoData(dataList); 859 }; 860 displayXpowerGpuFreqData = (dataList: Array<XpowerGpuFreqStruct>): void => { 861 this.displayTab<TabPaneXpowerGpuFreqSelection>('box-xpower-gpu-freq-selection').setGpuFreqData(dataList); 862 }; 863 displayPerfToolsData = (data: PerfToolStruct): void => 864 this.displayTab<TabPaneCurrentSelection>('current-selection').setPerfToolsData(data); 865 displayIrqData = (data: IrqStruct): void => 866 this.displayTab<TabPaneCurrentSelection>('current-selection').setIrqData(data); 867 displayStartupData = (data: AppStartupStruct, scrollCallback: Function, rowData: unknown): void => 868 this.displayTab<TabPaneCurrentSelection>('current-selection').setStartupData(data, scrollCallback, rowData); 869 displayAllStartupData = (data: AllAppStartupStruct, scrollCallback: Function): void => 870 this.displayTab<TabPaneCurrentSelection>('current-selection').setAllStartupData(data, scrollCallback); 871 displayStaticInitData = (data: SoStruct, scrollCallback: Function): void => 872 this.displayTab<TabPaneCurrentSelection>('current-selection').setStaticInitData(data, scrollCallback); 873 874 displayNativeHookData = (data: HeapStruct, rowType: string, ipid: number): void => { 875 let val = new SelectionParam(); 876 val.nativeMemoryStatistic.push(rowType); 877 val.nativeMemoryCurrentIPid = ipid; 878 val.nativeMemory = []; 879 val.leftNs = data.startTime! + data.dur!; 880 val.rightNs = data.startTime! + data.dur! + 1; 881 this.selection = val; 882 this.displayTab<TabPaneNMStatisticAnalysis>('box-native-statistic-analysis', 'box-native-calltree').data = val; 883 this.showUploadSoBt(val); 884 this.showSwitchProcessBt(val); 885 }; 886 887 displayGpuSelectedData = (type: string, startTs: number, dataList: Array<SnapshotStruct>): void => { 888 this.displayTab<TabPaneGpuClickSelectComparison>('gpu-click-select-comparison').getGpuClickDataByDB( 889 type, 890 startTs, 891 dataList 892 ); 893 let dataObject = { type: type, startTs: startTs }; 894 this.displayTab<TabPaneGpuClickSelect>('gpu-click-select', 'gpu-click-select-comparison').gpuClickData(dataObject); 895 }; 896 897 displayFuncData = ( 898 names: string[], 899 threadName: string, 900 data: FuncStruct, 901 scrollCallback: Function, 902 callback?: (data: Array<unknown>, str: string, binderTid: number) => void, 903 distributedCallback?: (dataList: FuncStruct[]) => void 904 ): Promise<void> => 905 this.displayTab<TabPaneCurrentSelection>(...names).setFunctionData( 906 data, 907 threadName, 908 scrollCallback, 909 callback, 910 distributedCallback 911 ); 912 displayCpuData = ( 913 data: CpuStruct, 914 callback: ((data: WakeupBean | null) => void) | undefined = undefined, 915 scrollCallback?: (data: CpuStruct) => void 916 ): Promise<void> => 917 this.displayTab<TabPaneCurrentSelection>('current-selection').setCpuData(data, callback, scrollCallback); 918 displayJankData = ( 919 data: JankStruct, 920 callback: ((data: Array<unknown>) => void) | undefined = undefined, 921 scrollCallback: ((e: JankStruct) => void) | undefined 922 // @ts-ignore 923 ): void => this.displayTab<TabPaneCurrentSelection>('current-selection').setJankData(data, callback, scrollCallback); 924 displayShmData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 925 this.displayTab<TabPaneVmTrackerShmComparison>('box-vmtracker-shm-comparison').setShmData(data, dataList); 926 this.displayTab<TabPaneVmTrackerShmSelection>( 927 'box-vmtracker-shm-selection', 928 'box-vmtracker-shm-comparison' 929 ).setShmData(data, dataList); 930 }; 931 displaySmapsData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 932 let val = new SelectionParam(); 933 val.smapsType = []; 934 val.leftNs = data.startNs; 935 this.selection = val; 936 val.smapsType = []; 937 this.displayTab<TabPaneSmapsComparison>('box-smaps-comparison').setData(val, dataList); 938 this.displayTab<TabPaneSmapsStatistics>( 939 'box-smaps-statistics', 940 'box-smaps-sample', 941 'box-smaps-comparison', 942 'box-smaps-record' 943 ).data = val; 944 }; 945 displaySnapshotData = ( 946 data: HeapSnapshotStruct, 947 dataListCache: Array<HeapSnapshotStruct>, 948 scrollCallback?: (data: HeapSnapshotStruct, dataListCache: Array<HeapSnapshotStruct>) => void 949 ): void => { 950 if (dataListCache.length > 1) { 951 this.displayTab<TabPaneSummary>('box-heap-summary', 'box-heap-comparison').setSnapshotData( 952 data, 953 dataListCache, 954 scrollCallback 955 ); 956 let nav = this.shadowRoot!.querySelector('#tabs')!.shadowRoot!.querySelector( 957 '#nav > #nav-comparison' 958 ) as HTMLDivElement; 959 let tabPaneComparison = this.shadowRoot!.querySelector( 960 '#box-heap-comparison > tabpane-comparison' 961 ) as TabPaneComparison; 962 nav!.onclick = (): void => { 963 tabPaneComparison.initComparison(data, dataListCache); 964 }; 965 } else { 966 this.displayTab<TabPaneSummary>('box-heap-summary').setSnapshotData(data, dataListCache, scrollCallback); 967 } 968 }; 969 displayFlagData = (flagObj: Flag): void => this.displayTab<TabPaneFlag>('box-flag').setCurrentFlag(flagObj); 970 displayFreqData = (): CpuFreqStruct | undefined => 971 (this.displayTab<TabPaneCurrentSelection>('box-freq').data = CpuFreqStruct.selectCpuFreqStruct); 972 displayCpuStateData = (): CpuStateStruct | undefined => 973 (this.displayTab<TabPaneCurrentSelection>('cpu-state-click').data = CpuStateStruct.selectStateStruct); 974 displayFreqLimitData = (): CpuFreqLimitsStruct | undefined => 975 (this.displayTab<TabPaneCurrentSelection>('box-freq-limit').data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct); 976 977 displayFrameAnimationData = (data: FrameAnimationStruct, scrollCallback: Function): Promise<void> => 978 this.displayTab<TabPaneCurrentSelection>('current-selection').setFrameAnimationData(data, scrollCallback); 979 displayFrameDynamicData = (row: TraceRow<FrameDynamicStruct>, data: FrameDynamicStruct): void => 980 this.displayTab<TabPaneFrameDynamic>('box-frame-dynamic').buildDynamicTable([data], true); 981 displayFrameSpacingData = (data: FrameSpacingStruct): void => 982 this.displayTab<TabFrameSpacing>('box-frames-spacing').setFrameSpacingData(data); 983 displayJsProfilerData = (data: Array<JsCpuProfilerChartFrame>): void => { 984 let val = new SelectionParam(); 985 val.jsCpuProfilerData = data; 986 this.selection = val; 987 this.displayTab<TabPaneJsCpuStatistics>( 988 'box-js-Profiler-statistics', 989 'box-js-Profiler-bottom-up', 990 'box-js-Profiler-top-down' 991 ).data = data; 992 }; 993 displayPurgTotalAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 994 data.type = 'ability'; 995 this.displayTab<TabPanePurgTotalComparisonAbility>('box-purgeable-total-comparison-ability').totalData( 996 data, 997 dataList 998 ); 999 this.displayTab<TabPanePurgTotalSelection>( 1000 'box-purgeable-total-selection', 1001 'box-purgeable-total-comparison-ability' 1002 ).data = data; 1003 }; 1004 displayPurgPinAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 1005 data.type = 'ability'; 1006 this.displayTab<TabPanePurgPinComparisonAbility>('box-purgeable-pin-comparison-ability').totalData(data, dataList); 1007 this.displayTab<TabPanePurgPinSelection>( 1008 'box-purgeable-pin-selection', 1009 'box-purgeable-pin-comparison-ability' 1010 ).data = data; 1011 }; 1012 displayPurgTotalVMData = (data: SnapshotStruct, dataListCache: Array<SnapshotStruct>): void => { 1013 data.type = 'VM'; 1014 this.displayTab<TabPanePurgTotalComparisonVM>('box-purgeable-total-comparison-vm').totalData(data, dataListCache); 1015 this.displayTab<TabPanePurgTotalSelection>( 1016 'box-purgeable-total-selection', 1017 'box-purgeable-total-comparison-vm' 1018 ).data = data; 1019 }; 1020 displayPurgPinVMData = (data: SnapshotStruct, dataListCache: Array<SnapshotStruct>): void => { 1021 data.type = 'VM'; 1022 this.displayTab<TabPanePurgPinComparisonVM>('box-purgeable-pin-comparison-vm').totalData(data, dataListCache); 1023 this.displayTab<TabPanePurgPinSelection>('box-purgeable-pin-selection', 'box-purgeable-pin-comparison-vm').data = 1024 data; 1025 }; 1026 displayDmaAbility = (data: number, dataList: Array<SnapshotStruct>): void => { 1027 if (dataList.length > 0) { 1028 this.displayTab<TabPaneDmaAbilityComparison>('box-dma-ability-comparison').comparisonDataByDB(data, dataList); 1029 this.displayTab<TabPaneDmaSelectAbility>( 1030 'box-dma-selection-ability', 1031 'box-dma-ability-comparison' 1032 ).queryDmaClickDataByDB(data); 1033 } else { 1034 this.displayTab<TabPaneDmaSelectAbility>('box-dma-selection-ability').queryDmaClickDataByDB(data); 1035 } 1036 }; 1037 displayDmaVmTracker = (data: number, dataListCache: Array<SnapshotStruct>): void => { 1038 if (dataListCache.length > 0) { 1039 this.displayTab<TabPaneDmaVmTrackerComparison>('box-vmTracker-comparison').comparisonDataByDB( 1040 data, 1041 dataListCache 1042 ); 1043 this.displayTab<TabPaneDmaSelectVmTracker>( 1044 'box-dma-selection-vmTracker', 1045 'box-vmTracker-comparison' 1046 ).queryDmaVmTrackerClickDataByDB(data); 1047 } else { 1048 this.displayTab<TabPaneDmaSelectVmTracker>('box-dma-selection-vmTracker').queryDmaVmTrackerClickDataByDB(data); 1049 } 1050 }; 1051 displayGpuMemoryAbility = (data: number, dataList: Array<SnapshotStruct>): void => { 1052 if (dataList.length > 0) { 1053 this.displayTab<TabPaneGpuMemoryComparison>('box-gpu-memory-comparison').comparisonDataByDB(data, dataList); 1054 this.displayTab<TabPaneGpuMemorySelectAbility>( 1055 'box-gpu-memory-selection-ability', 1056 'box-gpu-memory-comparison' 1057 ).queryGpuMemoryClickDataByDB(data); 1058 } else { 1059 this.displayTab<TabPaneGpuMemorySelectAbility>('box-gpu-memory-selection-ability').data = data; 1060 } 1061 }; 1062 displayGpuMemoryVmTracker = (data: number, dataListCache: Array<SnapshotStruct>): void => { 1063 if (dataListCache.length > 0) { 1064 this.displayTab<TabPaneGpuMemoryVmTrackerComparison>('box-gpu-memory-vmTracker-comparison').comparisonDataByDB( 1065 data, 1066 dataListCache 1067 ); 1068 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 1069 'box-gpu-memory-selection-vmTracker', 1070 'box-gpu-memory-vmTracker-comparison' 1071 ).queryGpuMemoryVmTrackerClickDataByDB(data); 1072 } else { 1073 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 1074 'box-gpu-memory-selection-vmTracker' 1075 ).queryGpuMemoryVmTrackerClickDataByDB(data); 1076 } 1077 }; 1078 displayGpuResourceVmTracker = (data: number): void => { 1079 this.displayTab<TabPaneGpuResourceVmTracker>('box-smaps-gpu-resource').data = data; 1080 }; 1081 1082 displaySystemLogsData = (): void => { 1083 let tblHiLogPanel = this.shadowRoot?.querySelector<LitTabpane>("lit-tabpane[id='box-hilogs']"); 1084 if (tblHiLogPanel) { 1085 let tblHiLog = tblHiLogPanel.querySelector<TabPaneHiLogs>('tab-hi-log'); 1086 if (tblHiLog) { 1087 tblHiLog.initTabSheetEl(this); 1088 } 1089 } 1090 }; 1091 1092 displayHangsData = (): void => { 1093 let tblHangPanel = this.shadowRoot?.querySelector<LitTabpane>("lit-tabpane[id='box-hang']"); 1094 if (tblHangPanel) { 1095 let tblHang = tblHangPanel.querySelector<TabPaneHiLogs>('tab-hang'); 1096 if (tblHang) { 1097 tblHang.initTabSheetEl(this); 1098 } 1099 } 1100 }; 1101 1102 displaySampleData = (data: SampleStruct, reqProperty: unknown): void => { 1103 this.displayTab<TabPaneSampleInstruction>('box-sample-instruction').setSampleInstructionData(data, reqProperty); 1104 this.optionsDiv!.style.display = 'flex'; 1105 const select = 1106 this.optionsSettingTree!.getCheckdKeys().length === 0 ? ['0'] : this.optionsSettingTree!.getCheckdKeys(); 1107 this.optionsSettingTree!.treeData = [ 1108 { key: '0', title: 'instruction', checked: select[0] === '0' }, 1109 { key: '1', title: 'cycles', checked: select[0] === '1' }, 1110 ]; 1111 }; 1112 displayUserPlugin = (selectData: unknown): void => { 1113 this.displayTab<TabPaneUserPlugin>('tab-pane-userplugin').data = selectData; 1114 }; 1115 1116 displayGpuCounterData = (data: GpuCounterStruct): void => { 1117 this.displayTab<TabPaneGpuCounter>('box-gpu-counter').data = data; 1118 }; 1119 1120 displaySystemStatesData = (): void => { 1121 let dataCutPane = this.shadowRoot?.querySelector<TabPaneDataCut>('tabpane-datacut'); 1122 if (dataCutPane) { 1123 dataCutPane.initTabSheetEl(this); 1124 } 1125 let tblStatesPanel = this.shadowRoot?.querySelector<TabPaneFreqStatesDataCut>('tabpane-states-datacut'); 1126 if (tblStatesPanel) { 1127 tblStatesPanel.initTabSheetEl(this); 1128 } 1129 }; 1130 rangeSelect(selection: SelectionParam, restore = false): boolean { 1131 this.selection = selection; 1132 this.exportBt!.style.display = 'flex'; 1133 this.showUploadSoBt(selection); 1134 this.showSwitchProcessBt(selection); 1135 this.showOptionsBt(selection); // @ts-ignore 1136 Reflect.ownKeys(tabConfig) 1137 .reverse() 1138 .forEach((id) => { 1139 // @ts-ignore 1140 let element = tabConfig[id]; 1141 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 1142 if (pane) { 1143 pane.hidden = !(element.require && element.require(selection)); 1144 } 1145 }); 1146 if (restore) { 1147 if (this.litTabs?.activekey) { 1148 this.loadTabPaneData(this.litTabs?.activekey); 1149 this.setMode('max'); 1150 return true; 1151 } else { 1152 this.setMode('hidden'); 1153 return false; 1154 } 1155 } else { 1156 let firstPane = this.shadowRoot!.querySelector<LitTabpane>("lit-tabpane[hidden='false']"); 1157 if (firstPane) { 1158 this.litTabs?.activeByKey(firstPane.key); 1159 this.loadTabPaneData(firstPane.key); 1160 this.setMode('max'); 1161 return true; 1162 } else { 1163 this.setMode('hidden'); 1164 return false; 1165 } 1166 } 1167 } 1168 1169 showOptionsBt(selection: SelectionParam | null | undefined): void { 1170 if (selection && selection.sampleData.length > 0) { 1171 this.optionsDiv!.style.display = 'flex'; 1172 const select = 1173 this.optionsSettingTree!.getCheckdKeys().length === 0 ? ['0'] : this.optionsSettingTree!.getCheckdKeys(); 1174 this.optionsSettingTree!.treeData = [ 1175 { key: '0', title: 'instruction', checked: select[0] === '0' }, 1176 { key: '1', title: 'cycles', checked: select[0] === '1' }, 1177 ]; 1178 } else { 1179 this.optionsDiv!.style.display = 'none'; 1180 } 1181 } 1182 1183 updateRangeSelect(ipid?: number): boolean { 1184 if ( 1185 this.selection && 1186 (this.selection.nativeMemory.length > 0 || 1187 this.selection.nativeMemoryStatistic.length > 0 || 1188 this.selection.perfSampleIds.length > 0 || 1189 this.selection.fileSystemType.length > 0 || 1190 this.selection.fsCount > 0 || 1191 this.selection.fileSysVirtualMemory || 1192 this.selection.vmCount > 0 || 1193 this.selection.diskIOLatency || 1194 this.selection.diskIOipids.length > 0) 1195 ) { 1196 let param: SelectionParam = new SelectionParam(); 1197 Object.assign(param, this.selection); 1198 if (param.nativeMemory.length > 0 || param.nativeMemoryStatistic.length > 0) { 1199 Utils.getInstance().initResponseTypeList(param); 1200 if (ipid) { 1201 Utils.getInstance().setCurrentSelectIPid(ipid); 1202 param.nativeMemoryCurrentIPid = ipid; 1203 } 1204 } 1205 this.rangeSelect(param, true); 1206 return true; 1207 } else { 1208 return false; 1209 } 1210 } 1211 1212 showUploadSoBt(selection: SelectionParam | null | undefined): void { 1213 if ( 1214 selection && 1215 (selection.nativeMemory.length > 0 || 1216 selection.nativeMemoryStatistic.length > 0 || 1217 selection.perfSampleIds.length > 0 || 1218 selection.fileSystemType.length > 0 || 1219 selection.fsCount > 0 || 1220 selection.fileSysVirtualMemory || 1221 selection.vmCount > 0 || 1222 selection.diskIOLatency || 1223 selection.diskIOipids.length > 0 || 1224 selection.threadIds.length > 0) 1225 ) { 1226 this.importDiv!.style.display = 'flex'; 1227 } else { 1228 this.importDiv!.style.display = 'none'; 1229 } 1230 } 1231 isProcessEqual(treeData: Array<{ pid: number; ipid: number }>): boolean { 1232 if (treeData.length !== this.lastProcessSet.size) { 1233 return false; 1234 } 1235 for (let process of treeData) { 1236 if (!this.lastProcessSet.has(process.pid)) { 1237 return false; 1238 } 1239 } 1240 return true; 1241 } 1242 1243 showSwitchProcessBt(selection: SelectionParam | null | undefined): void { 1244 // 2个及以上进程再显示 1245 if (selection && selection.nativeMemoryAllProcess.length > 1) { 1246 this.switchDiv!.style.display = 'flex'; 1247 if (this.isProcessEqual(selection.nativeMemoryAllProcess)) { 1248 if (this.processTree) { 1249 for (const data of this.processTree.treeData) { 1250 if (data.key === `${selection.nativeMemoryCurrentIPid}`) { 1251 data.checked = true; 1252 } else { 1253 data.checked = false; 1254 } 1255 } 1256 //调用set重新更新界面 1257 this.processTree.treeData = this.processTree.treeData; 1258 } 1259 return; 1260 } 1261 this.lastProcessSet = new Set<number>(); 1262 const processArray: Array<TreeItemData> = []; 1263 let isFirst: boolean = true; 1264 for (let process of selection.nativeMemoryAllProcess) { 1265 const treeData: TreeItemData = { 1266 key: `${process.ipid}`, 1267 title: `Process ${process.pid}`, 1268 checked: isFirst, 1269 }; 1270 if (isFirst) { 1271 this.lastSelectIPid = process.ipid; 1272 isFirst = false; 1273 } 1274 processArray.push(treeData); 1275 this.lastProcessSet.add(process.pid); 1276 } 1277 this.processTree!.treeData = processArray; 1278 } else { 1279 this.switchDiv!.style.display = 'none'; 1280 } 1281 } 1282 1283 loadTabPaneData(key: string): void { 1284 let component: unknown = this.shadowRoot 1285 ?.querySelector<LitTabpane>(`#tabs lit-tabpane[key='${key}']`) 1286 ?.children.item(0); 1287 if (component) { 1288 // @ts-ignore 1289 component.data = this.selection; 1290 if (this.selection) { 1291 this.selection.isRowClick = false; 1292 } 1293 } 1294 } 1295 1296 setMode(mode: string): void { 1297 let delta = this.clientHeight; 1298 let show = mode === 'max' ? 1 : -1; 1299 this.setAttribute('mode', mode); 1300 if (mode === 'hidden') { 1301 this.selection = undefined; 1302 } 1303 window.publish(window.SmartEvent.UI.ShowBottomTab, { show: show, delta: delta }); 1304 } 1305 1306 tdClickHandler(e: unknown, isDependCpu?: boolean): void { 1307 // @ts-ignore 1308 this.currentPaneID = e.target.parentElement.id; 1309 //隐藏除了当前Tab页的其他Tab页 1310 this.shadowRoot!.querySelectorAll<LitTabpane>('lit-tabpane').forEach((it): boolean => 1311 it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) 1312 ); //todo:看能不能优化 1313 let pane = this.getPaneByID('box-cpu-child'); //通过Id找到需要展示的Tab页 1314 pane.closeable = true; //关闭的ican显示 1315 pane.hidden = false; 1316 this.litTabs!.activeByKey(pane.key); //显示key值对应的Tab页 1317 // @ts-ignore 1318 pane.tab = e.detail.tabTitle ? e.detail.tabTitle : Utils.transferPTSTitle(e.detail.title); //设置Tab页标题,有的标题可直接用,有的标题需在此转换成需要展示的字符串 1319 let param = new BoxJumpParam(); 1320 param.traceId = this.selection!.traceId; 1321 param.leftNs = this.selection!.leftNs; 1322 param.rightNs = this.selection!.rightNs; 1323 param.cpus = isDependCpu ? this.selection!.cpus : []; 1324 // @ts-ignore 1325 param.state = e.detail.summary ? '' : e.detail.state; 1326 // @ts-ignore 1327 param.processId = e.detail.summary ? this.selection.processIds : e.detail.pid; 1328 // @ts-ignore 1329 param.threadId = e.detail.summary ? this.selection.threadIds : e.detail.tid; 1330 param.isJumpPage = true; // @ts-ignore 1331 param.currentId = e.target.parentElement.id; //根据父Tab页的标题,确认子Tab页的dur是否需要处理 1332 (pane.children.item(0) as TabPaneBoxChild).data = param; 1333 } 1334 1335 //Slice Tab点击Occurrences列下的td进行跳转 1336 tdSliceClickHandler(e: unknown): void { 1337 // @ts-ignore 1338 this.currentPaneID = e.target.parentElement.id; 1339 //隐藏除了当前Tab页的其他Tab页 1340 this.shadowRoot!.querySelectorAll<LitTabpane>('lit-tabpane').forEach((it): boolean => 1341 it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) 1342 ); 1343 let pane = this.getPaneByID('box-slice-child'); //通过Id找到需要展示的Tab页 1344 pane.closeable = true; 1345 pane.hidden = false; 1346 this.litTabs!.activeByKey(pane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 1347 // @ts-ignore 1348 pane.tab = e.detail.tabTitle; //设置Tab页标题 1349 let param = new SliceBoxJumpParam(); 1350 param.traceId = this.selection!.traceId; 1351 param.leftNs = this.selection!.leftNs; 1352 param.rightNs = this.selection!.rightNs; 1353 param.processId = this.selection!.processIds; 1354 param.threadId = this.selection!.funTids; //@ts-ignore2 1355 param.name = e.detail.allName ? e.detail.allName : [e.detail.name]; //@ts-ignore2 1356 param.isJumpPage = true; // @ts-ignore 1357 param.isSummary = e.detail.allName ? true : false; 1358 (pane.children.item(0) as TabPaneSliceChild).data = { param: param, selection: this.selection }; 1359 } 1360 1361 clearMemory(): void { 1362 let allTabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 1363 allTabs.forEach((tab) => { 1364 if (tab) { 1365 let tables = Array.from( 1366 (tab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 1367 ); 1368 for (let table of tables) { 1369 table.recycleDataSource = []; 1370 } 1371 } 1372 }); 1373 } 1374} 1375