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 { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; 20import { resizeObserver } from '../SheetUtils'; 21import { SpSystemTrace } from '../../../SpSystemTrace'; 22import { drawLines } from '../../../../database/ui-worker/ProcedureWorkerCommon'; 23import { TraceRow } from '../../base/TraceRow'; 24import { CpuFreqStruct } from '../../../../database/ui-worker/ProcedureWorkerFreq'; 25import { CpuStateStruct } from '../../../../database/ui-worker/cpu/ProcedureWorkerCpuState'; 26import { getTabPaneCounterSampleData } from '../../../../database/sql/Cpu.sql'; 27 28@element('tabpane-counter-sample') 29export class TabPaneCounterSample extends BaseElement { 30 private counterSampleTbl: LitTable | null | undefined; 31 private range: HTMLLabelElement | null | undefined; 32 private loadDataInCache: boolean = true; 33 private selectionParam: SelectionParam | null | undefined; 34 private sampleProgressEL: LitProgressBar | null | undefined; 35 private counterLoadingPage: unknown; 36 private counterLoadingList: number[] = []; 37 private counterSampleSource: unknown[] = []; 38 private counterSortKey: string = 'counter'; 39 private counterSortType: number = 0; 40 private systemTrace: SpSystemTrace | undefined | null; 41 // @ts-ignore 42 private _rangeRow: Array<TraceRow<unknown>> | undefined | null; 43 44 set data(counterSampleValue: SelectionParam | unknown) { 45 if (counterSampleValue === this.selectionParam) { 46 return; 47 } 48 this.sampleProgressEL!.loading = true; 49 // @ts-ignore 50 this.counterLoadingPage.style.visibility = 'visible'; 51 // @ts-ignore 52 this.selectionParam = counterSampleValue; 53 if (this.counterSampleTbl) { 54 // @ts-ignore 55 this.counterSampleTbl.shadowRoot.querySelector('.table').style.height = `${ 56 this.parentElement!.clientHeight - 25 57 }px`; 58 } 59 this.queryDataByDB(counterSampleValue); 60 } 61 // @ts-ignore 62 set rangeTraceRow(rangeRow: Array<TraceRow<unknown>> | undefined) { 63 this._rangeRow = rangeRow; 64 } 65 66 initElements(): void { 67 this.sampleProgressEL = this.shadowRoot!.querySelector<LitProgressBar>('.progressCounter'); 68 this.counterLoadingPage = this.shadowRoot!.querySelector('.loadingCounter'); 69 this.counterSampleTbl = this.shadowRoot!.querySelector<LitTable>('#tb-counter-sample'); 70 this.systemTrace = document 71 .querySelector('body > sp-application') 72 ?.shadowRoot!.querySelector<SpSystemTrace>('#sp-system-trace'); 73 this.counterSampleTbl!.addEventListener('column-click', (evt): void => { 74 // @ts-ignore 75 this.counterSortKey = evt.detail.key; 76 // @ts-ignore 77 this.counterSortType = evt.detail.sort; 78 // @ts-ignore 79 this.sortTable(evt.detail.key, evt.detail.sort); 80 }); 81 this.rowClickEvent(); 82 } 83 84 private rowClickEvent(): void { 85 this.counterSampleTbl!.addEventListener('row-click', (evt): void => { 86 // @ts-ignore 87 let data = evt.detail.data; 88 let path = new Path2D(); 89 if (this._rangeRow && this._rangeRow!.length > 0) { 90 let rangeTraceRow = this._rangeRow!.filter(function (item) { 91 return item.name.includes('State'); 92 }); 93 let cpuStateFilter = []; 94 for (let row of rangeTraceRow!) { 95 let context = row.collect ? this.systemTrace!.canvasFavoritePanelCtx! : this.systemTrace!.canvasPanelCtx!; 96 cpuStateFilter.push(...row.dataListCache); 97 row.canvasSave(context); // @ts-ignore 98 context.clearRect(row.frame.x, row.frame.y, row.frame.width, row.frame.height); // @ts-ignore 99 drawLines(context!, TraceRow.range?.xs || [], row.frame.height, this.systemTrace!.timerShaftEL!.lineColor()); 100 if (row.name.includes('State') && parseInt(row.name.replace(/[^\d]/g, ' ')) === data.cpu) { 101 CpuFreqStruct.hoverCpuFreqStruct = undefined; 102 for (let i = 0; i < cpuStateFilter!.length; i++) { 103 if ( 104 // @ts-ignore 105 cpuStateFilter[i].value === data.value && 106 // @ts-ignore 107 cpuStateFilter[i].cpu === data.cpu && 108 // @ts-ignore 109 Math.max(TraceRow.rangeSelectObject?.startNS!, cpuStateFilter[i].startTs!) < 110 // @ts-ignore 111 Math.min(TraceRow.rangeSelectObject?.endNS!, cpuStateFilter[i].startTs! + cpuStateFilter[i].dur!) 112 ) { 113 // @ts-ignore 114 CpuStateStruct.hoverStateStruct = cpuStateFilter[i]; 115 } 116 // @ts-ignore 117 if (cpuStateFilter[i].cpu === data.cpu) { 118 // @ts-ignore 119 CpuStateStruct.draw(context, path, cpuStateFilter[i]); 120 } 121 } 122 } else { 123 for (let i = 0; i < cpuStateFilter!.length; i++) { 124 if ( 125 row.name.includes('State') && 126 // @ts-ignore 127 cpuStateFilter[i].cpu !== data.cpu && 128 // @ts-ignore 129 cpuStateFilter[i].cpu === parseInt(row.name.replace(/[^\d]/g, ' ')) 130 ) { 131 // @ts-ignore 132 CpuStateStruct.draw(context, path, cpuStateFilter[i]); 133 } 134 } 135 } 136 row.canvasRestore(context, this.systemTrace); 137 } 138 } 139 }); 140 } 141 142 connectedCallback(): void { 143 super.connectedCallback(); 144 // @ts-ignore 145 resizeObserver(this.parentElement!, this.counterSampleTbl!, 25, this.counterLoadingPage, 24); 146 } 147 148 queryDataByDB(counterSampleParam: SelectionParam | unknown): void { 149 this.counterLoadingList.push(1); 150 this.sampleProgressEL!.loading = true; 151 // @ts-ignore 152 this.counterLoadingPage.style.visibility = 'visible'; 153 154 getTabPaneCounterSampleData( 155 // @ts-ignore 156 counterSampleParam.leftNs + counterSampleParam.recordStartNs, 157 // @ts-ignore 158 counterSampleParam.rightNs + counterSampleParam.recordStartNs, 159 // @ts-ignore 160 counterSampleParam.cpuStateFilterIds 161 ).then((result) => { 162 this.counterLoadingList.splice(0, 1); 163 if (this.counterLoadingList.length === 0) { 164 this.sampleProgressEL!.loading = false; 165 // @ts-ignore 166 this.counterLoadingPage.style.visibility = 'hidden'; 167 } 168 let sampleMap = new Map<unknown, unknown>(); 169 // @ts-ignore 170 counterSampleParam.cpuStateFilterIds.forEach((a: number): void => { 171 this.getInitTime( 172 //@ts-ignore 173 result.filter((f) => f.filterId === a), 174 sampleMap, 175 // @ts-ignore 176 counterSampleParam 177 ); 178 }); 179 // @ts-ignore 180 let counterSampleList: Array<unknown> = []; 181 sampleMap.forEach((a) => { 182 // @ts-ignore 183 a.timeStr = parseFloat((a.time / 1000000.0).toFixed(6)); 184 counterSampleList.push(a); 185 }); 186 counterSampleList.sort((a, b): number => { 187 // @ts-ignore 188 let countLeftData = Number(a.counter.toString().replace('Cpu', '')); 189 // @ts-ignore 190 let countRightData = Number(b.counter.toString().replace('Cpu', '')); 191 if (countLeftData > countRightData) { 192 return 1; 193 } else { 194 return -1; 195 } 196 }); 197 this.counterSampleSource = counterSampleList; 198 this.sortTable(this.counterSortKey, this.counterSortType); 199 }); 200 } 201 // @ts-ignore 202 getInitTime(initCounterResultList: Array<unknown>, sampleMap: Map<unknown, unknown>, val: SelectionParam): void { 203 let leftNs = val.leftNs + val.recordStartNs; 204 let rightNs = val.rightNs + val.recordStartNs; 205 if (initCounterResultList.length === 0) { 206 return; 207 } 208 // @ts-ignore 209 let idx = initCounterResultList.findIndex((a) => a.ts >= leftNs); 210 if (idx !== 0) { 211 initCounterResultList = initCounterResultList.slice( 212 idx === -1 ? initCounterResultList.length - 1 : idx - 1, 213 initCounterResultList.length 214 ); 215 } 216 // @ts-ignore 217 if (initCounterResultList[0].ts < leftNs && idx !== 0) { 218 // @ts-ignore 219 initCounterResultList[0].ts = leftNs; 220 } 221 initCounterResultList.forEach((item, idx): void => { 222 if (idx + 1 === initCounterResultList.length) { 223 // @ts-ignore 224 item.time = rightNs - item.ts; 225 } else { 226 // @ts-ignore 227 item.time = initCounterResultList[idx + 1].ts - item.ts; 228 } 229 // @ts-ignore 230 if (sampleMap.has(`${item.filterId}-${item.value}`)) { 231 // @ts-ignore 232 let obj = sampleMap.get(`${item.filterId}-${item.value}`); 233 // @ts-ignore 234 obj.time += item.time; 235 } else { 236 // @ts-ignore 237 sampleMap.set(`${item.filterId}-${item.value}`, { 238 // @ts-ignore 239 ...item, 240 // @ts-ignore 241 counter: `Cpu ${item.cpu}`, 242 // @ts-ignore 243 count: initCounterResultList.filter((ele) => ele.value === item.value).length, 244 }); 245 } 246 }); 247 } 248 249 sortTable(key: string, type: number): void { 250 if (type === 0) { 251 this.counterSampleTbl!.recycleDataSource = this.counterSampleSource; 252 } else { 253 let arr = Array.from(this.counterSampleSource); 254 arr.sort((sortByColumnLeftData, sortByColumnRightData): number => { 255 if (key === 'timeStr') { 256 if (type === 1) { 257 // @ts-ignore 258 return sortByColumnLeftData.time - sortByColumnRightData.time; 259 } else { 260 // @ts-ignore 261 return sortByColumnRightData.time - sortByColumnLeftData.time; 262 } 263 } else if (key === 'counter') { 264 // @ts-ignore 265 let countLeftData = Number(sortByColumnLeftData.counter.toString().replace('Cpu', '')); 266 // @ts-ignore 267 let countRightData = Number(sortByColumnRightData.counter.toString().replace('Cpu', '')); 268 if (type === 1) { 269 return countLeftData - countRightData; 270 } else { 271 return countRightData - countLeftData; 272 } 273 } else if (key === 'value') { 274 if (type === 1) { 275 // @ts-ignore 276 return sortByColumnLeftData.value - sortByColumnRightData.value; 277 } else { 278 // @ts-ignore 279 return sortByColumnRightData.value - sortByColumnLeftData.value; 280 } 281 } else if (key === 'count') { 282 if (type === 1) { 283 // @ts-ignore 284 return sortByColumnLeftData.count - sortByColumnRightData.count; 285 } else { 286 // @ts-ignore 287 return sortByColumnRightData.count - sortByColumnLeftData.count; 288 } 289 } else { 290 return 0; 291 } 292 }); 293 this.counterSampleTbl!.recycleDataSource = arr; 294 } 295 } 296 297 initHtml(): string { 298 return ` 299 <style> 300 .progressCounter{ 301 height: 1px; 302 left: 0; 303 right: 0; 304 bottom: 5px; 305 position: absolute; 306 } 307 :host{ 308 display: flex; 309 padding: 10px 10px; 310 flex-direction: column; 311 } 312 .loadingCounter{ 313 left: 0; 314 right: 0; 315 width:100%; 316 bottom: 0; 317 position: absolute; 318 background:transparent; 319 z-index: 999999; 320 } 321 .counter-sample-table{ 322 height: auto; 323 } 324 </style> 325 <lit-table id="tb-counter-sample" class="counter-sample-table"> 326 <lit-table-column class="counter-sample-column" width="20%" order data-index="counter" key="counter" align="flex-start" title="Cpu" > 327 </lit-table-column> 328 <lit-table-column class="counter-sample-column" width="1fr" order data-index="timeStr" key="timeStr" align="flex-start" title="Time(ms)" > 329 </lit-table-column> 330 <lit-table-column class="counter-sample-column" width="1fr" order data-index="value" key="value" align="flex-start" title="Value" > 331 </lit-table-column> 332 <lit-table-column class="counter-sample-column" width="1fr" order data-index="count" key="count" align="flex-start" title="Count" > 333 </lit-table-column> 334 </lit-table> 335 <lit-progress-bar class="progressCounter"></lit-progress-bar> 336 <div class="loadingCounter"></div> 337 `; 338 } 339} 340