• 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 (typeof stack.symbol === 'number') {
110          stack.symbol = SpSystemTrace.DATA_DICT.get(stack.symbol) || '';
111        } // @ts-ignore
112        let files = (perfDataQuery.filesData[stack.fileId] ?? []) as Array<PerfFile>;
113        stack.path = files[stack.symbolId]?.path || '';
114        stack.type = stack.path.endsWith('.so.1') || stack.path.endsWith('.dll') || stack.path.endsWith('.so') ? 0 : 1;
115      }
116      this.tblData!.dataSource = result;
117    });
118  }
119
120  initElements(): void {
121    this.perfSampleTbl = this.shadowRoot?.querySelector<LitTable>('#tb-perf-sample');
122    this.tblData = this.shadowRoot?.querySelector<LitTable>('#tb-stack-data');
123    this.perfSampleTbl!.addEventListener('row-click', (e) => {
124      // @ts-ignore
125      let data = e.detail.data as PerfSample;
126      this.setRightTableData(data);
127    });
128    this.perfSampleTbl!.addEventListener('column-click', (evt) => {
129      // @ts-ignore
130      this.sortKey = evt.detail.key;
131      // @ts-ignore
132      this.sortType = evt.detail.sort;
133      // @ts-ignore
134      this.sortPerfSampleTable(evt.detail.key, evt.detail.sort);
135    });
136  }
137
138  connectedCallback(): void {
139    super.connectedCallback();
140    new ResizeObserver(() => {
141      if (this.parentElement?.clientHeight !== 0) {
142        // @ts-ignore
143        this.perfSampleTbl?.shadowRoot.querySelector('.table').style.height = `${
144          this.parentElement!.clientHeight - 40
145        }px`;
146        // @ts-ignore
147        this.tblData?.shadowRoot.querySelector('.table').style.height = `${this.parentElement.clientHeight - 25}px`;
148        this.perfSampleTbl?.reMeauseHeight();
149        this.tblData?.reMeauseHeight();
150      }
151    }).observe(this.parentElement!);
152  }
153
154  sortPerfSampleTable(key: string, type: number): void {
155    this.perfSampleSource.sort((perfSampleA, perfSampleB): number => {
156      if (key === 'timeString') {
157        if (type === 0) {
158          return perfSampleA.time - perfSampleB.time;
159        } else if (type === 1) {
160          return perfSampleA.time - perfSampleB.time;
161        } else {
162          return perfSampleB.time - perfSampleA.time;
163        }
164      } else {
165        if (type === 0) {
166          return perfSampleA.core - perfSampleB.core;
167        } else if (type === 1) {
168          return perfSampleA.core - perfSampleB.core;
169        } else {
170          return perfSampleB.core - perfSampleA.core;
171        }
172      }
173    });
174    this.perfSampleTbl!.recycleDataSource = this.perfSampleSource;
175  }
176
177  initHtml(): string {
178    return `<style>
179:host{
180    display: flex;
181    flex-direction: column;
182    padding: 10px 10px;
183}
184</style>
185<div class="perf-sample-content" style="display: flex;flex-direction: row">
186    <lit-slicer style="width:100%">
187    <div id="left_table" style="width: 65%">
188        <tab-native-data-modal style="display:none;"/></tab-native-data-modal>
189        <lit-table id="tb-perf-sample" style="height: auto">
190            <lit-table-column class="perf-sample-column" order width="1fr" title="Sample Time"
191            data-index="timeString" key="timeString" align="flex-start" ></lit-table-column>
192            <lit-table-column class="perf-sample-column" order width="70px" title="Core"
193            data-index="coreName" key="coreName" align="flex-start" ></lit-table-column>
194            <lit-table-column class="perf-sample-column" width="1fr" title="Process"
195            data-index="processName" key="processName" align="flex-start" ></lit-table-column>
196            <lit-table-column class="perf-sample-column" width="1fr" title="Thread"
197            data-index="threadName" key="threadName" align="flex-start" ></lit-table-column>
198            <lit-table-column class="perf-sample-column" width="1fr" title="State"
199            data-index="state" key="state" align="flex-start" ></lit-table-column>
200            <lit-table-column class="perf-sample-column" width="1fr" title="Backtrace"
201            data-index="backtrace" key="backtrace" align="flex-start" >
202                <template>
203                    <div>
204                        <span class="title-span">{{backtrace[0]}}</span>
205                        <span v-if="backtrace.length > 1">⬅</span>
206                        <span v-if="backtrace.length > 1" style="color: #565656"> {{backtrace[1]}}</span>
207                    </div>
208                </template>
209            </lit-table-column>
210        </lit-table>
211    </div>
212    <lit-slicer-track ></lit-slicer-track>
213    <lit-table id="tb-stack-data" hideDownload no-head
214    style="height: auto;border-left: 1px solid var(--dark-border1,#e2e2e2)">
215        <lit-table-column width="60px" title="" data-index="type" key="type"  align="flex-start" >
216            <template>
217                <img src="img/library.png" size="20" v-if=" type == 1 ">
218                <img src="img/function.png" size="20" v-if=" type == 0 ">
219            </template>
220        </lit-table-column>
221        <lit-table-column width="1fr" title="" data-index="symbol" key="symbol"  align="flex-start"></lit-table-column>
222    </lit-table>
223    </lit-slicer>
224</div>`;
225  }
226}
227