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 } 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 ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock'; 35import { type IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq'; 36import { type JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank'; 37import { type HeapStruct } from '../../../database/ui-worker/ProcedureWorkerHeap'; 38import { type LitTable } from '../../../../base-ui/table/lit-table'; 39import { threadPool } from '../../../database/SqlLite'; 40import { type HeapSnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerHeapSnapshot'; 41import { type TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis'; 42import { type TabPaneCurrent } from '../sheet/TabPaneCurrent'; 43import { type SlicesTime } from '../timer-shaft/SportRuler'; 44import { type AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup'; 45import { type AllAppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAllAppStartup'; 46import { type SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit'; 47import { type FrameAnimationStruct } from '../../../database/ui-worker/ProcedureWorkerFrameAnimation'; 48import { type TraceRow } from './TraceRow'; 49import { type FrameDynamicStruct } from '../../../database/ui-worker/ProcedureWorkerFrameDynamic'; 50import { type TabPaneFrameDynamic } from '../sheet/frame/TabPaneFrameDynamic'; 51import { type FrameSpacingStruct } from '../../../database/ui-worker/ProcedureWorkerFrameSpacing'; 52import { type TabFrameSpacing } from '../sheet/frame/TabFrameSpacing'; 53import { type JsCpuProfilerChartFrame } from '../../../bean/JsStruct'; 54import { type TabPaneComparison } from '../sheet/ark-ts/TabPaneComparison'; 55import { type TabPaneSummary } from '../sheet/ark-ts/TabPaneSummary'; 56import { type TabPaneGpuClickSelect } from '../sheet/gpu/TabPaneGpuClickSelect'; 57import { type TabPanePurgTotalSelection } from '../sheet/ability/TabPanePurgTotalSelection'; 58import { type TabPanePurgPinSelection } from '../sheet/ability/TabPanePurgPinSelection'; 59import { type TabPaneVmTrackerShmSelection } from '../sheet/vmtracker/TabPaneVmTrackerShmSelection'; 60import { type TabPaneSmapsStatistics } from '../sheet/smaps/TabPaneSmapsStatistics'; 61import { type TabPaneSmapsComparison } from '../sheet/smaps/TabPaneSmapsComparison'; 62import { type SnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerSnapshot'; 63import { type TabPaneDmaSelectAbility } from '../sheet/ability/TabPaneDmaSelectAbility'; 64import { type TabPaneGpuMemorySelectAbility } from '../sheet/ability/TabPaneGpuMemorySelectAbility'; 65import { type TabPaneDmaSelectVmTracker } from '../sheet/vmtracker/TabPaneDmaSelectVmTracker'; 66import { type TabPanePurgTotalComparisonAbility } from '../sheet/ability/TabPanePurgTotalComparisonAbility'; 67import { type TabPanePurgPinComparisonAbility } from '../sheet/ability/TabPanePurgPinComparisonAbility'; 68import { type TabPanePurgTotalComparisonVM } from '../sheet/vmtracker/TabPanePurgTotalComparisonVM'; 69import { type TabPanePurgPinComparisonVM } from '../sheet/vmtracker/TabPanePurgPinComparisonVM'; 70import { type TabPaneDmaAbilityComparison } from '../sheet/ability/TabPaneDmaAbilityComparison'; 71import { type TabPaneGpuMemoryComparison } from '../sheet/ability/TabPaneGpuMemoryComparison'; 72import { type TabPaneDmaVmTrackerComparison } from '../sheet/vmtracker/TabPaneDmaVmTrackerComparison'; 73import { type TabPaneGpuMemorySelectVmTracker } from '../sheet/vmtracker/TabPaneGpuMemorySelectVmTracker'; 74import { type TabPaneGpuMemoryVmTrackerComparison } from '../sheet/vmtracker/TabPaneGpuMemoryVmTrackerComparison'; 75import { type TabPaneVmTrackerShmComparison } from '../sheet/vmtracker/TabPaneVmTrackerShmComparison'; 76import { type TabPaneJsCpuStatistics } from '../sheet/ark-ts/TabPaneJsCpuStatistics'; 77import { type TabPaneGpuClickSelectComparison } from '../sheet/gpu/TabPaneGpuClickSelectComparison'; 78import { Utils } from './Utils'; 79import { TabPaneHiLogs } from '../sheet/hilog/TabPaneHiLogs'; 80import { TabPaneGpuResourceVmTracker } from '../sheet/vmtracker/TabPaneGpuResourceVmTracker'; 81import { type LitPageTable } from '../../../../base-ui/table/LitPageTable'; 82import '../../../../base-ui/popover/LitPopoverV'; 83import { LitPopover } from '../../../../base-ui/popover/LitPopoverV'; 84import { LitTree, TreeItemData } from '../../../../base-ui/tree/LitTree'; 85 86@element('trace-sheet') 87export class TraceSheet extends BaseElement { 88 systemLogFlag: Flag | undefined | null; 89 private litTabs: LitTabs | undefined | null; 90 private switchDiv: LitPopover | undefined | null; 91 private processTree: LitTree | undefined | null; 92 private importDiv: HTMLDivElement | undefined | null; 93 private exportBt: LitIcon | undefined | null; 94 private nav: HTMLDivElement | undefined | null; 95 private tabs: HTMLDivElement | undefined | null; 96 private navRoot: HTMLDivElement | null | undefined; 97 private search: HTMLDivElement | undefined | null; 98 private timerShaft: HTMLDivElement | undefined | null; 99 private spacer: HTMLDivElement | undefined | null; 100 private rowsPaneEL: HTMLDivElement | undefined | null; 101 private selection: SelectionParam | undefined | null; 102 private currentPaneID: string = 'current-selection'; 103 private fragment: DocumentFragment | undefined; 104 private lastSelectIPid: number = -1; 105 private lastProcessSet: Set<number> = new Set<number>(); 106 107 static get observedAttributes(): string[] { 108 return ['mode']; 109 } 110 111 buildTabs(litTabs: LitTabs | undefined | null): void { 112 this.fragment = document.createDocumentFragment(); 113 Reflect.ownKeys(tabConfig).forEach((key, index) => { 114 let pane = new LitTabpane(); 115 pane.id = key.toString(); 116 pane.className = 'tabHeight'; 117 pane.tab = tabConfig[key].title; 118 pane.hidden = true; 119 pane.key = `${tabConfig[key].key || index}`; 120 let cls = tabConfig[key].type; 121 let node = new cls(); 122 pane.append(node); 123 this.fragment?.appendChild(pane); 124 }); 125 litTabs!.appendChild(this.fragment); 126 } 127 128 displayTab<T>(...names: string[]): T { 129 this.setAttribute('mode', 'max'); 130 this.showUploadSoBt(null); 131 this.showSwitchProcessBt(null); 132 this.shadowRoot 133 ?.querySelectorAll<LitTabpane>('#tabs lit-tabpane') 134 .forEach((it) => (it.hidden = !names.some((k) => k === it.id))); 135 let litTabpane = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[id='${names[0]}']`); 136 if (names[0] === 'current-selection') { 137 this.exportBt!.style.display = 'none'; 138 } else { 139 this.exportBt!.style.display = 'flex'; 140 } 141 this.shadowRoot?.querySelector<LitTabs>('#tabs')?.activePane(litTabpane!.key); 142 return litTabpane!.children.item(0) as unknown as T; 143 } 144 145 getComponentByID<T>(id: string): T { 146 return this.getPaneByID(id)?.children.item(0) as unknown as T; 147 } 148 149 getPaneByID(id: string): LitTabpane { 150 return this.shadowRoot!.querySelector(`#${id}`)!; 151 } 152 153 initElements(): void { 154 this.litTabs = this.shadowRoot?.querySelector('#tabs'); 155 this.litTabs!.addEventListener('contextmenu', (e) => { 156 e.preventDefault(); 157 }); 158 this.importDiv = this.shadowRoot?.querySelector('#import_div'); 159 this.switchDiv = this.shadowRoot?.querySelector('#select-process'); 160 this.processTree = this.shadowRoot?.querySelector('#processTree'); 161 this.processTree!.onChange = (e: any): void => { 162 const select = this.processTree!.getCheckdKeys(); 163 const selectIPid = Number(select[0]); 164 this.switchDiv!.visible = 'false'; 165 this.updateRangeSelect(selectIPid); 166 this.lastSelectIPid = selectIPid; 167 }; 168 this.buildTabs(this.litTabs); 169 this.litTabs!.onTabClick = (e: any): void => this.loadTabPaneData(e.detail.key); 170 this.tableCloseHandler(); 171 this.rowClickEvent(); 172 } 173 private rowClickEvent(): void { 174 this.getComponentByID<any>('box-spt')?.addEventListener('row-click', this.rowClickHandler.bind(this)); 175 this.getComponentByID<any>('box-pts')?.addEventListener('row-click', this.rowClickHandler.bind(this)); 176 this.getComponentByID<any>('box-perf-analysis')?.addEventListener('row-click', (evt: MouseEvent) => { 177 this.perfAnalysisListener(evt); 178 }); 179 this.getComponentByID<any>('box-native-statistic-analysis')?.addEventListener('row-click', (e: MouseEvent) => { 180 this.nativeAnalysisListener(e); 181 }); 182 this.getComponentByID<any>('box-io-tier-statistics-analysis')?.addEventListener('row-click', (evt: MouseEvent) => { 183 // @ts-ignore 184 if (evt.detail.button === 2) { 185 let pane = this.getPaneByID('box-io-calltree'); 186 this.litTabs!.activeByKey(pane.key); 187 } 188 }); 189 this.getComponentByID<any>('box-virtual-memory-statistics-analysis')?.addEventListener( 190 'row-click', 191 (evt: MouseEvent) => { 192 // @ts-ignore 193 if (evt.detail.button === 2) { 194 let pane = this.getPaneByID('box-vm-calltree'); 195 this.litTabs!.activeByKey(pane.key); 196 } 197 } 198 ); 199 this.getComponentByID<any>('box-file-system-statistics-analysis')?.addEventListener( 200 'row-click', 201 (evt: MouseEvent) => { 202 // @ts-ignore 203 if (evt.detail.button === 2) { 204 let pane = this.getPaneByID('box-file-system-calltree'); 205 this.litTabs!.activeByKey(pane.key); 206 } 207 } 208 ); 209 this.getComponentByID<any>('box-native-statstics')?.addEventListener('row-click', (e: any) => { 210 this.nativeStatsticsListener(e); 211 }); 212 this.getComponentByID<any>('box-virtual-memory-statistics')?.addEventListener('row-click', (e: any) => { 213 this.virtualMemoryListener(e); 214 }); 215 this.getComponentByID<any>('box-io-tier-statistics')?.addEventListener('row-click', (e: any) => { 216 this.ioTierListener(e); 217 }); 218 this.getComponentByID<any>('box-file-system-statistics')?.addEventListener('row-click', (e: any) => { 219 this.fileSystemListener(e); 220 }); 221 } 222 223 private perfAnalysisListener(evt: MouseEvent): void { 224 // @ts-ignore 225 if (evt.detail.button === 2) { 226 let pane = this.getPaneByID('box-perf-profile'); 227 this.litTabs!.activeByKey(pane.key); 228 } 229 } 230 231 private nativeAnalysisListener(e: MouseEvent):void { 232 //@ts-ignore 233 if (e.detail.button === 2) { 234 let pane = this.getPaneByID('box-native-calltree'); 235 pane.hidden = false; 236 this.litTabs!.activeByKey(pane.key); 237 } 238 } 239 240 private nativeStatsticsListener(e: any): void { 241 if (e.detail.button === 0) { 242 this.selection!.statisticsSelectData = e.detail; 243 let pane = this.getPaneByID('box-native-memory'); 244 this.litTabs?.activeByKey(pane.key); 245 (pane.children.item(0) as any)!.fromStastics(this.selection); 246 } 247 } 248 249 private virtualMemoryListener(e: any): void { 250 if (e.detail.button === 0) { 251 this.selection!.fileSystemVMData = {path: e.detail.path}; 252 let pane = this.getPaneByID('box-vm-events'); 253 this.litTabs?.activeByKey(pane.key); 254 if (e.detail.path) { 255 (pane.children.item(0) as any)!.fromStastics(this.selection); 256 } 257 } 258 } 259 260 private ioTierListener(e: any):void { 261 if (e.detail.button === 0) { 262 this.selection!.fileSystemIoData = {path: e.detail.path}; 263 let pane = this.getPaneByID('box-io-events'); 264 this.litTabs?.activeByKey(pane.key); 265 if (e.detail.path) { 266 (pane.children.item(0) as any)!.fromStastics(this.selection); 267 } 268 } 269 } 270 271 private fileSystemListener(e: any): void { 272 if (e.detail.button === 0) { 273 this.selection!.fileSystemFsData = e.detail.data; 274 let pane = this.getPaneByID('box-file-system-event'); 275 this.litTabs?.activeByKey(pane.key); 276 if (e.detail.data) { 277 (pane.children.item(0) as any)!.fromStastics(this.selection); 278 } 279 } 280 } 281 282 private tableCloseHandler(): void { 283 this.litTabs!.addEventListener('close-handler', () => { 284 Reflect.ownKeys(tabConfig) 285 .reverse() 286 .forEach((id) => { 287 let element = tabConfig[id]; 288 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 289 if (element.require) { 290 pane!.hidden = !element.require(this.selection); 291 } else { 292 pane!.hidden = true; 293 } 294 }); 295 this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`); 296 }); 297 } 298 299 connectedCallback(): void { 300 this.nav = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.tab-nav-vessel'); 301 this.tabs = this.shadowRoot?.querySelector('#tabs'); 302 this.navRoot = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.nav-root'); 303 this.search = document.querySelector('body > sp-application') 304 ?.shadowRoot?.querySelector('div > div.search-vessel'); 305 this.timerShaft = this.parentElement?.querySelector('.timer-shaft'); 306 this.spacer = this.parentElement?.querySelector('.spacer'); 307 this.rowsPaneEL = this.parentElement?.querySelector('.rows-pane'); 308 let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#max-btn'); 309 let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#min-btn'); 310 let borderTop: number = 1; 311 let initialHeight = { tabs: `calc(30vh + 39px)`, node: '30vh' }; 312 this.initNavElements(tabsPackUp!, borderTop, initialHeight); 313 this.exportBt = this.shadowRoot?.querySelector<LitIcon>('#export-btn'); 314 tabsOpenUp!.onclick = (): void => { 315 this.tabs!.style.height = window.innerHeight - this.search!.offsetHeight - this.timerShaft!.offsetHeight - borderTop + 'px'; 316 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 317 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 318 litTabpane!.forEach((node: HTMLDivElement): void => { 319 node!.style.height = 320 window.innerHeight - 321 this.search!.offsetHeight - 322 this.timerShaft!.offsetHeight - 323 this.navRoot!.offsetHeight - 324 borderTop + 325 'px'; 326 initialHeight.node = node!.style.height; 327 }); 328 initialHeight.tabs = this.tabs!.style.height; 329 tabsPackUp!.name = 'down'; 330 }; 331 tabsPackUp!.onclick = (): void => { 332 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 333 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 334 if (tabsPackUp!.name == 'down') { 335 this.tabs!.style.height = this.navRoot!.offsetHeight + 'px'; 336 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = '0px')); 337 tabsPackUp!.name = 'up'; 338 tabsPackUp!.title = 'Reset Tab'; 339 (window as any).isPackUpTable = true; 340 } else { 341 tabsPackUp!.name = 'down'; 342 tabsPackUp!.title = 'Minimize Tab'; 343 this.tabs!.style.height = initialHeight.tabs; 344 litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = initialHeight.node)); 345 } 346 }; 347 this.importClickEvent(); 348 this.exportClickEvent(); 349 } 350 351 private initNavElements(tabsPackUp: LitIcon, borderTop: number, initialHeight: { node: string; tabs: string }): void { 352 let that = this; 353 this.nav!.onmousedown = (event): void => { 354 (window as any).isSheetMove = true; 355 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = 356 this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); 357 this.navMouseMove(event, litTabpane!, that, tabsPackUp, borderTop); 358 document.onmouseup = function (): void { 359 setTimeout(() => { 360 (window as any).isSheetMove = false; 361 }, 100); 362 litTabpane!.forEach((node: HTMLDivElement): void => { 363 if (node!.style.height !== '0px' && that.tabs!.style.height !== '') { 364 initialHeight.node = node!.style.height; 365 initialHeight.tabs = that.tabs!.style.height; 366 } 367 }); 368 this.onmousemove = null; 369 this.onmouseup = null; 370 }; 371 }; 372 } 373 374 private navMouseMove(event: MouseEvent, litTabpane: NodeListOf<HTMLDivElement>, 375 that: this, tabsPackUp: LitIcon, borderTop: number): void { 376 let preY = event.pageY; 377 let preHeight = this.tabs!.offsetHeight; 378 document.onmousemove = function (event): void { 379 let moveY: number = preHeight - (event.pageY - preY); 380 litTabpane!.forEach((node: HTMLDivElement) => { 381 if (that.spacer!.offsetHeight > that.rowsPaneEL!.offsetHeight) { 382 that.tabs!.style.height = moveY + 'px'; 383 node!.style.height = moveY - that.navRoot!.offsetHeight + 'px'; 384 tabsPackUp!.name = 'down'; 385 } else if ( 386 that.navRoot!.offsetHeight <= moveY && 387 that.search!.offsetHeight + that.timerShaft!.offsetHeight + borderTop + that.spacer!.offsetHeight <= 388 window.innerHeight - moveY 389 ) { 390 that.tabs!.style.height = moveY + 'px'; 391 node!.style.height = moveY - that.navRoot!.offsetHeight + 'px'; 392 tabsPackUp!.name = 'down'; 393 } else if (that.navRoot!.offsetHeight >= moveY) { 394 that.tabs!.style.height = that.navRoot!.offsetHeight + 'px'; 395 node!.style.height = '0px'; 396 tabsPackUp!.name = 'up'; 397 } else if ( 398 that.search!.offsetHeight + that.timerShaft!.offsetHeight + borderTop + that.spacer!.offsetHeight >= 399 window.innerHeight - moveY 400 ) { 401 that.tabs!.style.height = 402 window.innerHeight - 403 that.search!.offsetHeight - 404 that.timerShaft!.offsetHeight - 405 borderTop - 406 that.spacer!.offsetHeight + 407 'px'; 408 node!.style.height = 409 window.innerHeight - 410 that.search!.offsetHeight - 411 that.timerShaft!.offsetHeight - 412 that.navRoot!.offsetHeight - 413 borderTop - 414 that.spacer!.offsetHeight + 415 'px'; 416 tabsPackUp!.name = 'down'; 417 } 418 }); 419 }; 420 } 421 422 private importClickEvent(): void { 423 let importFileBt: HTMLInputElement | undefined | null = 424 this.shadowRoot?.querySelector<HTMLInputElement>('#import-file'); 425 importFileBt!.addEventListener('change', (event): void => { 426 let files = importFileBt?.files; 427 if (files) { 428 let fileList: Array<File> = []; 429 for (let file of files) { 430 if (file.name.endsWith('.so')) { 431 fileList.push(file); 432 } 433 } 434 if (fileList.length > 0) { 435 importFileBt!.disabled = true; 436 window.publish(window.SmartEvent.UI.Loading, { loading: true, text: 'Import So File' }); 437 threadPool.submit( 438 'upload-so', 439 '', 440 fileList, 441 (res: string) => { 442 importFileBt!.disabled = false; 443 if (res === 'ok') { 444 window.publish(window.SmartEvent.UI.UploadSOFile, {}); 445 } else { 446 window.publish(window.SmartEvent.UI.Error, 'parse so file failed!'); 447 } 448 }, 449 'upload-so' 450 ); 451 } 452 fileList.length = 0; 453 } 454 importFileBt!.files = null; 455 importFileBt!.value = ''; 456 }); 457 } 458 459 private exportClickEvent(): void { 460 this.exportBt!.onclick = (): void => { 461 let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!); 462 if (currentTab) { 463 let table1 = Array.from( 464 (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitPageTable>('lit-page-table') || [] 465 ); 466 let table2 = Array.from( 467 (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 468 ); 469 let tables = [...table1, ...table2]; 470 471 for (let table of tables) { 472 if (!table.hasAttribute('hideDownload')) { 473 table.exportData(); 474 } 475 } 476 } 477 }; 478 } 479 480 getTabpaneByKey(key: string): LitTabpane | undefined { 481 let tabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 482 return tabs.find((it) => it.key === key); 483 } 484 485 initHtml(): string { 486 return ` 487 <style> 488 :host([mode='hidden']){ 489 display: none; 490 } 491 :host{ 492 display: block; 493 background-color: rebeccapurple; 494 } 495 .tabHeight{ 496 height: 30vh; 497 background-color: var(--dark-background,#FFFFFF); 498 } 499 #check-popover[visible="true"] #check-des{ 500 color: #0A59F7; 501 } 502 .popover{ 503 color: var(--dark-color1,#4b5766); 504 justify-content: center; 505 align-items: center; 506 margin-right: 10px; 507 z-index: 2; 508 } 509 </style> 510 <div id="vessel" style="border-top: 1px solid var(--dark-border1,#D5D5D5);"> 511 <lit-tabs id="tabs" position="top-left" activekey="1" mode="card" > 512 <div slot="right" style="margin: 0 10px; color: var(--dark-icon,#606060);display: flex;align-items: center;"> 513 <lit-popover placement="bottomRight" class="popover" haveRadio="true" trigger="click" id="select-process"> 514 <div slot="content"> 515 <lit-tree id="processTree" checkable="true"></lit-tree> 516 </div> 517 <lit-icon name="setting" size="20" id="setting"></lit-icon> 518 </lit-popover> 519 <div title="Import SO" id="import_div" style="width: 20px;height: 20px;display: flex;flex-direction: row;margin-right: 10px"> 520 <input id="import-file" style="display: none;pointer-events: none" type="file" webkitdirectory> 521 <label style="width: 20px;height: 20px;cursor: pointer;" for="import-file"> 522 <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20"> 523 </lit-icon> 524 </label> 525 </div> 526 <lit-icon title="Download Table" id="export-btn" name="import-so" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 527 </lit-icon> 528 <lit-icon title="Maximize Tab" id="max-btn" name="vertical-align-top" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20"> 529 </lit-icon> 530 <lit-icon title="Minimize Tab" id="min-btn" name="down" style="font-weight: bold;cursor: pointer;" size="20"> 531 </lit-icon> 532 </div> 533 </lit-tabs> 534 </div>`; 535 } 536 displayCurrent = (data: SlicesTime): void => 537 this.displayTab<TabPaneCurrent>('tabpane-current').setCurrentSlicesTime(data); 538 displayThreadData = ( 539 data: ThreadStruct, 540 scrollCallback: ((e: ThreadStruct) => void) | undefined, 541 scrollWakeUp: (d: any) => void | undefined, 542 callback: ((data: Array<any>) => void) | undefined = undefined 543 ) => 544 this.displayTab<TabPaneCurrentSelection>('current-selection').setThreadData( 545 data, 546 scrollCallback, 547 scrollWakeUp, 548 callback 549 ); 550 displayMemData = (data: ProcessMemStruct): void => 551 this.displayTab<TabPaneCurrentSelection>('current-selection').setMemData(data); 552 displayClockData = (data: ClockStruct): void => 553 this.displayTab<TabPaneCurrentSelection>('current-selection').setClockData(data); 554 displayIrqData = (data: IrqStruct): void => 555 this.displayTab<TabPaneCurrentSelection>('current-selection').setIrqData(data); 556 displayStartupData = (data: AppStartupStruct, scrollCallback: Function): void => 557 this.displayTab<TabPaneCurrentSelection>('current-selection').setStartupData(data, scrollCallback); 558 displayAllStartupData = (data: AllAppStartupStruct, scrollCallback: Function): void => 559 this.displayTab<TabPaneCurrentSelection>('current-selection').setAllStartupData(data, scrollCallback); 560 displayStaticInitData = (data: SoStruct, scrollCallback: Function): void => 561 this.displayTab<TabPaneCurrentSelection>('current-selection').setStaticInitData(data, scrollCallback); 562 563 displayNativeHookData = (data: HeapStruct, rowType: string, ipid: number): void => { 564 let val = new SelectionParam(); 565 val.nativeMemoryStatistic.push(rowType); 566 val.nativeMemoryCurrentIPid = ipid; 567 val.nativeMemory = []; 568 val.leftNs = data.startTime!; 569 val.rightNs = data.dur === 0 ? data.startTime! : data.startTime! + data.dur! - 1; 570 this.selection = val; 571 this.displayTab<TabPaneNMStatisticAnalysis>('box-native-statistic-analysis', 'box-native-calltree').data = val; 572 this.showUploadSoBt(val); 573 this.showSwitchProcessBt(val); 574 }; 575 576 displayGpuSelectedData = (type: string, startTs: number, dataList: Array<SnapshotStruct>): void => { 577 this.displayTab<TabPaneGpuClickSelectComparison>('gpu-click-select-comparison').getGpuClickDataByDB( 578 type, 579 startTs, 580 dataList 581 ); 582 let dataObject = { type: type, startTs: startTs }; 583 this.displayTab<TabPaneGpuClickSelect>('gpu-click-select', 'gpu-click-select-comparison').gpuClickData(dataObject); 584 }; 585 586 displayFuncData = (names: string[], data: FuncStruct, scrollCallback: Function): void => 587 this.displayTab<TabPaneCurrentSelection>(...names).setFunctionData(data, scrollCallback); 588 displayCpuData = ( 589 data: CpuStruct, 590 callback: ((data: WakeupBean | null) => void) | undefined = undefined, 591 scrollCallback?: (data: CpuStruct) => void 592 ): void => this.displayTab<TabPaneCurrentSelection>('current-selection').setCpuData(data, callback, scrollCallback); 593 displayJankData = ( 594 data: JankStruct, 595 callback: ((data: Array<any>) => void) | undefined = undefined, 596 scrollCallback: ((e: JankStruct) => void) | undefined 597 ): void => this.displayTab<TabPaneCurrentSelection>('current-selection').setJankData(data, callback, scrollCallback); 598 displayShmData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 599 this.displayTab<TabPaneVmTrackerShmComparison>('box-vmtracker-shm-comparison').setShmData(data, dataList); 600 this.displayTab<TabPaneVmTrackerShmSelection>( 601 'box-vmtracker-shm-selection', 602 'box-vmtracker-shm-comparison' 603 ).setShmData(data, dataList); 604 }; 605 displaySmapsData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 606 let val = new SelectionParam(); 607 val.smapsType = []; 608 val.leftNs = data.startNs; 609 this.selection = val; 610 val.smapsType = []; 611 this.displayTab<TabPaneSmapsComparison>('box-smaps-comparison').setData(val, dataList); 612 this.displayTab<TabPaneSmapsStatistics>( 613 'box-smaps-statistics', 614 'box-smaps-sample', 615 'box-smaps-comparison', 616 'box-smaps-record' 617 ).data = val; 618 }; 619 displaySnapshotData = ( 620 data: HeapSnapshotStruct, 621 dataListCache: Array<HeapSnapshotStruct>, 622 scrollCallback?: (data: HeapSnapshotStruct, dataListCache: Array<HeapSnapshotStruct>) => void 623 ): void => { 624 if (dataListCache.length > 1) { 625 this.displayTab<TabPaneSummary>('box-heap-summary', 'box-heap-comparison').setSnapshotData( 626 data, 627 dataListCache, 628 scrollCallback 629 ); 630 let nav = this.shadowRoot!.querySelector('#tabs')!.shadowRoot!.querySelector( 631 '#nav > #nav-comparison' 632 ) as HTMLDivElement; 633 let tabPaneComparison = this.shadowRoot!.querySelector( 634 '#box-heap-comparison > tabpane-comparison' 635 ) as TabPaneComparison; 636 nav!.onclick = (): void => { 637 tabPaneComparison.initComparison(data, dataListCache); 638 }; 639 } else { 640 this.displayTab<TabPaneSummary>('box-heap-summary').setSnapshotData(data, dataListCache, scrollCallback); 641 } 642 }; 643 displayFlagData = (flagObj: Flag): void => this.displayTab<TabPaneFlag>('box-flag').setCurrentFlag(flagObj); 644 displayFreqData = (): CpuFreqStruct | undefined => 645 (this.displayTab<TabPaneCurrentSelection>('box-freq').data = CpuFreqStruct.selectCpuFreqStruct); 646 displayCpuStateData = (): CpuStateStruct | undefined => 647 (this.displayTab<TabPaneCurrentSelection>('cpu-state-click').data = CpuStateStruct.selectStateStruct); 648 displayFreqLimitData = (): CpuFreqLimitsStruct | undefined => 649 (this.displayTab<TabPaneCurrentSelection>('box-freq-limit').data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct); 650 651 displayFrameAnimationData = (data: FrameAnimationStruct): Promise<void> => 652 this.displayTab<TabPaneCurrentSelection>('current-selection').setFrameAnimationData(data); 653 displayFrameDynamicData = (row: TraceRow<FrameDynamicStruct>, data: FrameDynamicStruct): void => 654 this.displayTab<TabPaneFrameDynamic>('box-frame-dynamic').buildDynamicTable([data], true); 655 displayFrameSpacingData = (data: FrameSpacingStruct): void => 656 this.displayTab<TabFrameSpacing>('box-frames-spacing').setFrameSpacingData(data); 657 displayJsProfilerData = (data: Array<JsCpuProfilerChartFrame>): void => { 658 let val = new SelectionParam(); 659 val.jsCpuProfilerData = data; 660 this.selection = val; 661 this.displayTab<TabPaneJsCpuStatistics>( 662 'box-js-Profiler-statistics', 663 'box-js-Profiler-bottom-up', 664 'box-js-Profiler-top-down' 665 ).data = data; 666 }; 667 displayPurgTotalAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 668 data.type = 'ability'; 669 this.displayTab<TabPanePurgTotalComparisonAbility>('box-purgeable-total-comparison-ability').totalData( 670 data, 671 dataList 672 ); 673 this.displayTab<TabPanePurgTotalSelection>( 674 'box-purgeable-total-selection', 675 'box-purgeable-total-comparison-ability' 676 ).data = data; 677 }; 678 displayPurgPinAbilityData = (data: SnapshotStruct, dataList: Array<SnapshotStruct>): void => { 679 data.type = 'ability'; 680 this.displayTab<TabPanePurgPinComparisonAbility>('box-purgeable-pin-comparison-ability').totalData(data, dataList); 681 this.displayTab<TabPanePurgPinSelection>( 682 'box-purgeable-pin-selection', 683 'box-purgeable-pin-comparison-ability' 684 ).data = data; 685 }; 686 displayPurgTotalVMData = (data: SnapshotStruct, dataListCache: Array<SnapshotStruct>): void => { 687 data.type = 'VM'; 688 this.displayTab<TabPanePurgTotalComparisonVM>('box-purgeable-total-comparison-vm').totalData(data, dataListCache); 689 this.displayTab<TabPanePurgTotalSelection>( 690 'box-purgeable-total-selection', 691 'box-purgeable-total-comparison-vm' 692 ).data = data; 693 }; 694 displayPurgPinVMData = (data: SnapshotStruct, dataListCache: Array<SnapshotStruct>): void => { 695 data.type = 'VM'; 696 this.displayTab<TabPanePurgPinComparisonVM>('box-purgeable-pin-comparison-vm').totalData(data, dataListCache); 697 this.displayTab<TabPanePurgPinSelection>('box-purgeable-pin-selection', 'box-purgeable-pin-comparison-vm').data = 698 data; 699 }; 700 displayDmaAbility = (data: number, dataList: Array<SnapshotStruct>): void => { 701 if (dataList.length > 0) { 702 this.displayTab<TabPaneDmaAbilityComparison>('box-dma-ability-comparison').comparisonDataByDB(data, dataList); 703 this.displayTab<TabPaneDmaSelectAbility>( 704 'box-dma-selection-ability', 705 'box-dma-ability-comparison' 706 ).queryDmaClickDataByDB(data); 707 } else { 708 this.displayTab<TabPaneDmaSelectAbility>('box-dma-selection-ability').queryDmaClickDataByDB(data); 709 } 710 }; 711 displayDmaVmTracker = (data: number, dataListCache: Array<SnapshotStruct>): void => { 712 if (dataListCache.length > 0) { 713 this.displayTab<TabPaneDmaVmTrackerComparison>('box-vmTracker-comparison').comparisonDataByDB( 714 data, 715 dataListCache 716 ); 717 this.displayTab<TabPaneDmaSelectVmTracker>( 718 'box-dma-selection-vmTracker', 719 'box-vmTracker-comparison' 720 ).queryDmaVmTrackerClickDataByDB(data); 721 } else { 722 this.displayTab<TabPaneDmaSelectVmTracker>('box-dma-selection-vmTracker').queryDmaVmTrackerClickDataByDB(data); 723 } 724 }; 725 displayGpuMemoryAbility = (data: number, dataList: Array<SnapshotStruct>): void => { 726 if (dataList.length > 0) { 727 this.displayTab<TabPaneGpuMemoryComparison>('box-gpu-memory-comparison').comparisonDataByDB(data, dataList); 728 this.displayTab<TabPaneGpuMemorySelectAbility>( 729 'box-gpu-memory-selection-ability', 730 'box-gpu-memory-comparison' 731 ).queryGpuMemoryClickDataByDB(data); 732 } else { 733 this.displayTab<TabPaneGpuMemorySelectAbility>('box-gpu-memory-selection-ability').data = data; 734 } 735 }; 736 displayGpuMemoryVmTracker = (data: number, dataListCache: Array<SnapshotStruct>): void => { 737 if (dataListCache.length > 0) { 738 this.displayTab<TabPaneGpuMemoryVmTrackerComparison>('box-gpu-memory-vmTracker-comparison').comparisonDataByDB( 739 data, 740 dataListCache 741 ); 742 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 743 'box-gpu-memory-selection-vmTracker', 744 'box-gpu-memory-vmTracker-comparison' 745 ).queryGpuMemoryVmTrackerClickDataByDB(data); 746 } else { 747 this.displayTab<TabPaneGpuMemorySelectVmTracker>( 748 'box-gpu-memory-selection-vmTracker' 749 ).queryGpuMemoryVmTrackerClickDataByDB(data); 750 } 751 }; 752 displayGpuResourceVmTracker = (data: number) => { 753 this.displayTab<TabPaneGpuResourceVmTracker>('box-smaps-gpu-resource').data = data; 754 }; 755 756 displaySystemLogsData = (): void => { 757 let tblHiLogPanel = this.shadowRoot?.querySelector<LitTabpane>("lit-tabpane[id='box-hilogs']"); 758 if (tblHiLogPanel) { 759 let tblHiLog = tblHiLogPanel.querySelector<TabPaneHiLogs>('tab-hi-log'); 760 if (tblHiLog) { 761 tblHiLog.initTabSheetEl(this); 762 } 763 } 764 }; 765 766 rangeSelect(selection: SelectionParam, restore = false): boolean { 767 this.selection = selection; 768 this.exportBt!.style.display = 'flex'; 769 this.showUploadSoBt(selection); 770 this.showSwitchProcessBt(selection); 771 Reflect.ownKeys(tabConfig) 772 .reverse() 773 .forEach((id) => { 774 let element = tabConfig[id]; 775 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 776 if (pane) { 777 pane.hidden = !(element.require && element.require(selection)); 778 } 779 }); 780 if (restore) { 781 if (this.litTabs?.activekey) { 782 this.loadTabPaneData(this.litTabs?.activekey); 783 this.setAttribute('mode', 'max'); 784 return true; 785 } else { 786 this.setAttribute('mode', 'hidden'); 787 return false; 788 } 789 } else { 790 let firstPane = this.shadowRoot!.querySelector<LitTabpane>(`lit-tabpane[hidden='false']`); 791 if (firstPane) { 792 this.litTabs?.activeByKey(firstPane.key); 793 this.loadTabPaneData(firstPane.key); 794 this.setAttribute('mode', 'max'); 795 return true; 796 } else { 797 this.setAttribute('mode', 'hidden'); 798 return false; 799 } 800 } 801 } 802 803 updateRangeSelect(ipid?: number): boolean { 804 if ( 805 this.selection && 806 (this.selection.nativeMemory.length > 0 || 807 this.selection.nativeMemoryStatistic.length > 0 || 808 this.selection.perfSampleIds.length > 0 || 809 this.selection.fileSystemType.length > 0 || 810 this.selection.fsCount > 0 || 811 this.selection.fileSysVirtualMemory || 812 this.selection.vmCount > 0 || 813 this.selection.diskIOLatency || 814 this.selection.diskIOipids.length > 0) 815 ) { 816 let param: SelectionParam = new SelectionParam(); 817 Object.assign(param, this.selection); 818 if (param.nativeMemory.length > 0 || param.nativeMemoryStatistic.length > 0) { 819 Utils.getInstance().initResponseTypeList(param); 820 if (ipid) { 821 Utils.getInstance().setCurrentSelectIPid(ipid); 822 param.nativeMemoryCurrentIPid = ipid; 823 } 824 } 825 this.rangeSelect(param, true); 826 return true; 827 } else { 828 return false; 829 } 830 } 831 832 showUploadSoBt(selection: SelectionParam | null | undefined): void { 833 if ( 834 selection && 835 (selection.nativeMemory.length > 0 || 836 selection.nativeMemoryStatistic.length > 0 || 837 selection.perfSampleIds.length > 0 || 838 selection.fileSystemType.length > 0 || 839 selection.fsCount > 0 || 840 selection.fileSysVirtualMemory || 841 selection.vmCount > 0 || 842 selection.diskIOLatency || 843 selection.diskIOipids.length > 0) 844 ) { 845 this.importDiv!.style.display = 'flex'; 846 } else { 847 this.importDiv!.style.display = 'none'; 848 } 849 } 850 isProcessEqual(treeData: Array<{ pid: number; ipid: number }>): boolean { 851 if (treeData.length !== this.lastProcessSet.size) { 852 return false; 853 } 854 for (let process of treeData) { 855 if (!this.lastProcessSet.has(process.pid)) { 856 return false; 857 } 858 } 859 return true; 860 } 861 862 showSwitchProcessBt(selection: SelectionParam | null | undefined): void { 863 // 2个及以上进程再显示 864 if (selection && selection.nativeMemoryAllProcess.length > 1) { 865 this.switchDiv!.style.display = 'flex'; 866 if (this.isProcessEqual(selection.nativeMemoryAllProcess)) { 867 if (this.processTree) { 868 for (const data of this.processTree.treeData) { 869 if (data.key === `${selection.nativeMemoryCurrentIPid}`) { 870 data.checked = true; 871 } else { 872 data.checked = false; 873 } 874 } 875 //调用set重新更新界面 876 this.processTree.treeData = this.processTree.treeData; 877 } 878 return; 879 } 880 this.lastProcessSet = new Set<number>(); 881 const processArray: Array<TreeItemData> = []; 882 let isFirst: boolean = true; 883 for (let process of selection.nativeMemoryAllProcess) { 884 const treeData: TreeItemData = { 885 key: `${process.ipid}`, 886 title: `Process ${process.pid}`, 887 checked: isFirst, 888 }; 889 if (isFirst) { 890 this.lastSelectIPid = process.ipid; 891 isFirst = false; 892 } 893 processArray.push(treeData); 894 this.lastProcessSet.add(process.pid); 895 } 896 this.processTree!.treeData = processArray; 897 } else { 898 this.switchDiv!.style.display = 'none'; 899 } 900 } 901 902 loadTabPaneData(key: string): void { 903 let component: any = this.shadowRoot 904 ?.querySelector<LitTabpane>(`#tabs lit-tabpane[key='${key}']`) 905 ?.children.item(0); 906 if (component) { 907 component.data = this.selection; 908 if (this.selection) { 909 this.selection.isRowClick = false; 910 } 911 } 912 } 913 914 rowClickHandler(e: any): void { 915 this.currentPaneID = e.target.parentElement.id; 916 this.shadowRoot!.querySelectorAll<LitTabpane>(`lit-tabpane`).forEach((it) => 917 it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) 918 ); 919 let pane = this.getPaneByID('box-cpu-child'); 920 pane.closeable = true; 921 pane.hidden = false; 922 this.litTabs!.activeByKey(pane.key); 923 pane.tab = Utils.transferPTSTitle(e.detail.title); 924 let param = new BoxJumpParam(); 925 param.leftNs = this.selection!.leftNs; 926 param.rightNs = this.selection!.rightNs; 927 param.cpus = this.selection!.cpus; 928 param.state = e.detail.state; 929 param.processId = e.detail.pid; 930 param.threadId = e.detail.tid; 931 (pane.children.item(0) as TabPaneBoxChild).data = param; 932 } 933 934 clearMemory(): void { 935 let allTabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []); 936 allTabs.forEach((tab) => { 937 if (tab) { 938 let tables = Array.from( 939 (tab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || [] 940 ); 941 for (let table of tables) { 942 table.recycleDataSource = []; 943 } 944 } 945 }); 946 } 947} 948