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