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 { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; 19import { initSort, resizeObserver } from '../SheetUtils'; 20import { queryIrqDataBoxSelect, querySoftIrqDataBoxSelect, queryIrqSelectData, querySoftirqSelectData } from '../../../../database/sql/Irq.sql'; 21import { FlagsConfig } from '../../../SpFlags'; 22import { IrqAndSoftirqBean, byCallidGroupBean, finalResultBean } from './irqAndSoftirqBean'; 23 24@element('tabpane-irq-counter') 25export class TabPaneIrqCounter extends BaseElement { 26 private irqCounterTbl: LitTable | null | undefined; 27 private irqRange: HTMLLabelElement | null | undefined; 28 private irqCounterSource: Array<SelectionData> = []; 29 private sortColumn: string = 'wallDurationFormat'; 30 private sortType: number = 2; 31 private loadIrq: boolean = false;//flag开关 32 private irqAndSoftirqSource: Array<finalResultBean> = []; 33 34 set data(irqParam: SelectionParam | unknown) { 35 if (this.irqCounterTbl) { 36 //@ts-ignore 37 this.irqCounterTbl.shadowRoot.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 45}px`; 38 } 39 this.irqRange!.textContent = `Selected range: ${parseFloat( 40 // @ts-ignore 41 ((irqParam.rightNs - irqParam.leftNs) / 1000000.0).toFixed(5) 42 )} ms`; 43 this.irqCounterTbl!.loading = true; 44 let dataSource: Array<SelectionData> = []; 45 this.loadIrq = FlagsConfig.getFlagsConfigEnableStatus('CPU by Irq');//flag开关 46 if (this.loadIrq) {//@ts-ignore 47 let irqCallIds = irqParam.softIrqCallIds.length > 0 ? irqParam.softIrqCallIds : irqParam.irqCallIds; 48 Promise.all([//@ts-ignore 49 queryIrqSelectData(irqCallIds, irqParam.leftNs, irqParam.rightNs),//@ts-ignore 50 querySoftirqSelectData(irqParam.softIrqCallIds, irqParam.leftNs, irqParam.rightNs), 51 ]).then(([irqData, softirqData]) => { 52 this.irqCounterTbl!.loading = false; 53 const resArr = irqData.concat(softirqData); 54 if (resArr != null && resArr.length > 0) {//@ts-ignore 55 let isSelectIrq = irqParam.irqCallIds.length > 0 ? true : false; 56 const cutData: finalResultBean[] = this.groupByCallid(resArr); 57 this.aggregateData(cutData, isSelectIrq);//整合数据 58 } else { 59 this.irqAndSoftirqSource = []; 60 this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource; 61 } 62 }); 63 } else { 64 Promise.all([ 65 // @ts-ignore 66 queryIrqDataBoxSelect(irqParam.irqCallIds, irqParam.leftNs, irqParam.rightNs), // @ts-ignore 67 querySoftIrqDataBoxSelect(irqParam.softIrqCallIds, irqParam.leftNs, irqParam.rightNs), 68 ]).then((resArr) => { 69 this.irqCounterTbl!.loading = false; 70 resArr.forEach((res) => { 71 res.forEach((item) => { 72 let selectData = new SelectionData(); 73 //@ts-ignore 74 selectData.name = item.irqName; 75 //@ts-ignore 76 selectData.cat = item.cat; 77 //@ts-ignore 78 selectData.count = item.count; 79 //@ts-ignore 80 selectData.wallDuration = item.wallDuration; 81 //@ts-ignore 82 selectData.wallDurationFormat = (item.wallDuration / 1000).toFixed(2); 83 //@ts-ignore 84 selectData.maxDuration = item.wallDuration; 85 //@ts-ignore 86 selectData.maxDurationFormat = (item.maxDuration / 1000).toFixed(2); 87 //@ts-ignore 88 selectData.avgDuration = (item.avgDuration / 1000).toFixed(2); 89 dataSource.push(selectData); 90 }); 91 }); 92 initSort(this.irqCounterTbl!, this.sortColumn, this.sortType); 93 this.irqCounterSource = dataSource; 94 this.irqCounterTbl!.recycleDataSource = dataSource; 95 this.sortByColumn(this.sortColumn, this.sortType); 96 }); 97 } 98 } 99 100 initElements(): void { 101 this.irqCounterTbl = this.shadowRoot?.querySelector<LitTable>('#tb-irq-counter'); 102 this.irqRange = this.shadowRoot?.querySelector('#time-range'); 103 this.irqCounterTbl!.addEventListener('column-click', (event) => { 104 if (!this.loadIrq) { 105 // @ts-ignore 106 this.sortByColumn(event.detail.key, event.detail.sort); 107 } else { 108 // @ts-ignore 109 this.reSortByColum(event.detail.key, event.detail.sort); 110 } 111 }); 112 } 113 114 connectedCallback(): void { 115 super.connectedCallback(); 116 resizeObserver(this.parentElement!, this.irqCounterTbl!); 117 } 118 119 initHtml(): string { 120 return ` 121 <style> 122 .irq-counter-label{ 123 font-size: 10pt; 124 } 125 :host{ 126 display: flex; 127 flex-direction: column; 128 padding: 10px 10px; 129 } 130 </style> 131 <label id="time-range" class="irq-counter-label" style="width: 100%;height: 20px;text-align: end;margin-bottom: 5px;">Selected range:0.0 ms</label> 132 <lit-table id="tb-irq-counter" style="height: auto"> 133 <lit-table-column width="30%" title="Name" data-index="name" key="name" align="flex-start" order> 134 </lit-table-column> 135 <lit-table-column width="10%" title="Type" data-index="cat" key="cat" align="flex-start" order> 136 </lit-table-column> 137 <lit-table-column width="1fr" title="Duration(μs)" data-index="wallDurationFormat" key="wallDurationFormat" align="flex-start" order > 138 </lit-table-column> 139 <lit-table-column width="1fr" title="Max Duration(μs)" data-index="maxDurationFormat" key="maxDurationFormat" align="flex-start" order > 140 </lit-table-column> 141 <lit-table-column width="1fr" title="Average Duration(μs)" data-index="avgDuration" key="avgDuration" align="flex-start" order > 142 </lit-table-column> 143 <lit-table-column width="1fr" title="Occurrences" data-index="count" key="count" align="flex-start" order > 144 </lit-table-column> 145 </lit-table> 146 `; 147 } 148 149 sortByColumn(sortColumn: string, sortType: number): void { 150 let key = sortColumn; 151 let type = sortType; 152 let arr = Array.from(this.irqCounterSource); 153 arr.sort((irqCounterLeftData, irqCounterRightData): number => { 154 if (key === 'wallDurationFormat' || type === 0) { 155 return (type === 1 ? 1 : -1) * (irqCounterLeftData.wallDuration - irqCounterRightData.wallDuration); 156 } else if (key === 'count') { 157 return (type === 1 ? 1 : -1) * (parseInt(irqCounterLeftData.count) - parseInt(irqCounterRightData.count)); 158 } else if (key === 'maxDurationFormat') { 159 return (type === 1 ? 1 : -1) * (irqCounterLeftData.maxDuration - irqCounterRightData.maxDuration); 160 } else if (key === 'avgDuration') { 161 const avgDiff = 162 irqCounterLeftData.wallDuration / parseInt(irqCounterLeftData.count) - 163 irqCounterRightData.wallDuration / parseInt(irqCounterRightData.count); 164 return (type === 1 ? 1 : -1) * avgDiff; 165 } else if (key === 'name') { 166 const nameDiff = irqCounterLeftData.name.localeCompare(irqCounterRightData.name); 167 return (type === 2 ? -1 : 1) * nameDiff; 168 } else { 169 return 0; 170 } 171 }); 172 this.irqCounterTbl!.recycleDataSource = arr; 173 } 174 175 //将所有数据按callid重新分组 176 private groupByCallid(data: Array<IrqAndSoftirqBean>): finalResultBean[] { 177 const callidObject: { [callid: number]: byCallidGroupBean } = 178 data.reduce((groups, item) => { 179 const { callid, ...restProps } = item; 180 const newIrqAndSoftirqBean: IrqAndSoftirqBean = { callid, ...restProps }; 181 182 if (!groups[callid]) { 183 groups[callid] = { Callid: [] }; 184 } 185 groups[callid].Callid!.push(newIrqAndSoftirqBean); 186 187 return groups; 188 }, {} as { [callid: number]: byCallidGroupBean }); 189 const cutObj: { [callid: number]: finalResultBean[] } = {}; 190 Object.entries(callidObject).forEach(([callidStr, { Callid }]) => { 191 const callid = Number(callidStr); 192 cutObj[callid] = this.callidByIrq(Callid); 193 }); 194 const cutList: finalResultBean[] = Object.values(cutObj).flat(); 195 return cutList; 196 } 197 198 //具体切割方法 199 private callidByIrq(data: IrqAndSoftirqBean[]): finalResultBean[] { 200 let sourceData = data.sort((a, b) => a.startTime - b.startTime); 201 let waitArr: IrqAndSoftirqBean[] = []; 202 let completedArr: finalResultBean[] = []; 203 let globalTs: number = 0; 204 let index: number = 0; 205 while (index < sourceData.length || waitArr.length > 0) { 206 let minEndTs = Math.min(...waitArr.map((item: IrqAndSoftirqBean) => item.endTime)); 207 let minIndex = waitArr.findIndex((item: IrqAndSoftirqBean) => item.endTime === minEndTs); 208 //当waitArr为空时 209 if (waitArr.length === 0) { 210 globalTs = sourceData[index].startTime; 211 waitArr.push(sourceData[index]); 212 index++; 213 continue; 214 } 215 //当全局Ts等于minEndTs时,只做删除处理 216 if (globalTs === minEndTs) { 217 if (minIndex !== -1) { 218 const item = waitArr[minIndex]; 219 if (item.endTime > item.startTime) { 220 waitArr.splice(minIndex, 1); 221 } else { 222 // wallDuration为0,需要特别处理 223 const obj: finalResultBean = { 224 cat: item.cat, 225 name: item.name, 226 wallDuration: 0, 227 count: item.isFirstObject === 1 ? 1 : 0 228 }; 229 completedArr.push(obj); 230 waitArr.splice(minIndex, 1); 231 } 232 continue; 233 } 234 } 235 let obj: finalResultBean = { 236 cat: '', 237 name: '', 238 wallDuration: 0, 239 count: 0, 240 }; 241 if (index < sourceData.length) { 242 if (sourceData[index].startTime < minEndTs) { 243 if (globalTs === sourceData[index].startTime) { 244 waitArr.push(sourceData[index]); 245 index++; 246 continue; 247 } else { 248 const maxPriorityItem = this.findMaxPriority(waitArr); 249 obj = { 250 cat: maxPriorityItem.cat, 251 name: maxPriorityItem.name, 252 wallDuration: sourceData[index].startTime - globalTs, 253 count: maxPriorityItem.isFirstObject === 1 ? 1 : 0 254 } 255 completedArr.push(obj); 256 maxPriorityItem.isFirstObject = 0; 257 waitArr.push(sourceData[index]); 258 globalTs = sourceData[index].startTime; 259 index++; 260 } 261 } else { 262 const maxPriorityItem = this.findMaxPriority(waitArr); 263 obj = { 264 cat: maxPriorityItem.cat, 265 name: maxPriorityItem.name, 266 wallDuration: minEndTs - globalTs, 267 count: maxPriorityItem.isFirstObject === 1 ? 1 : 0 268 } 269 completedArr.push(obj); 270 maxPriorityItem.isFirstObject = 0; 271 globalTs = minEndTs; 272 if (minIndex !== -1) { waitArr.splice(minIndex, 1) }; 273 } 274 } else { 275 const maxPriorityItem = this.findMaxPriority(waitArr); 276 obj = { 277 cat: maxPriorityItem.cat, 278 name: maxPriorityItem.name, 279 wallDuration: minEndTs - globalTs, 280 count: maxPriorityItem.isFirstObject === 1 ? 1 : 0 281 } 282 completedArr.push(obj); 283 maxPriorityItem.isFirstObject = 0; 284 globalTs = minEndTs; 285 if (minIndex !== -1) { waitArr.splice(minIndex, 1) }; 286 } 287 } 288 return completedArr; 289 } 290 291 private findMaxPriority(arr: IrqAndSoftirqBean[]): IrqAndSoftirqBean { 292 return arr.reduce((maxItem: IrqAndSoftirqBean, currentItem: IrqAndSoftirqBean) => { 293 return maxItem.priority > currentItem.priority ? maxItem : currentItem; 294 }, arr[0]);; 295 } 296 297 // 聚合数据 298 private aggregateData(data: finalResultBean[], isSelectIrq: boolean): void { 299 function groupAndSumDurations(items: finalResultBean[]): finalResultBean[] { 300 const grouped: Record<string, finalResultBean> = items.reduce((acc, item) => { 301 if (item.cat === 'irq' && !isSelectIrq) {//若没有框选irq,则不对其进行处理 302 return acc; 303 } 304 if (!acc[item.name]) { 305 acc[item.name] = { 306 wallDuration: 0, 307 maxDuration: 0, 308 name: item.name, 309 cat: item.cat, 310 count: 0, 311 avgDuration: 0 312 }; 313 } 314 acc[item.name].wallDuration += item.wallDuration; 315 acc[item.name].wallDurationFormat = (acc[item.name].wallDuration / 1000).toFixed(2); 316 acc[item.name].count += item.count; 317 acc[item.name].avgDuration = (acc[item.name].wallDuration / acc[item.name].count / 1000).toFixed(2); 318 if (item.wallDuration > acc[item.name].maxDuration!) { 319 acc[item.name].maxDuration = item.wallDuration; 320 acc[item.name].maxDurationFormat = (acc[item.name].maxDuration! / 1000).toFixed(2); 321 } 322 return acc; 323 }, {} as Record<string, finalResultBean>); 324 return Object.values(grouped); 325 } 326 this.irqAndSoftirqSource = groupAndSumDurations(data); 327 this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource; 328 } 329 330 private reSortByColum(key: string, type: number): void { 331 // 如果数组为空,则直接返回 332 if (!this.irqAndSoftirqSource.length) return; 333 let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.irqAndSoftirqSource)); 334 let sortList: Array<finalResultBean> = []; 335 sortList.push(...sortObject); 336 if (type === 0) { 337 this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource; 338 } else { 339 sortList.sort((a, b) => { 340 let aValue: number | string, bValue: number | string; 341 if (key === 'name' || key === 'cat') { 342 aValue = a[key]; 343 bValue = b[key]; 344 } else { 345 // @ts-ignore 346 aValue = parseFloat(a[key]); 347 // @ts-ignore 348 bValue = parseFloat(b[key]); 349 } 350 if (typeof aValue === 'string' && typeof bValue === 'string') { 351 return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); 352 } else if (typeof aValue === 'number' && typeof bValue === 'number') { 353 return type === 1 ? aValue - bValue : bValue - aValue; 354 } else { 355 return 0; 356 } 357 }); 358 this.irqCounterTbl!.recycleDataSource = sortList; 359 } 360 } 361} 362