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