• 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.js';
17import { LitTabs } from '../../../../base-ui/tabs/lit-tabs.js';
18import { LitTabpane } from '../../../../base-ui/tabs/lit-tabpane.js';
19import { BoxJumpParam, SelectionParam } from '../../../bean/BoxSelection.js';
20import { TabPaneCurrentSelection } from '../sheet/TabPaneCurrentSelection.js';
21import { TabPaneFlag } from '../timer-shaft/TabPaneFlag.js';
22import { Flag } from '../timer-shaft/Flag.js';
23import { WakeupBean } from '../../../bean/WakeupBean.js';
24import { LitIcon } from '../../../../base-ui/icon/LitIcon.js';
25import { tabConfig } from './TraceSheetConfig.js';
26import { TabPaneBoxChild } from '../sheet/cpu/TabPaneBoxChild.js';
27import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js';
28import { CpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerFreq.js';
29import { CpuFreqLimitsStruct } from '../../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js';
30import { ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread.js';
31import { FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc.js';
32import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem.js';
33import { CpuStateStruct } from '../../../database/ui-worker/ProcedureWorkerCpuState.js';
34import { ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock.js';
35import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq.js';
36import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank.js';
37import { HeapStruct } from '../../../database/ui-worker/ProcedureWorkerHeap.js';
38import { LitTable } from '../../../../base-ui/table/lit-table.js';
39import { threadPool } from '../../../database/SqlLite.js';
40import { HeapSnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js';
41import { TabPaneComparison } from '../sheet/snapshot/TabPaneComparison.js';
42import { TabPaneSummary } from '../sheet/snapshot/TabPaneSummary.js';
43import { TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis.js';
44import { TabPaneCurrent } from '../sheet/TabPaneCurrent.js';
45import { SlicesTime } from '../timer-shaft/SportRuler.js';
46import { AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup.js';
47import { SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit.js';
48@element('trace-sheet')
49export class TraceSheet extends BaseElement {
50  private litTabs: LitTabs | undefined | null;
51  private importDiv: HTMLDivElement | undefined | null;
52  private nav: HTMLDivElement | undefined | null;
53  private selection: SelectionParam | undefined | null;
54  private currentPaneID: string = 'current-selection';
55  private fragment: DocumentFragment | undefined;
56
57  static get observedAttributes() {
58    return ['mode'];
59  }
60
61  buildTabs(litTabs: LitTabs | undefined | null) {
62    this.fragment = document.createDocumentFragment();
63    Reflect.ownKeys(tabConfig).forEach((key, index) => {
64      let pane = new LitTabpane();
65      pane.id = key.toString();
66      pane.className = 'tabHeight';
67      pane.tab = tabConfig[key].title;
68      pane.hidden = true;
69      pane.key = `${tabConfig[key].key || index}`;
70      let cls = tabConfig[key].type;
71      let node = new cls();
72      pane.append(node);
73      this.fragment?.appendChild(pane);
74    });
75    litTabs!.appendChild(this.fragment);
76  }
77
78  displayTab<T>(...names: string[]): T {
79    this.setAttribute('mode', 'max');
80    this.showUploadSoBt(null);
81    this.shadowRoot
82      ?.querySelectorAll<LitTabpane>('#tabs lit-tabpane')
83      .forEach((it) => (it.hidden = !names.some((k) => k === it.id)));
84    let litTabpane = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[id='${names[0]}']`);
85    this.shadowRoot?.querySelector<LitTabs>('#tabs')?.activePane(litTabpane!.key);
86    return litTabpane!.children.item(0) as unknown as T;
87  }
88
89  getComponentByID<T>(id: string): T {
90    return this.getPaneByID(id)!.children.item(0) as unknown as T;
91  }
92
93  getPaneByID(id: string): LitTabpane {
94    return this.shadowRoot!.querySelector(`#${id}`)!;
95  }
96
97  initElements(): void {
98    this.litTabs = this.shadowRoot?.querySelector('#tabs');
99    this.importDiv = this.shadowRoot?.querySelector('#import_div');
100    this.buildTabs(this.litTabs);
101    let minBtn = this.shadowRoot?.querySelector('#min-btn');
102    minBtn?.addEventListener('click', () => {});
103    this.litTabs!.onTabClick = (e: any) => this.loadTabPaneData(e.detail.key);
104    this.litTabs!.addEventListener('close-handler', () => {
105      Reflect.ownKeys(tabConfig)
106        .reverse()
107        .forEach((id) => {
108          let element = tabConfig[id];
109          let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`);
110          if (element.require) {
111            pane!.hidden = !element.require(this.selection);
112          } else {
113            pane!.hidden = true;
114          }
115        });
116      this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`);
117    });
118    this.getComponentByID<any>('box-spt')!.addEventListener('row-click', this.rowClickHandler.bind(this));
119    this.getComponentByID<any>('box-pts')!.addEventListener('row-click', this.rowClickHandler.bind(this));
120    this.getComponentByID<any>('box-native-statstics')!.addEventListener('row-click', (e: any) => {
121      this.selection!.statisticsSelectData = e.detail;
122      let pane = this.getPaneByID('box-native-memory');
123      this.litTabs?.activeByKey(pane.key);
124      (pane.children.item(0) as any)!.fromStastics(this.selection);
125    });
126    this.getComponentByID<any>('box-virtual-memory-statistics')!.addEventListener('row-click', (e: any) => {
127      this.selection!.fileSystemVMData = { path: e.detail.path };
128      let pane = this.getPaneByID('box-vm-events');
129      this.litTabs?.activeByKey(pane.key);
130      if (e.detail.path) {
131        (pane.children.item(0) as any)!.fromStastics(this.selection);
132      }
133    });
134    this.getComponentByID<any>('box-io-tier-statistics')!.addEventListener('row-click', (e: any) => {
135      this.selection!.fileSystemIoData = { path: e.detail.path };
136      let pane = this.getPaneByID('box-io-events');
137      this.litTabs?.activeByKey(pane.key);
138      if (e.detail.path) {
139        (pane.children.item(0) as any)!.fromStastics(this.selection);
140      }
141    });
142    this.getComponentByID<any>('box-file-system-statistics')!.addEventListener('row-click', (e: any) => {
143      this.selection!.fileSystemFsData = e.detail.data;
144      let pane = this.getPaneByID('box-file-system-event');
145      this.litTabs?.activeByKey(pane.key);
146      if (e.detail.data) {
147        (pane.children.item(0) as any)!.fromStastics(this.selection);
148      }
149    });
150  }
151
152  connectedCallback() {
153    this.nav = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.tab-nav-container');
154    let tabs: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#tabs');
155    let navRoot: HTMLDivElement | null | undefined = this.shadowRoot
156      ?.querySelector('#tabs')
157      ?.shadowRoot?.querySelector('.nav-root');
158    let search: HTMLDivElement | undefined | null = document
159      .querySelector('body > sp-application')
160      ?.shadowRoot?.querySelector('div > div.search-container');
161    let timerShaft: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.timer-shaft');
162    let spacer: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.spacer');
163    let rowsPaneEL: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.rows-pane');
164
165    let borderTop: number = 1;
166    let initialHeight = { tabs: `calc(30vh + 39px)`, node: '30vh' };
167    this.nav!.onmousedown = (event) => {
168      (window as any).isSheetMove = true;
169      let litTabpane: NodeListOf<HTMLDivElement> | undefined | null =
170        this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane');
171      let preY = event.pageY;
172      let preHeight = tabs!.offsetHeight;
173      document.onmousemove = function (event) {
174        let moveY: number = preHeight - (event.pageY - preY);
175        litTabpane!.forEach((node: HTMLDivElement) => {
176          if (spacer!.offsetHeight > rowsPaneEL!.offsetHeight) {
177            tabs!.style.height = moveY + 'px';
178            node!.style.height = moveY - navRoot!.offsetHeight + 'px';
179            tabsPackUp!.name = 'down';
180          } else if (
181            navRoot!.offsetHeight <= moveY &&
182            search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight <=
183              window.innerHeight - moveY
184          ) {
185            tabs!.style.height = moveY + 'px';
186            node!.style.height = moveY - navRoot!.offsetHeight + 'px';
187            tabsPackUp!.name = 'down';
188          } else if (navRoot!.offsetHeight >= moveY) {
189            tabs!.style.height = navRoot!.offsetHeight + 'px';
190            node!.style.height = '0px';
191            tabsPackUp!.name = 'up';
192          } else if (
193            search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight >=
194            window.innerHeight - moveY
195          ) {
196            tabs!.style.height =
197              window.innerHeight -
198              search!.offsetHeight -
199              timerShaft!.offsetHeight -
200              borderTop -
201              spacer!.offsetHeight +
202              'px';
203            node!.style.height =
204              window.innerHeight -
205              search!.offsetHeight -
206              timerShaft!.offsetHeight -
207              navRoot!.offsetHeight -
208              borderTop -
209              spacer!.offsetHeight +
210              'px';
211            tabsPackUp!.name = 'down';
212          }
213        });
214      };
215      document.onmouseup = function () {
216        setTimeout(() => {
217          (window as any).isSheetMove = false;
218        }, 100);
219        litTabpane!.forEach((node: HTMLDivElement) => {
220          if (node!.style.height !== '0px' && tabs!.style.height != '') {
221            initialHeight.node = node!.style.height;
222            initialHeight.tabs = tabs!.style.height;
223          }
224        });
225        this.onmousemove = null;
226        this.onmouseup = null;
227      };
228    };
229    let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#max-btn');
230    let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#min-btn');
231    let importFileBt: HTMLInputElement | undefined | null =
232      this.shadowRoot?.querySelector<HTMLInputElement>('#import-file');
233    let exportDataBt: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>('#export-btn');
234    tabsOpenUp!.onclick = () => {
235      tabs!.style.height = window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - borderTop + 'px';
236      let litTabpane: NodeListOf<HTMLDivElement> | undefined | null =
237        this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane');
238      litTabpane!.forEach((node: HTMLDivElement) => {
239        node!.style.height =
240          window.innerHeight -
241          search!.offsetHeight -
242          timerShaft!.offsetHeight -
243          navRoot!.offsetHeight -
244          borderTop +
245          'px';
246        initialHeight.node = node!.style.height;
247      });
248      initialHeight.tabs = tabs!.style.height;
249      tabsPackUp!.name = 'down';
250    };
251    tabsPackUp!.onclick = () => {
252      let litTabpane: NodeListOf<HTMLDivElement> | undefined | null =
253        this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane');
254      if (tabsPackUp!.name == 'down') {
255        tabs!.style.height = navRoot!.offsetHeight + 'px';
256        litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = '0px'));
257        tabsPackUp!.name = 'up';
258        (window as any).isPackUpTable = true;
259      } else {
260        tabsPackUp!.name = 'down';
261        tabs!.style.height = initialHeight.tabs;
262        litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = initialHeight.node));
263      }
264    };
265    importFileBt!.addEventListener('change', (event) => {
266      let files = importFileBt?.files;
267      if (files) {
268        let fileList: Array<File> = [];
269        for (let file of files) {
270          if (file.name.endsWith('.so')) {
271            fileList.push(file);
272          }
273        }
274        if (fileList.length > 0) {
275          importFileBt!.disabled = true;
276          window.publish(window.SmartEvent.UI.Loading, true);
277          threadPool.submit(
278            'upload-so',
279            '',
280            fileList,
281            (res: string) => {
282              importFileBt!.disabled = false;
283              if (res === 'ok') {
284                window.publish(window.SmartEvent.UI.UploadSOFile, {});
285              } else {
286                window.publish(window.SmartEvent.UI.Error, 'parse so file failed!');
287              }
288            },
289            'upload-so'
290          );
291        }
292        fileList.length = 0;
293      }
294      importFileBt!.files = null;
295      importFileBt!.value = '';
296    });
297    exportDataBt!.onclick = () => {
298      let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!);
299      if (currentTab) {
300        let tables = Array.from(
301          (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || []
302        );
303        for (let table of tables) {
304          if (!table.hasAttribute('hideDownload')) {
305            table.exportData();
306          }
307        }
308      }
309    };
310  }
311
312  getTabpaneByKey(key: string): LitTabpane | undefined {
313    let tabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []);
314    return tabs.find((it) => it.key === key);
315  }
316
317  initHtml(): string {
318    return `
319            <style>
320                :host([mode='hidden']){
321                    display: none;
322                }
323                :host{
324                    display: block;
325                    background-color: rebeccapurple;
326                }
327                .tabHeight{
328                    height: 30vh;
329                    background-color: var(--dark-background,#FFFFFF);
330                }
331            </style>
332            <div id="container" style="border-top: 1px solid var(--dark-border1,#D5D5D5);">
333                <lit-tabs id="tabs" position="top-left" activekey="1" mode="card" >
334                    <div slot="right" style="margin: 0 10px; color: var(--dark-icon,#606060);display: flex;align-items: center;">
335                        <div title="SO导入" id="import_div" style="width: 20px;height: 20px;display: flex;flex-direction: row;margin-right: 10px">
336                            <input id="import-file" style="display: none;pointer-events: none" type="file" webkitdirectory>
337                            <label style="width: 20px;height: 20px;cursor: pointer;" for="import-file">
338                                <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20">
339                                </lit-icon>
340                            </label>
341                        </div>
342                        <lit-icon title="下载数据" id="export-btn" name="import-so" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20">
343                        </lit-icon>
344                        <lit-icon title="最大化" id="max-btn" name="vertical-align-top" style="font-weight: bold;cursor: pointer;margin-right: 10px" size="20">
345                        </lit-icon>
346                        <lit-icon title="最小化" id="min-btn" name="down" style="font-weight: bold;cursor: pointer;" size="20">
347                        </lit-icon>
348                    </div>
349                </lit-tabs>
350            </div>`;
351  }
352  displayCurrent = (data: SlicesTime) =>
353    this.displayTab<TabPaneCurrent>('tabpane-current').setCurrentSlicesTime(data);
354  displayThreadData = (
355    data: ThreadStruct,
356    scrollCallback: ((e: ThreadStruct) => void) | undefined,
357    scrollWakeUp: (d: any) => void | undefined
358  ) => this.displayTab<TabPaneCurrentSelection>('current-selection').setThreadData(data, scrollCallback, scrollWakeUp);
359  displayMemData = (data: ProcessMemStruct) =>
360    this.displayTab<TabPaneCurrentSelection>('current-selection').setMemData(data);
361  displayClockData = (data: ClockStruct) =>
362    this.displayTab<TabPaneCurrentSelection>('current-selection').setClockData(data);
363  displayIrqData = (data: IrqStruct) => this.displayTab<TabPaneCurrentSelection>('current-selection').setIrqData(data);
364  displayStartupData = (data: AppStartupStruct, scrollCallback: Function) =>
365    this.displayTab<TabPaneCurrentSelection>('current-selection').setStartupData(data,scrollCallback);
366  displayStaticInitData = (data: SoStruct, scrollCallback: Function) =>
367    this.displayTab<TabPaneCurrentSelection>('current-selection').setStaticInitData(data,scrollCallback);
368
369  displayNativeHookData = (data: HeapStruct, rowType: string) => {
370    let val = new SelectionParam();
371    val.nativeMemoryStatistic.push(rowType);
372    val.nativeMemory = [];
373    val.leftNs = data.startTime!;
374    val.rightNs = data.startTime! + data.dur! - 1;
375    this.selection = val;
376    this.displayTab<TabPaneNMStatisticAnalysis>('box-native-statistic-analysis', 'box-native-calltree').data = val;
377    this.showUploadSoBt(val);
378  };
379
380  displayFuncData = (names: string[], data: FuncStruct, scrollCallback: Function) =>
381    this.displayTab<TabPaneCurrentSelection>(...names).setFunctionData(data, scrollCallback);
382  displayCpuData = (
383    data: CpuStruct,
384    callback: ((data: WakeupBean | null) => void) | undefined = undefined,
385    scrollCallback?: (data: CpuStruct) => void
386  ) => this.displayTab<TabPaneCurrentSelection>('current-selection').setCpuData(data, callback, scrollCallback);
387  displayJankData = (
388    data: JankStruct,
389    callback: ((data: Array<any>) => void) | undefined = undefined,
390    scrollCallback: ((e: JankStruct) => void) | undefined
391  ) => this.displayTab<TabPaneCurrentSelection>('current-selection').setJankData(data, callback, scrollCallback);
392  displaySnapshotData = (
393    data: HeapSnapshotStruct,
394    dataList: Array<HeapSnapshotStruct>,
395    scrollCallback?: (data: HeapSnapshotStruct, dataList: Array<HeapSnapshotStruct>) => void
396  ) => {
397    if (dataList.length > 1) {
398      this.displayTab<TabPaneSummary>('box-heap-summary', 'box-heap-comparison').setSnapshotData(
399        data,
400        dataList,
401        scrollCallback
402      );
403      let nav = this.shadowRoot!.querySelector('#tabs')!.shadowRoot!.querySelector(
404        '#nav > #nav-comparison'
405      ) as HTMLDivElement;
406      let tabPaneComparison = this.shadowRoot!.querySelector(
407        '#box-heap-comparison > tabpane-comparison'
408      ) as TabPaneComparison;
409      nav!.onclick = () => {
410        tabPaneComparison.initComparison(data, dataList);
411      };
412    } else {
413      this.displayTab<TabPaneSummary>('box-heap-summary').setSnapshotData(data, dataList, scrollCallback);
414    }
415  };
416  displayFlagData = (flagObj: Flag) => this.displayTab<TabPaneFlag>('box-flag').setFlagObj(flagObj);
417  displayFreqData = () =>
418    (this.displayTab<TabPaneCurrentSelection>('box-freq').data = CpuFreqStruct.selectCpuFreqStruct);
419  displayCpuStateData = () =>
420    (this.displayTab<TabPaneCurrentSelection>('cpu-state-click').data = CpuStateStruct.selectStateStruct);
421  displayFreqLimitData = () =>
422    (this.displayTab<TabPaneCurrentSelection>('box-freq-limit').data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct);
423
424  rangeSelect(selection: SelectionParam, restore = false): boolean {
425    this.selection = selection;
426    this.showUploadSoBt(selection);
427    Reflect.ownKeys(tabConfig)
428      .reverse()
429      .forEach((id) => {
430        let element = tabConfig[id];
431        if (element.require) {
432          if (element.require(selection)) {
433            let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`);
434            pane!.hidden = false;
435          } else {
436            this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`)!.hidden = true;
437          }
438        } else {
439          this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`)!.hidden = true;
440        }
441      });
442    if (restore) {
443      if (this.litTabs?.activekey) {
444        this.loadTabPaneData(this.litTabs?.activekey);
445        this.setAttribute('mode', 'max');
446        return true;
447      } else {
448        this.setAttribute('mode', 'hidden');
449        return false;
450      }
451    } else {
452      let firstPane = this.shadowRoot!.querySelector<LitTabpane>(`lit-tabpane[hidden='false']`);
453      if (firstPane) {
454        this.litTabs?.activeByKey(firstPane.key);
455        this.loadTabPaneData(firstPane.key);
456        this.setAttribute('mode', 'max');
457        return true;
458      } else {
459        this.setAttribute('mode', 'hidden');
460        return false;
461      }
462    }
463  }
464
465  updateRangeSelect(): boolean {
466    if (
467      this.selection &&
468      (this.selection.nativeMemory.length > 0 ||
469        this.selection.nativeMemoryStatistic.length > 0 ||
470        this.selection.perfSampleIds.length > 0 ||
471        this.selection.fileSystemType.length > 0 ||
472        this.selection.fsCount > 0 ||
473        this.selection.fileSysVirtualMemory ||
474        this.selection.vmCount > 0 ||
475        this.selection.diskIOLatency ||
476        this.selection.diskIOipids.length > 0)
477    ) {
478      let param: SelectionParam = new SelectionParam();
479      Object.assign(param, this.selection);
480      this.rangeSelect(param, true);
481      return true;
482    } else {
483      return false;
484    }
485  }
486
487  showUploadSoBt(selection: SelectionParam | null | undefined) {
488    if (
489      selection &&
490      (selection.nativeMemory.length > 0 ||
491        selection.nativeMemoryStatistic.length > 0 ||
492        selection.perfSampleIds.length > 0 ||
493        selection.fileSystemType.length > 0 ||
494        selection.fsCount > 0 ||
495        selection.fileSysVirtualMemory ||
496        selection.vmCount > 0 ||
497        selection.diskIOLatency ||
498        selection.diskIOipids.length > 0)
499    ) {
500      this.importDiv!.style.display = 'flex';
501    } else {
502      this.importDiv!.style.display = 'none';
503    }
504  }
505
506  loadTabPaneData(key: string) {
507    let component: any = this.shadowRoot
508      ?.querySelector<LitTabpane>(`#tabs lit-tabpane[key='${key}']`)
509      ?.children.item(0);
510    if (component) {
511      component.data = this.selection;
512    }
513  }
514
515  rowClickHandler(e: any) {
516    this.currentPaneID = e.target.parentElement.id;
517    this.shadowRoot!.querySelectorAll<LitTabpane>(`lit-tabpane`).forEach((it) =>
518      it.id != this.currentPaneID ? (it.hidden = true) : (it.hidden = false)
519    );
520    let pane = this.getPaneByID('box-cpu-child');
521    pane.closeable = true;
522    pane.hidden = false;
523    this.litTabs!.activeByKey(pane.key);
524    pane.tab = e.detail.title;
525    let param = new BoxJumpParam();
526    param.leftNs = this.selection!.leftNs;
527    param.rightNs = this.selection!.rightNs;
528    param.state = e.detail.state;
529    param.threadId = e.detail.threadId;
530    param.processId = e.detail.processId;
531    (pane.children.item(0) as TabPaneBoxChild).data = param;
532  }
533
534  clearMemory() {
535    let allTabs = Array.from(this.shadowRoot?.querySelectorAll<LitTabpane>('#tabs lit-tabpane').values() || []);
536    allTabs.forEach(tab => {
537      if (tab) {
538        let tables = Array.from(
539          (tab.firstChild as BaseElement).shadowRoot?.querySelectorAll<LitTable>('lit-table') || []
540        );
541        for (let table of tables) {
542          table.recycleDataSource = [];
543        }
544      }
545    });
546  }
547}
548