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 { log } from '../../../../../log/Log'; 20import { getProbablyTime } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon'; 21import { Utils } from '../../base/Utils'; 22import { resizeObserver } from '../SheetUtils'; 23import { getTabCpuByThread } from '../../../../database/sql/Cpu.sql'; 24import { getCpuData, getIrqAndSoftIrqData } from "../../../../database/sql/CpuAndIrq.sql"; 25import { byCpuGroupBean, CpuAndIrqBean, softirqAndIrq, finalResultBean } from "./CpuAndIrqBean"; 26import { FlagsConfig } from '../../../SpFlags'; 27 28@element('tabpane-cpu-thread') 29export class TabPaneCpuByThread extends BaseElement { 30 private cpuByThreadTbl: LitTable | null | undefined; 31 private range: HTMLLabelElement | null | undefined; 32 private cpuByThreadSource: Array<SelectionData> = []; 33 private currentSelectionParam: SelectionParam | undefined; 34 private cpuByIrqSource: Array<finalResultBean> = []; 35 private loadIrq: boolean = false;//flag开关 36 private pubColumns = ` 37 <lit-table-column order width="250px" title="Process" data-index="process" key="process" align="flex-start" order > 38 </lit-table-column> 39 <lit-table-column order width="120px" title="PID" data-index="pid" key="pid" align="flex-start" order > 40 </lit-table-column> 41 <lit-table-column order width="250px" title="Thread" data-index="thread" key="thread" align="flex-start" order > 42 </lit-table-column> 43 <lit-table-column order width="120px" title="TID" data-index="tid" key="tid" align="flex-start" order > 44 </lit-table-column> 45 <lit-table-column order width="200px" title="Wall duration(ms)" data-index="wallDuration" key="wallDuration" align="flex-start" order > 46 </lit-table-column> 47 <lit-table-column order width="200px" title="Avg Wall duration(ms)" data-index="avgDuration" key="avgDuration" align="flex-start" order > 48 </lit-table-column> 49 <lit-table-column order width="120px" title="Occurrences" data-index="occurrences" key="occurrences" align="flex-start" order > 50 </lit-table-column> 51 `; 52 53 set data(cpuByThreadValue: SelectionParam | unknown) { 54 if (this.currentSelectionParam === cpuByThreadValue) { 55 return; 56 } 57 // @ts-ignore 58 this.currentSelectionParam = cpuByThreadValue; 59 // @ts-ignore 60 this.cpuByThreadTbl!.innerHTML = this.getTableColumns(cpuByThreadValue.cpus); 61 this.cpuByThreadTbl!.injectColumns(); 62 this.range!.textContent = 63 // @ts-ignore 64 `Selected range: ${parseFloat(((cpuByThreadValue.rightNs - cpuByThreadValue.leftNs) / 1000000.0).toFixed(5))} ms`; 65 this.cpuByThreadTbl!.loading = true; 66 this.loadIrq = FlagsConfig.getFlagsConfigEnableStatus('CPU by Irq');//flag开关 67 this.handleAsyncRequest(cpuByThreadValue, this.loadIrq); 68 } 69 70 private handleAsyncRequest(cpuByThreadValue: unknown, loadIrq: boolean): void { 71 if (loadIrq) { 72 //查询cpu数据和irq数据 73 Promise.all([ 74 // @ts-ignore 75 getCpuData(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, cpuByThreadValue.rightNs), 76 // @ts-ignore 77 getIrqAndSoftIrqData(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, cpuByThreadValue.rightNs) 78 ]).then(([cpuData, interruptData]) => { 79 this.cpuByThreadTbl!.loading = false; 80 const resArr = cpuData.concat(interruptData); 81 if (resArr != null && resArr.length > 0) { 82 const cutData: finalResultBean[] = this.groupByCpu(resArr);//切割后数据 83 this.aggregateData(cutData, cpuByThreadValue);//整合数据 84 } else { 85 this.cpuByIrqSource = []; 86 this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource; 87 } 88 }); 89 } else { 90 // @ts-ignore 91 getTabCpuByThread(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, // @ts-ignore 92 cpuByThreadValue.rightNs, cpuByThreadValue.traceId).then((result): void => { 93 this.cpuByThreadTbl!.loading = false; 94 if (result !== null && result.length > 0) { 95 log(`getTabCpuByThread size :${result.length}`); 96 this.processResult(result, cpuByThreadValue); 97 } else { 98 this.cpuByThreadSource = []; 99 this.cpuByThreadTbl!.recycleDataSource = this.cpuByThreadSource; 100 } 101 }); 102 } 103 104 } 105 106 //将所有数据按cpu重新分组 107 private groupByCpu(data: Array<CpuAndIrqBean>): finalResultBean[] { 108 const cpuObject: { [cpu: number]: byCpuGroupBean } = 109 data.reduce((groups, item) => { 110 const { cpu, ...restProps } = item; 111 const newCpuAndIrqBean: CpuAndIrqBean = { cpu, ...restProps }; 112 113 if (!groups[cpu]) { 114 groups[cpu] = { CPU: [] }; 115 } 116 groups[cpu].CPU!.push(newCpuAndIrqBean); 117 118 return groups; 119 }, {} as { [cpu: number]: byCpuGroupBean }) 120 const cutObj: { [cpu: number]: finalResultBean[] } = {}; 121 Object.entries(cpuObject).forEach(([cpuStr, { CPU }]) => { 122 const cpu = Number(cpuStr); 123 cutObj[cpu] = this.cpuByIrq(CPU); 124 }) 125 const cutList: finalResultBean[] = Object.values(cutObj).flat(); 126 return cutList; 127 } 128 129 //具体切割方法 130 private cpuByIrq(data: CpuAndIrqBean[]): finalResultBean[] { 131 let sourceData = data.sort((a, b) => a.startTime - b.startTime); 132 let waitArr: CpuAndIrqBean[] = []; 133 let completedArr: finalResultBean[] = []; 134 let globalTs: number = 0; 135 let index: number = 0; 136 while (index < sourceData.length || waitArr.length > 0) { 137 let minEndTs = Math.min(...waitArr.map((item: CpuAndIrqBean) => item.endTime)); 138 let minIndex = waitArr.findIndex((item: CpuAndIrqBean) => item.endTime === minEndTs); 139 //当waitArr为空时 140 if (waitArr.length === 0) { 141 globalTs = sourceData[index].startTime; 142 waitArr.push(sourceData[index]); 143 index++; 144 continue; 145 } 146 //当全局Ts等于minEndTs时,只做删除处理 147 if (globalTs === minEndTs) { 148 if (minIndex !== -1) { waitArr.splice(minIndex, 1) }; 149 continue; 150 } 151 let obj: finalResultBean = { 152 cat: '', 153 dur: 0, 154 cpu: 0, 155 pid: 0, 156 tid: 0, 157 occurrences: 0 158 }; 159 if (index < sourceData.length) { 160 if (sourceData[index].startTime < minEndTs) { 161 if (globalTs === sourceData[index].startTime) { 162 waitArr.push(sourceData[index]); 163 index++; 164 continue; 165 } else { 166 const maxPriorityItem = this.findMaxPriority(waitArr); 167 obj = { 168 cat: maxPriorityItem.cat, 169 dur: sourceData[index].startTime - globalTs, 170 cpu: maxPriorityItem.cpu, 171 pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]', 172 tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]', 173 occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0 174 } 175 completedArr.push(obj); 176 maxPriorityItem.isFirstObject = 0; 177 waitArr.push(sourceData[index]); 178 globalTs = sourceData[index].startTime; 179 index++; 180 } 181 } else { 182 const maxPriorityItem = this.findMaxPriority(waitArr); 183 obj = { 184 cat: maxPriorityItem.cat, 185 dur: minEndTs - globalTs, 186 cpu: maxPriorityItem.cpu, 187 pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]', 188 tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]', 189 occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0 190 } 191 completedArr.push(obj); 192 maxPriorityItem.isFirstObject = 0; 193 globalTs = minEndTs; 194 if (minIndex !== -1) { waitArr.splice(minIndex, 1) }; 195 } 196 } else { 197 const maxPriorityItem = this.findMaxPriority(waitArr); 198 obj = { 199 cat: maxPriorityItem.cat, 200 dur: minEndTs - globalTs, 201 cpu: maxPriorityItem.cpu, 202 pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]', 203 tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]', 204 occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0 205 } 206 completedArr.push(obj); 207 maxPriorityItem.isFirstObject = 0; 208 globalTs = minEndTs; 209 if (minIndex !== -1) { waitArr.splice(minIndex, 1) }; 210 } 211 } 212 return completedArr; 213 } 214 215 private findMaxPriority(arr: CpuAndIrqBean[]): CpuAndIrqBean { 216 return arr.reduce((maxItem: CpuAndIrqBean, currentItem: CpuAndIrqBean) => { 217 return maxItem.priority > currentItem.priority ? maxItem : currentItem; 218 }, arr[0]); 219 } 220 221 // 聚合数据 222 private aggregateData(data: any[], cpuByThreadValue: SelectionParam | any): void { 223 const cpuAggregations: { [tidPidKey: string]: softirqAndIrq } = {}; 224 //@ts-ignore 225 let softirqAggregations: softirqAndIrq = { 226 occurrences: 0, 227 wallDuration: 0, 228 avgDuration: 0, 229 cpus: {} 230 }; 231 //@ts-ignore 232 let irqAggregations: softirqAndIrq = { 233 occurrences: 0, 234 wallDuration: 0, 235 avgDuration: 0, 236 cpus: {} 237 }; 238 data.forEach((obj) => { 239 // 聚合 cpu 数据 240 if (obj.cat === "cpu" && obj.dur !== 0) { 241 const tidPidKey = `${obj.tid}-${obj.pid}`; 242 const cpuDurationKey = `cpu${obj.cpu}`; 243 const cpuPercentKey = `cpu${obj.cpu}Ratio`; 244 245 if (!cpuAggregations[tidPidKey]) { 246 cpuAggregations[tidPidKey] = { 247 tid: obj.tid, 248 pid: obj.pid, 249 wallDuration: 0, 250 occurrences: 0, 251 avgDuration: 0, 252 cpus: {}, 253 [cpuDurationKey]: 0, 254 [cpuPercentKey]: 100, 255 }; 256 } 257 258 cpuAggregations[tidPidKey].wallDuration += obj.dur; 259 cpuAggregations[tidPidKey].occurrences += obj.occurrences; 260 cpuAggregations[tidPidKey].avgDuration = cpuAggregations[tidPidKey].wallDuration / cpuAggregations[tidPidKey].occurrences; 261 cpuAggregations[tidPidKey].cpus[obj.cpu] = (cpuAggregations[tidPidKey].cpus[obj.cpu] || 0) + obj.dur; 262 cpuAggregations[tidPidKey][cpuDurationKey] = cpuAggregations[tidPidKey].cpus[obj.cpu]; 263 cpuAggregations[tidPidKey][cpuPercentKey] = (cpuAggregations[tidPidKey][cpuDurationKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100; 264 } 265 266 // 聚合 softirq 数据 267 if (obj.cat === "softirq" && obj.dur !== 0) { 268 this.updateIrqAndSoftirq(softirqAggregations, obj, cpuByThreadValue); 269 } 270 // 聚合 irq 数据 271 if (obj.cat === "irq" && obj.dur !== 0) { 272 this.updateIrqAndSoftirq(irqAggregations, obj, cpuByThreadValue); 273 } 274 275 }); 276 277 // 将聚合数据转换为最终结果格式 278 const result: Array<{ [key: string]: any }> = []; 279 280 // 添加 CPU 数据 281 for (const tidPidKey in cpuAggregations) { 282 const aggregation = cpuAggregations[tidPidKey]; 283 const { tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations } = aggregation; 284 result.push({ tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations }); 285 } 286 287 // 添加softirq 288 if (softirqAggregations.wallDuration > 0) { 289 result.push({ process: 'softirq', thread: 'softirq', tid: '[NULL]', pid: '[NULL]', ...softirqAggregations, }); 290 } 291 292 // 添加 irq 数据 293 if (irqAggregations.wallDuration) { 294 result.push({ process: 'irq', thread: 'irq', tid: '[NULL]', pid: '[NULL]', ...irqAggregations }); 295 } 296 this.handleFunction(result, cpuByThreadValue); 297 298 } 299 300 //irq和softirq聚合方法 301 private updateIrqAndSoftirq(aggregation: softirqAndIrq, obj: CpuAndIrqBean, cpuByThreadValue: SelectionParam): void { 302 const callid = obj.cpu; 303 const callidDurKey = `cpu${callid}`; 304 const callidPercentKey = `cpu${callid}Ratio`; 305 306 aggregation.wallDuration += obj.dur; 307 aggregation.occurrences += obj.occurrences; 308 aggregation.avgDuration = aggregation.wallDuration / aggregation.occurrences; 309 310 if (!aggregation.cpus[callid]) { 311 aggregation.cpus[callid] = 0; 312 } 313 aggregation.cpus[callid] += obj.dur; 314 315 if (!(callidDurKey in aggregation)) { 316 aggregation[callidDurKey] = 0; 317 } 318 aggregation[callidDurKey] += obj.dur; 319 320 aggregation[callidPercentKey] = (aggregation[callidDurKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100; 321 } 322 323 //最后将所有数据进行统一整理 324 private handleFunction(data: Array<{ [key: string]: any }>, cpuByThreadValue: SelectionParam): void { 325 let index = 0; 326 let totalWallDuration = 0; 327 let totalOccurrences = 0; 328 const finalData: Array<finalResultBean> = []; 329 while (index < data.length) { 330 const obj = data[index]; 331 totalWallDuration += obj.wallDuration; 332 totalOccurrences += obj.occurrences; 333 if (obj.tid !== '[NULL]' && obj.pid !== '[NULL]') { 334 // @ts-ignore 335 let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(obj.pid); 336 // @ts-ignore 337 let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(obj.tid); 338 obj.thread = thread == null || thread.length === 0 ? '[NULL]' : thread; 339 obj.process = process == null || process.length === 0 ? '[NULL]' : process; 340 } 341 obj.wallDuration /= 1000000; 342 obj.wallDuration = obj.wallDuration.toFixed(6); 343 obj.avgDuration /= 1000000; 344 obj.avgDuration = obj.avgDuration.toFixed(6); 345 for (const cpu in obj.cpus) { 346 if (obj.cpus.hasOwnProperty(cpu)) { 347 obj[`cpu${cpu}TimeStr`] = getProbablyTime(obj[`cpu${cpu}`]); 348 obj[`cpu${cpu}Ratio`] = obj[`cpu${cpu}Ratio`].toFixed(2); 349 } 350 } 351 for (const cpuNumber of cpuByThreadValue.cpus) { 352 const cpuKey = `cpu${cpuNumber}TimeStr`; 353 const percentKey = `cpu${cpuNumber}Ratio`; 354 if (!obj.hasOwnProperty(cpuKey)) { 355 obj[cpuKey] = "0.00"; 356 obj[percentKey] = "0.00"; 357 } 358 } 359 delete obj.cpus; 360 finalData.push(obj); 361 index++; 362 } 363 finalData.unshift({ 364 wallDuration: (totalWallDuration / 1000000).toFixed(6), 365 occurrences: totalOccurrences, 366 }); 367 this.cpuByIrqSource = finalData; 368 this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource; 369 } 370 371 //点击表头进行排序 372 private reSortByColum(key: string, type: number): void { 373 // 如果数组为空,则直接返回 374 if (!this.cpuByIrqSource.length) return; 375 let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.cpuByIrqSource)).splice(1); 376 let sortList: Array<finalResultBean> = []; 377 sortList.push(...sortObject); 378 if (type === 0) { 379 this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource; 380 } else { 381 sortList.sort((a, b) => { 382 let aValue: number | string, bValue: number | string; 383 if (key === 'process' || key === 'thread') { 384 // @ts-ignore 385 aValue = a[key]; 386 // @ts-ignore 387 bValue = b[key]; 388 } else { 389 // @ts-ignore 390 aValue = parseFloat(a[key]); 391 // @ts-ignore 392 bValue = parseFloat(b[key]); 393 } 394 if (typeof aValue === 'string' && typeof bValue === 'string') { 395 return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); 396 } else if (typeof aValue === 'number' && typeof bValue === 'number') { 397 return type === 1 ? aValue - bValue : bValue - aValue; 398 } else { 399 return 0; 400 } 401 }); 402 this.cpuByThreadTbl!.recycleDataSource = [this.cpuByIrqSource[0]].concat(sortList); 403 } 404 } 405 406 private processResult(result: Array<unknown>, cpuByThreadValue: unknown): void { 407 let sumWall = 0.0; 408 let sumOcc = 0; 409 let map: Map<string, unknown> = new Map<string, unknown>(); 410 for (let e of result) { 411 // @ts-ignore 412 sumWall += e.wallDuration; 413 // @ts-ignore 414 sumOcc += e.occurrences; 415 this.updateThreadMap(e, cpuByThreadValue, map); 416 } 417 this.calculateCount(map, sumWall, sumOcc); 418 } 419 420 private updateThreadMap(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void { 421 // @ts-ignore 422 if (map.has(`${e.tid}`)) { 423 this.updateExistingThread(e, cpuByThreadValue, map); 424 } else { 425 this.createThread(e, cpuByThreadValue, map); 426 } 427 } 428 429 private updateExistingThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void { 430 // @ts-ignore 431 let thread = map.get(`${e.tid}`)!; 432 // @ts-ignore 433 thread.wallDuration += e.wallDuration; 434 // @ts-ignore 435 thread.occurrences += e.occurrences; 436 this.updateCpuValues(e, cpuByThreadValue, thread); 437 } 438 439 private createThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void { 440 // @ts-ignore 441 let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(e.pid); 442 // @ts-ignore 443 let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(e.tid); 444 let cpuByThreadObject: unknown = { 445 // @ts-ignore 446 tid: e.tid, 447 // @ts-ignore 448 pid: e.pid, 449 thread: !thread || thread.length === 0 ? '[NULL]' : thread, 450 process: !process || process.length === 0 ? '[NULL]' : process, 451 // @ts-ignore 452 wallDuration: e.wallDuration || 0, 453 // @ts-ignore 454 occurrences: e.occurrences || 0, 455 avgDuration: 0, 456 }; 457 this.initializeCpuValues(cpuByThreadValue, cpuByThreadObject); 458 this.updateCpuValues(e, cpuByThreadValue, cpuByThreadObject); 459 // @ts-ignore 460 map.set(`${e.tid}`, cpuByThreadObject); 461 } 462 463 private initializeCpuValues(cpuByThreadValue: unknown, cpuByThreadObject: unknown): void { 464 // @ts-ignore 465 for (let i of cpuByThreadValue.cpus) { 466 // @ts-ignore 467 cpuByThreadObject[`cpu${i}`] = 0; 468 // @ts-ignore 469 cpuByThreadObject[`cpu${i}TimeStr`] = '0'; 470 // @ts-ignore 471 cpuByThreadObject[`cpu${i}Ratio`] = '0'; 472 } 473 } 474 475 private updateCpuValues(e: unknown, cpuByThreadValue: unknown, cpuByThreadObject: unknown): void { 476 // @ts-ignore 477 cpuByThreadObject[`cpu${e.cpu}`] = e.wallDuration || 0; 478 // @ts-ignore 479 cpuByThreadObject[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0); 480 // @ts-ignore 481 let ratio = ((100.0 * (e.wallDuration || 0)) / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)).toFixed(2); 482 if (ratio === '0.00') { 483 ratio = '0'; 484 } 485 // @ts-ignore 486 cpuByThreadObject[`cpu${e.cpu}Ratio`] = ratio; 487 } 488 489 private calculateCount(map: Map<string, unknown>, sumWall: number, sumOcc: number): void { 490 // @ts-ignore 491 let arr = Array.from(map.values()).sort((a, b) => b.wallDuration - a.wallDuration); 492 for (let e of arr) { 493 // @ts-ignore 494 e.avgDuration = (e.wallDuration / (e.occurrences || 1.0) / 1000000.0).toFixed(5); 495 // @ts-ignore 496 e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); 497 } 498 let count: unknown = {}; 499 // @ts-ignore 500 count.process = ' '; 501 // @ts-ignore 502 count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(7)); 503 // @ts-ignore 504 count.occurrences = sumOcc; 505 // @ts-ignore 506 arr.splice(0, 0, count); 507 // @ts-ignore 508 this.cpuByThreadSource = arr; 509 this.cpuByThreadTbl!.recycleDataSource = arr; 510 } 511 512 getTableColumns(cpus: Array<number>): string { 513 let cpuByThreadTblHtml = `${this.pubColumns}`; 514 let cpuByThreadList = cpus.sort((cpuByThreadA, cpuByThreadB) => cpuByThreadA - cpuByThreadB); 515 for (let index of cpuByThreadList) { 516 cpuByThreadTblHtml = `${cpuByThreadTblHtml} 517 <lit-table-column width="100px" title="cpu${index}" data-index="cpu${index}TimeStr" key="cpu${index}TimeStr" align="flex-start" order> 518 </lit-table-column> 519 <lit-table-column width="100px" title="%" data-index="cpu${index}Ratio" key="cpu${index}Ratio" align="flex-start" order> 520 </lit-table-column> 521 `; 522 } 523 return cpuByThreadTblHtml; 524 } 525 526 initElements(): void { 527 this.cpuByThreadTbl = this.shadowRoot?.querySelector<LitTable>('#tb-cpu-thread'); 528 this.range = this.shadowRoot?.querySelector('#time-range'); 529 this.cpuByThreadTbl!.addEventListener('column-click', (evt): void => { 530 if (!this.loadIrq) { 531 // @ts-ignore 532 this.sortByColumn(evt.detail); 533 } else { 534 // @ts-ignore 535 this.reSortByColum(evt.detail.key, evt.detail.sort); 536 } 537 }); 538 this.cpuByThreadTbl!.addEventListener('row-click', (evt: unknown): void => { 539 // @ts-ignore 540 let data = evt.detail.data; 541 data.isSelected = true; 542 this.cpuByThreadTbl?.clearAllSelection(data); 543 this.cpuByThreadTbl?.setCurrentSelection(data); 544 }); 545 } 546 547 connectedCallback(): void { 548 super.connectedCallback(); 549 resizeObserver(this.parentElement!, this.cpuByThreadTbl!); 550 } 551 552 initHtml(): string { 553 return ` 554 <style> 555 .cpu-by-thread-label{ 556 width: 100%; 557 height: 20px; 558 } 559 :host{ 560 width: auto; 561 display: flex; 562 flex-direction: column; 563 padding: 10px 10px; 564 } 565 </style> 566 <label id="time-range" class="cpu-by-thread-label" style="text-align: end;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label> 567 <lit-table id="tb-cpu-thread" style="height:calc( 30vh - 25px )" > 568 569 </lit-table> 570 `; 571 } 572 compare(property: unknown, sort: unknown, type: string) { 573 return function (cpuByThreadLeftData: SelectionData, cpuByThreadRightData: SelectionData): number { 574 if (cpuByThreadLeftData.process === ' ' || cpuByThreadRightData.process === ' ') { 575 return 0; 576 } 577 if (type === 'number') { 578 return sort === 2 // @ts-ignore 579 ? parseFloat(cpuByThreadRightData[property]) - parseFloat(cpuByThreadLeftData[property]) // @ts-ignore 580 : parseFloat(cpuByThreadLeftData[property]) - parseFloat(cpuByThreadRightData[property]); 581 } else { 582 // @ts-ignore 583 if (cpuByThreadRightData[property] > cpuByThreadLeftData[property]) { 584 return sort === 2 ? 1 : -1; 585 } else { 586 // @ts-ignore 587 if (cpuByThreadRightData[property] === cpuByThreadLeftData[property]) { 588 return 0; 589 } else { 590 return sort === 2 ? -1 : 1; 591 } 592 } 593 } 594 }; 595 } 596 sortByColumn(detail: unknown): void { 597 // @ts-ignore 598 if ((detail.key as string).includes('cpu')) { 599 // @ts-ignore 600 if ((detail.key as string).includes('Ratio')) { 601 // @ts-ignore 602 this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string')); 603 } else { 604 // @ts-ignore 605 this.cpuByThreadSource.sort(this.compare((detail.key as string).replace('TimeStr', ''), detail.sort, 'number')); 606 } 607 } else { 608 if ( 609 // @ts-ignore 610 detail.key === 'pid' || 611 // @ts-ignore 612 detail.key === 'tid' || 613 // @ts-ignore 614 detail.key === 'wallDuration' || 615 // @ts-ignore 616 detail.key === 'avgDuration' || 617 // @ts-ignore 618 detail.key === 'occurrences' 619 ) { 620 // @ts-ignore 621 this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'number')); 622 } else { 623 // @ts-ignore 624 this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string')); 625 } 626 } 627 628 this.cpuByThreadTbl!.recycleDataSource = this.cpuByThreadSource; 629 } 630} 631