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