• 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 { LitTable } from '../../../../../base-ui/table/lit-table';
18import { SelectionParam } from '../../../../bean/BoxSelection';
19import { perfDataQuery } from '../../../chart/PerfDataQuery';
20import { PerfFile, PerfSample, PerfThread } from '../../../../bean/PerfProfile';
21import { Utils } from '../../base/Utils';
22import { log } from '../../../../../log/Log';
23import '../../../../../base-ui/slicer/lit-slicer';
24import { SpSystemTrace } from '../../../SpSystemTrace';
25import {
26  queryPerfProcess,
27  queryPerfSampleCallChain,
28  queryPerfSampleListByTimeRange,
29} from '../../../../database/sql/Perf.sql';
30
31@element('tabpane-perf-sample')
32export class TabPanePerfSample extends BaseElement {
33  private perfSampleTbl: LitTable | null | undefined;
34  private tblData: LitTable | null | undefined;
35  private perfSampleSource: Array<PerfSample> = [];
36  private processMap: Map<number, PerfThread> = new Map<number, PerfThread>();
37  private sortKey: string = 'timeString';
38  private sortType: number = 0;
39
40  set data(perfSampleSelection: SelectionParam | null | undefined) {
41    this.perfSampleTbl!.style.visibility = 'visible';
42    // @ts-ignore
43    this.perfSampleTbl?.shadowRoot?.querySelector('.table')?.style?.height = `${
44      this.parentElement!.clientHeight - 40
45    }px`;
46    this.perfSampleTbl!.recycleDataSource = [];
47    // @ts-ignore
48    this.tblData?.shadowRoot?.querySelector('.table')?.style?.height = `${this.parentElement!.clientHeight - 25}px`;
49    this.tblData!.recycleDataSource = [];
50    if (perfSampleSelection) {
51      Promise.all([
52        queryPerfProcess(),
53        queryPerfSampleListByTimeRange(
54          perfSampleSelection.leftNs,
55          perfSampleSelection.rightNs,
56          perfSampleSelection.perfAll ? [] : perfSampleSelection.perfCpus,
57          perfSampleSelection.perfAll ? [] : perfSampleSelection.perfProcess,
58          perfSampleSelection.perfAll ? [] : perfSampleSelection.perfThread,
59          perfSampleSelection.perfEventTypeId
60        ),
61      ]).then((results) => {
62        let processes = results[0] as Array<PerfThread>;
63        log(`queryPerfProcess size : ${processes.length}`);
64        let samples = results[1] as Array<PerfSample>;
65        log(`queryPerfSampleListByTimeRange size : ${samples.length}`);
66        this.processMap.clear();
67        for (let process of processes) {
68          this.processMap.set(process.pid, process);
69        }
70        this.initPerfSampleData(samples);
71      });
72    }
73  }
74
75  private initPerfSampleData(samples: PerfSample[]): void {
76    for (let sample of samples) {
77      let process = this.processMap.get(sample.pid);
78      sample.processName =
79        process === null || process === undefined
80          ? `Process(${sample.pid})`
81          : `${process!.processName || 'Process'}(${sample.pid})`;
82      sample.threadName =
83        sample.threadName === null || sample.threadName === undefined
84          ? `Thread(${sample.tid})`
85          : `${sample.threadName}(${sample.tid})`;
86      sample.coreName = `CPU ${sample.core}`;
87      sample.timeString = Utils.getTimeString(sample.time);
88      sample.backtrace = [];
89      let call = perfDataQuery.callChainMap.get(sample.sampleId);
90      if (call === undefined || call === null) {
91        sample.depth = 0;
92        sample.backtrace.push('No Effective Call Stack');
93      } else {
94        sample.depth = call.depth;
95        if (typeof call.name === 'number') {
96          call.name = SpSystemTrace.DATA_DICT.get(call.name) || '';
97        }
98        sample.backtrace.push(call.name);
99        sample.backtrace.push(`(${sample.depth} other frames)`);
100      }
101    }
102    this.perfSampleSource = samples;
103    this.sortPerfSampleTable(this.sortKey, this.sortType);
104  }
105
106  setRightTableData(sample: PerfSample): void {
107    queryPerfSampleCallChain(sample.sampleId).then((result) => {
108      for (let stack of result) {
109         if (stack.sourceId !== undefined) {
110          stack.sourceFile = SpSystemTrace.DATA_DICT.get(stack.sourceId) || '';
111        }
112        if (typeof stack.symbol === 'number') {
113          stack.symbol = SpSystemTrace.DATA_DICT.get(stack.symbol) || '';
114        }
115        if (stack.sourceFile && stack.lineNumber !== undefined) {
116          stack.symbol = `${stack.symbol}[${stack.sourceFile}(${stack.lineNumber})]`;
117        }
118        //@ts-ignore
119        let files = (perfDataQuery.filesData[stack.fileId] ?? []) as Array<PerfFile>;
120        stack.path = files[stack.symbolId]?.path || '';
121        stack.type = stack.path.endsWith('.so.1') || stack.path.endsWith('.dll') || stack.path.endsWith('.so') ? 0 : 1;
122      }
123      this.tblData!.dataSource = result;
124    });
125  }
126
127  initElements(): void {
128    this.perfSampleTbl = this.shadowRoot?.querySelector<LitTable>('#tb-perf-sample');
129    this.tblData = this.shadowRoot?.querySelector<LitTable>('#tb-stack-data');
130    this.perfSampleTbl!.addEventListener('row-click', (e) => {
131      // @ts-ignore
132      let data = e.detail.data as PerfSample;
133      this.setRightTableData(data);
134    });
135    this.perfSampleTbl!.addEventListener('column-click', (evt) => {
136      // @ts-ignore
137      this.sortKey = evt.detail.key;
138      // @ts-ignore
139      this.sortType = evt.detail.sort;
140      // @ts-ignore
141      this.sortPerfSampleTable(evt.detail.key, evt.detail.sort);
142    });
143  }
144
145  connectedCallback(): void {
146    super.connectedCallback();
147    new ResizeObserver(() => {
148      if (this.parentElement?.clientHeight !== 0) {
149        // @ts-ignore
150        this.perfSampleTbl?.shadowRoot.querySelector('.table').style.height = `${
151          this.parentElement!.clientHeight - 40
152        }px`;
153        // @ts-ignore
154        this.tblData?.shadowRoot.querySelector('.table').style.height = `${this.parentElement.clientHeight - 25}px`;
155        this.perfSampleTbl?.reMeauseHeight();
156        this.tblData?.reMeauseHeight();
157      }
158    }).observe(this.parentElement!);
159  }
160
161  sortPerfSampleTable(key: string, type: number): void {
162    this.perfSampleSource.sort((perfSampleA, perfSampleB): number => {
163      if (key === 'timeString') {
164        if (type === 0) {
165          return perfSampleA.time - perfSampleB.time;
166        } else if (type === 1) {
167          return perfSampleA.time - perfSampleB.time;
168        } else {
169          return perfSampleB.time - perfSampleA.time;
170        }
171      } else {
172        if (type === 0) {
173          return perfSampleA.core - perfSampleB.core;
174        } else if (type === 1) {
175          return perfSampleA.core - perfSampleB.core;
176        } else {
177          return perfSampleB.core - perfSampleA.core;
178        }
179      }
180    });
181    this.perfSampleTbl!.recycleDataSource = this.perfSampleSource;
182  }
183
184  initHtml(): string {
185    return `<style>
186:host{
187    display: flex;
188    flex-direction: column;
189    padding: 10px 10px;
190}
191</style>
192<div class="perf-sample-content" style="display: flex;flex-direction: row">
193    <lit-slicer style="width:100%">
194    <div id="left_table" style="width: 65%">
195        <tab-native-data-modal style="display:none;"/></tab-native-data-modal>
196        <lit-table id="tb-perf-sample" style="height: auto">
197            <lit-table-column class="perf-sample-column" order width="1fr" title="Sample Time"
198            data-index="timeString" key="timeString" align="flex-start" ></lit-table-column>
199            <lit-table-column class="perf-sample-column" order width="70px" title="Core"
200            data-index="coreName" key="coreName" align="flex-start" ></lit-table-column>
201            <lit-table-column class="perf-sample-column" width="1fr" title="Process"
202            data-index="processName" key="processName" align="flex-start" ></lit-table-column>
203            <lit-table-column class="perf-sample-column" width="1fr" title="Thread"
204            data-index="threadName" key="threadName" align="flex-start" ></lit-table-column>
205            <lit-table-column class="perf-sample-column" width="1fr" title="State"
206            data-index="state" key="state" align="flex-start" ></lit-table-column>
207            <lit-table-column class="perf-sample-column" width="1fr" title="Backtrace"
208            data-index="backtrace" key="backtrace" align="flex-start" >
209                <template>
210                    <div>
211                        <span class="title-span">{{backtrace[0]}}</span>
212                        <span v-if="backtrace.length > 1">⬅</span>
213                        <span v-if="backtrace.length > 1" style="color: #565656"> {{backtrace[1]}}</span>
214                    </div>
215                </template>
216            </lit-table-column>
217        </lit-table>
218    </div>
219    <lit-slicer-track ></lit-slicer-track>
220    <lit-table id="tb-stack-data" hideDownload no-head
221    style="height: auto;border-left: 1px solid var(--dark-border1,#e2e2e2)">
222        <lit-table-column width="60px" title="" data-index="type" key="type"  align="flex-start" >
223            <template>
224                <img src="img/library.png" size="20" v-if=" type == 1 ">
225                <img src="img/function.png" size="20" v-if=" type == 0 ">
226            </template>
227        </lit-table-column>
228        <lit-table-column width="1fr" title="" data-index="symbol" key="symbol"  align="flex-start"></lit-table-column>
229    </lit-table>
230    </lit-slicer>
231</div>`;
232  }
233}
234