• 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 } 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