• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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