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