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 { convertJSON, getProbablyTime, LogicHandler } from './ProcedureLogicWorkerCommon'; 17 18export class ProcedureLogicWorkerSchedulingAnalysis extends LogicHandler { 19 currentEventId: string = ''; 20 endTs: number = 0; 21 startTs: number = 0; 22 totalDur: number = 0; 23 cpu: number = 0; 24 freq: number = 0; 25 bigCores: Array<number> = []; 26 midCores: Array<number> = []; 27 smallCores: Array<number> = []; 28 cpuFreqMap: Map<number, Array<CpuMeasure>> = new Map<number, Array<CpuMeasure>>(); 29 cpuIdle0Map: Map<number, Array<CpuMeasure>> = new Map<number, Array<CpuMeasure>>(); 30 threadMap: Map<number, string> = new Map<number, string>(); 31 processMap: Map<number, string> = new Map<number, string>(); 32 cpuAnalysisMap: Map<string, unknown> = new Map<string, unknown>(); 33 34 clearAll(): void { 35 this.bigCores.length = 0; 36 this.midCores.length = 0; 37 this.smallCores.length = 0; 38 this.cpuAnalysisMap.clear(); 39 this.threadMap.clear(); 40 this.processMap.clear(); 41 this.cpuFreqMap.clear(); 42 this.cpuIdle0Map.clear(); 43 } 44 45 handle(data: unknown): void { 46 //@ts-ignore 47 this.currentEventId = data.id; 48 //@ts-ignore 49 if (data.params.endTs) { 50 //@ts-ignore 51 this.endTs = data.params.endTs; 52 //@ts-ignore 53 this.totalDur = data.params.total; 54 this.startTs = this.endTs - this.totalDur; 55 } 56 //@ts-ignore 57 if (data && data.type) { 58 //@ts-ignore 59 this.handleDataByType(data); 60 } 61 } 62 private handleDataByType(data: { id: string; action: string; params: unknown }): void { 63 //@ts-ignore 64 switch (data.type) { 65 case 'scheduling-clearData': 66 this.schedulingClearData(data); 67 break; 68 case 'scheduling-initFreqData': 69 this.schedulingInitFreqData(data); 70 break; 71 case 'scheduling-getProcessAndThread': 72 this.schedulinGetProcessAndThread(data); 73 break; 74 case 'scheduling-getCpuIdle0': 75 this.schedulingGetCpuIdle0(data); 76 break; 77 case 'scheduling-getCpuUsage': 78 this.schedulingGetCpuUsage(data); 79 break; 80 case 'scheduling-CPU Frequency': 81 this.schedulingCPUFrequency(data); 82 break; 83 case 'scheduling-CPU Frequency Thread': 84 this.schedulingCPUFrequencyThread(data); 85 break; 86 case 'scheduling-CPU Idle': 87 this.schedulingCPUIdle(data); 88 break; 89 case 'scheduling-CPU Irq': 90 this.schedulingCPUIrq(data); 91 break; 92 case 'scheduling-Thread CpuUsage': 93 this.schedulingThreadCpuUsage(data); 94 break; 95 case 'scheduling-Thread RunTime': 96 this.schedulingThreadRunTime(data); 97 break; 98 case 'scheduling-Process ThreadCount': 99 this.schedulingProcessThreadCount(data); 100 break; 101 case 'scheduling-Process SwitchCount': 102 this.schedulingProcessSwitchCount(data); 103 break; 104 case 'scheduling-Thread Freq': 105 this.schedulingThreadFreq(data); 106 break; 107 } 108 } 109 private schedulingClearData(data: { id: string; action: string; params: unknown }): void { 110 this.clearAll(); 111 self.postMessage({ 112 id: data.id, 113 action: data.action, 114 results: [], 115 }); 116 } 117 private schedulingInitFreqData(data: { id: string; action: string; params: unknown }): void { 118 //@ts-ignore 119 if (data.params.list) { 120 //@ts-ignore 121 this.groupFreqByCpu(convertJSON(data.params.list) || []); 122 self.postMessage({ 123 id: data.id, 124 action: data.action, 125 results: [], 126 }); 127 } else { 128 this.getCpuFrequency('scheduling-initFreqData'); 129 } 130 } 131 private schedulinGetProcessAndThread(data: { id: string; action: string; params: unknown }): void { 132 //@ts-ignore 133 if (data.params.list) { 134 //@ts-ignore 135 let arr = convertJSON(data.params.list) || []; 136 //@ts-ignore 137 this.handleProcessThread(arr); 138 self.postMessage({ 139 id: data.id, 140 action: data.action, 141 results: [], 142 }); 143 } else { 144 this.getProcessAndThread(); 145 } 146 } 147 private schedulingGetCpuIdle0(data: { id: string; action: string; params: unknown }): void { 148 //@ts-ignore 149 if (data.params.list) { 150 //@ts-ignore 151 let arr = convertJSON(data.params.list) || []; 152 //@ts-ignore 153 this.handleCPUIdle0Map(arr); 154 self.postMessage({ 155 id: data.id, 156 action: data.action, 157 results: [], 158 }); 159 } else { 160 this.getCpuIdle0(); 161 } 162 } 163 private schedulingGetCpuUsage(data: { id: string; action: string; params: unknown }): void { 164 //@ts-ignore 165 if (data.params.list) { 166 //@ts-ignore 167 let arr = convertJSON(data.params.list) || []; 168 self.postMessage({ 169 id: data.id, 170 action: data.action, 171 results: arr, 172 }); 173 arr = []; 174 } else { 175 this.getCpuUsage(); 176 } 177 } 178 private schedulingCPUFrequency(data: { id: string; action: string; params: unknown }): void { 179 if (this.cpuAnalysisMap.has('freq')) { 180 self.postMessage({ 181 id: data.id, 182 action: data.action, 183 results: this.cpuAnalysisMap.get('freq') || [], 184 }); 185 } else { 186 //@ts-ignore 187 if (data.params.list) { 188 //@ts-ignore 189 let res = this.computeCpuMeasureDur(convertJSON(data.params.list) || [], 'freq'); 190 this.cpuAnalysisMap.set('freq', res); 191 self.postMessage({ 192 id: data.id, 193 action: data.action, 194 results: res, 195 }); 196 } else { 197 this.getCpuFrequency('scheduling-CPU Frequency'); 198 } 199 } 200 } 201 private schedulingCPUFrequencyThread(data: { id: string; action: string; params: unknown }): void { 202 //@ts-ignore 203 if (data.params.list) { 204 self.postMessage({ 205 id: data.id, 206 action: data.action, 207 //@ts-ignore 208 results: this.handlerFreqThreadData(convertJSON(data.params.list) || []), 209 }); 210 } else { 211 //@ts-ignore 212 this.cpu = data.params.cpu; 213 //@ts-ignore 214 this.freq = data.params.freq; 215 //@ts-ignore 216 this.getThreadStateByCpu(data.params.cpu); 217 } 218 } 219 private schedulingCPUIdle(data: { id: string; action: string; params: unknown }): void { 220 if (this.cpuAnalysisMap.has('idle')) { 221 self.postMessage({ 222 id: data.id, 223 action: data.action, 224 results: this.cpuAnalysisMap.get('idle') || [], 225 }); 226 } else { 227 //@ts-ignore 228 if (data.params.list) { 229 //@ts-ignore 230 let res = this.computeCpuMeasureDur(convertJSON(data.params.list) || []); 231 this.cpuAnalysisMap.set('idle', res); 232 self.postMessage({ 233 id: data.id, 234 action: data.action, 235 results: res, 236 }); 237 } else { 238 this.getCpuIdle(); 239 } 240 } 241 } 242 private schedulingCPUIrq(data: { id: string; action: string; params: unknown }): void { 243 if (this.cpuAnalysisMap.has('irq')) { 244 self.postMessage({ 245 id: data.id, 246 action: data.action, 247 results: this.cpuAnalysisMap.get('irq') || [], 248 }); 249 } else { 250 //@ts-ignore 251 if (data.params.list) { 252 //@ts-ignore 253 let res = this.groupIrgDataByCpu(convertJSON(data.params.list) || []); 254 this.cpuAnalysisMap.set('irq', res); 255 self.postMessage({ 256 id: data.id, 257 action: data.action, 258 results: res, 259 }); 260 } else { 261 this.getCpuIrq(); 262 } 263 } 264 } 265 private schedulingThreadCpuUsage(data: { id: string; action: string; params: unknown }): void { 266 //@ts-ignore 267 if (data.params.list) { 268 self.postMessage({ 269 id: data.id, 270 action: data.action, 271 //@ts-ignore 272 results: this.handlerThreadCpuUsageData(convertJSON(data.params.list) || []), 273 }); 274 } else { 275 //@ts-ignore 276 this.bigCores = data.params.bigCores || []; 277 //@ts-ignore 278 this.midCores = data.params.midCores || []; 279 //@ts-ignore 280 this.smallCores = data.params.smallCores || []; 281 //@ts-ignore 282 this.queryThreadCpuUsage(data.params.bigCores || [], data.params.midCores || [], data.params.smallCores || []); 283 } 284 } 285 private schedulingThreadRunTime(data: { id: string; action: string; params: unknown }): void { 286 //@ts-ignore 287 if (data.params.list) { 288 //@ts-ignore 289 let arr = convertJSON(data.params.list) || []; 290 self.postMessage({ 291 id: data.id, 292 action: data.action, 293 results: arr.map((it) => { 294 //@ts-ignore 295 it.maxDurationStr = getProbablyTime(it.maxDuration); 296 //@ts-ignore 297 it.pName = this.processMap.get(it.pid) || 'null'; 298 //@ts-ignore 299 it.tName = this.threadMap.get(it.tid) || 'null'; 300 return it; 301 }), 302 }); 303 } else { 304 //@ts-ignore 305 this.queryThreadRunTime(data.params.cpuMax); 306 } 307 } 308 private schedulingProcessThreadCount(data: { id: string; action: string; params: unknown }): void { 309 //@ts-ignore 310 if (data.params.list) { 311 self.postMessage({ 312 id: data.id, 313 action: data.action, 314 //@ts-ignore 315 results: convertJSON(data.params.list) || [], 316 }); 317 } else { 318 this.queryProcessThreadCount(); 319 } 320 } 321 private schedulingProcessSwitchCount(data: { id: string; action: string; params: unknown }): void { 322 //@ts-ignore 323 if (data.params.list) { 324 //@ts-ignore 325 let arr = convertJSON(data.params.list) || []; 326 self.postMessage({ 327 id: data.id, 328 action: data.action, 329 results: arr.map((it) => { 330 //@ts-ignore 331 it.pName = this.processMap.get(it.pid) || 'null'; 332 //@ts-ignore 333 it.tName = this.threadMap.get(it.tid) || 'null'; 334 return it; 335 }), 336 }); 337 } else { 338 this.queryProcessSwitchCount(); 339 } 340 } 341 private schedulingThreadFreq(data: { id: string; action: string; params: unknown }): void { 342 //@ts-ignore 343 if (data.params.list) { 344 self.postMessage({ 345 id: data.id, 346 action: data.action, 347 //@ts-ignore 348 results: this.handlerThreadFreqData(convertJSON(data.params.list) || []), 349 }); 350 } else { 351 //@ts-ignore 352 this.queryThreadStateByTid(data.params.tid); 353 } 354 } 355 getProcessAndThread(): void { 356 this.queryData( 357 this.currentEventId, 358 'scheduling-getProcessAndThread', 359 ` 360select tid id,ifnull(name,'null') name,'t' type from thread 361union all 362select pid id,ifnull(name,'null') name,'p' type from process; 363 `, 364 {} 365 ); 366 } 367 368 getCpuUsage(): void { 369 this.queryData( 370 this.currentEventId, 371 'scheduling-getCpuUsage', 372 ` 373select cpu, 374 sum(case 375 when A.ts < B.start_ts 376 then (A.ts - B.start_ts + A.dur) 377 when A.ts >= B.start_ts 378 and (A.ts + A.dur) <= B.end_ts 379 then A.dur 380 when (A.ts + A.dur) > B.end_ts 381 then (B.end_ts - A.ts) end) / cast(B.end_ts - B.start_ts as float) as usage 382from thread_state A, 383 trace_range B 384where (A.ts - B.start_ts) > 0 385 and A.dur > 0 386 and (A.ts + A.dur) > B.start_ts 387 and cpu >= 0 388 and A.ts < B.end_ts 389group by cpu 390order by cpu; 391`, 392 {} 393 ); 394 } 395 396 getCpuFrequency(name: string): void { 397 this.queryData( 398 this.currentEventId, 399 name, 400 ` 401select cpu,value,ts,dur 402from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id 403where cmf.name = 'cpu_frequency' 404order by cpu,ts; 405`, 406 {} 407 ); 408 } 409 410 getThreadStateByCpu(cpu: number): void { 411 let sql = ` 412select st.tid, 413 st.pid, 414 dur, 415 ts - tr.start_ts as ts 416from thread_state st,trace_range tr 417where cpu = ${cpu} 418 and dur > 0 419 and ts > tr.start_ts 420 and ts + st.dur < tr.end_ts 421order by ts;`; 422 this.queryData(this.currentEventId, 'scheduling-CPU Frequency Thread', sql, {}); 423 } 424 425 getCpuIdle0(): void { 426 this.queryData( 427 this.currentEventId, 428 'scheduling-getCpuIdle0', 429 ` 430select cpu,value,ts,dur 431from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id 432where cmf.name = 'cpu_idle' and value = 0 433`, 434 {} 435 ); 436 } 437 438 getCpuIdle(): void { 439 this.queryData( 440 this.currentEventId, 441 'scheduling-CPU Idle', 442 ` 443select cpu,value,ts,dur 444from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id 445where cmf.name = 'cpu_idle' and value != 0 446`, 447 {} 448 ); 449 } 450 451 getCpuIrq(): void { 452 this.queryData( 453 this.currentEventId, 454 'scheduling-CPU Irq', 455 ` 456 SELECT callid AS cpu, 457 CASE WHEN cat = 'ipi' THEN 'irq' ELSE cat END AS block, 458 CASE WHEN cat = 'ipi' THEN 'IPI' || name ELSE name END AS value, 459 sum( dur ) sum, 460 min( dur ) min, 461 max( dur ) max, 462 avg( dur ) avg 463 FROM 464 irq 465 WHERE 466 cat = 'ipi' 467 OR cat = 'softirq' 468 OR ( cat = 'irq' AND flag = '1' ) 469 GROUP BY 470 callid, 471 cat, 472 name;`, 473 {} 474 ); 475 } 476 477 queryThreadCpuUsage(bigCores: number[], midCores: number[], smallCores: number[]): void { 478 let sql = ` 479 select A.pid,A.tid,A.cpu, 480 sum(A.dur) as total 481from thread_state A 482where cpu not null 483group by A.pid, A.tid,A.cpu`; 484 this.queryData(this.currentEventId, 'scheduling-Thread CpuUsage', sql, {}); 485 } 486 487 queryThreadRunTime(cpuMax: number): void { 488 let sql = ` 489 select (row_number() over (order by max(A.dur) desc)) no,A.tid, A.cpu,A.ts as timestamp,A.pid, max(A.dur) maxDuration 490 from thread_state A, trace_range B 491 where cpu not null and A.ts between B.start_ts and B.end_ts 492 group by A.tid, A.pid 493 order by maxDuration desc 494 limit 20`; 495 this.queryData(this.currentEventId, 'scheduling-Thread RunTime', sql, {}); 496 } 497 498 queryProcessThreadCount(): void { 499 this.queryData( 500 this.currentEventId, 501 'scheduling-Process ThreadCount', 502 ` 503select row_number() over (order by count(tid) desc) NO,count(tid) threadNumber,p.pid,ifnull(p.name,'null') pName 504from thread t 505left join process p on t.ipid = p.ipid 506group by p.pid, p.name 507order by threadNumber desc limit 20;`, 508 {} 509 ); 510 } 511 512 queryProcessSwitchCount(): void { 513 this.queryData( 514 this.currentEventId, 515 'scheduling-Process SwitchCount', 516 ` 517select row_number() over (order by count(a.tid) desc) NO, 518 count(a.tid) as switchCount, 519 a.tid, 520 a.pid 521from thread_state a 522where cpu not null 523group by a.pid,a.tid limit 20;`, 524 {} 525 ); 526 } 527 528 queryThreadStateByTid(tid: number): void { 529 let sql = ` 530select cpu,dur,ts - tr.start_ts as ts 531from thread_state st,trace_range tr 532where cpu not null 533 and tid = ${tid} 534 and dur > 0 535 and ts > tr.start_ts 536 and ts + st.dur < tr.end_ts 537 order by cpu,ts;`; 538 this.queryData(this.currentEventId, 'scheduling-Thread Freq', sql, {}); 539 } 540 541 groupIrgDataByCpu(arr: Irq[]): Map<number, CpuAnalysis[]> { 542 //首先计算 每个频点的持续时间,并根据Cpu来分组 543 let map: Map<number, Array<Irq>> = new Map<number, Array<Irq>>(); 544 let sumMap: Map<number, number> = new Map<number, number>(); 545 for (let i = 0, len = arr.length; i < len; i++) { 546 let ca = arr[i]; 547 if (map.has(ca.cpu)) { 548 map.get(ca.cpu)!.push(ca); 549 } else { 550 map.set(ca.cpu, [ca]); 551 } 552 sumMap.set(ca.cpu, (sumMap.get(ca.cpu) || 0) + ca.sum); 553 } 554 let target: Map<number, CpuAnalysis[]> = new Map<number, CpuAnalysis[]>(); 555 for (let key of map.keys()) { 556 let cpuArr = map 557 .get(key)! 558 .sort((a, b) => b.sum - a.sum) 559 .slice(0, 20); 560 target.set( 561 key, 562 cpuArr.map((irqBean) => { 563 let item = { 564 cpu: irqBean.cpu, 565 value: irqBean.value, 566 sum: irqBean.sum, 567 sumTimeStr: getProbablyTime(irqBean.sum), 568 min: getProbablyTime(irqBean.min), 569 max: getProbablyTime(irqBean.max), 570 avg: getProbablyTime(irqBean.avg), 571 minValue: irqBean.min, 572 maxValue: irqBean.max, 573 avgValue: irqBean.avg, 574 ratio: ((irqBean.sum / (sumMap.get(key) || 1)) * 100).toFixed(2), 575 block: irqBean.block, 576 }; 577 //@ts-ignore 578 return item as CpuAnalysis; 579 }) 580 ); 581 } 582 return target; 583 } 584 585 handleProcessThread(arr: { id: number; name: string; type: string }[]): void { 586 this.processMap.clear(); 587 this.threadMap.clear(); 588 for (let pt of arr) { 589 if (pt.type === 'p') { 590 this.processMap.set(pt.id, pt.name); 591 } else { 592 this.threadMap.set(pt.id, pt.name); 593 } 594 } 595 } 596 597 handleCPUIdle0Map(arr: CpuMeasure[]): void { 598 this.cpuIdle0Map.clear(); 599 for (let i = 0, len = arr.length; i < len; i++) { 600 let ca = arr[i]; 601 ca.ts = ca.ts - this.startTs; 602 if (ca.dur === null || ca.dur === undefined) { 603 ca.dur = this.totalDur - ca.ts; 604 } 605 if (this.cpuIdle0Map.has(ca.cpu)) { 606 this.cpuIdle0Map.get(ca.cpu)!.push(ca); 607 } else { 608 this.cpuIdle0Map.set(ca.cpu, [ca]); 609 } 610 } 611 } 612 613 getEffectiveFrequencyDur(m: CpuMeasure): void { 614 let arr = this.cpuIdle0Map.get(m.cpu) || []; 615 let filterArr: CpuMeasure[] = []; 616 for (let it of arr) { 617 if (Math.min(m.ts + m.dur, it.ts + it.dur) - Math.max(m.ts, it.ts) > 0) { 618 filterArr.push(it); 619 } 620 if (it.ts > m.ts + m.dur) { 621 break; 622 } 623 } 624 let dur = 0; 625 for (let idle of filterArr) { 626 dur += Math.min(m.ts + m.dur, idle.ts + idle.dur) - Math.max(m.ts, idle.ts); 627 } 628 m.dur = dur; 629 } 630 631 groupFreqByCpu(arr: CpuMeasure[]): void { 632 let map: Map<number, Array<CpuMeasure>> = new Map<number, Array<CpuMeasure>>(); 633 for (let i = 0, len = arr.length; i < len; i++) { 634 let ca = arr[i]; 635 ca.ts = ca.ts - this.startTs; 636 if (ca.dur === null || ca.dur === undefined) { 637 ca.dur = this.totalDur - ca.ts; 638 } 639 if (ca.dur > 0) { 640 if (map.has(ca.cpu)) { 641 map.get(ca.cpu)!.push(ca); 642 } else { 643 let cpuArr: CpuMeasure[] = []; 644 if (ca.ts > 0) { 645 cpuArr.push({ 646 cpu: ca.cpu, 647 value: -1, 648 block: '', 649 ts: 0, 650 dur: ca.ts, 651 }); 652 } 653 cpuArr.push(ca); 654 map.set(ca.cpu, cpuArr); 655 } 656 } 657 } 658 this.cpuFreqMap.clear(); 659 this.cpuFreqMap = map; 660 } 661 662 private filterMap(map: Map<number, Array<CpuMeasure>>, key: number): Map<number, CpuAnalysis[]> { 663 //@ts-ignore 664 return map.get(key)!.reduce((group: unknown, ca) => { 665 const { value } = ca; 666 //@ts-ignore 667 const groupItem = group[value]; 668 if (groupItem) { 669 groupItem.sum = groupItem.sum + ca.dur; 670 groupItem.min = groupItem.min < ca.dur ? groupItem.min : ca.dur; 671 groupItem.max = groupItem.max > ca.dur ? groupItem.max : ca.dur; 672 groupItem.count = groupItem.count + 1; 673 groupItem.avg = (groupItem.sum / groupItem.count).toFixed(2); 674 } else { 675 //@ts-ignore 676 group[value] = { 677 cpu: ca.cpu, 678 value: ca.value, 679 sum: ca.dur, 680 min: ca.dur, 681 max: ca.dur, 682 avg: ca.dur, 683 count: 1, 684 ratio: '', 685 block: ca.block, 686 }; 687 } 688 return group; 689 }, {}); 690 } 691 private setTargetMapValue(cpuArr: Array<CpuAnalysis>, sumMap: Map<number, number>, key: number): unknown[] { 692 return cpuArr.map((cpuAnalysisBean) => { 693 return { 694 cpu: cpuAnalysisBean.cpu, 695 value: cpuAnalysisBean.value, 696 sum: cpuAnalysisBean.sum, 697 sumTimeStr: getProbablyTime(cpuAnalysisBean.sum), 698 min: getProbablyTime(cpuAnalysisBean.min), 699 minValue: cpuAnalysisBean.min, 700 max: getProbablyTime(cpuAnalysisBean.max), 701 maxValue: cpuAnalysisBean.max, 702 avgValue: cpuAnalysisBean.avg, 703 avg: getProbablyTime(cpuAnalysisBean.avg), 704 count: cpuAnalysisBean.count, 705 ratio: ((cpuAnalysisBean.sum / (sumMap.get(key) || 1)) * 100).toFixed(2), 706 block: cpuAnalysisBean.block, 707 }; 708 }); 709 } 710 //根据查询的数据,加工出CPU调度分析所需要展示的相关数据 711 private computeCpuMeasureDur(arr: Array<CpuMeasure>, type?: string): Map<number, CpuAnalysis[]> { 712 //首先计算 每个频点的持续时间,并根据Cpu来分组 713 let map: Map<number, Array<CpuMeasure>> = new Map<number, Array<CpuMeasure>>(); 714 let sumMap: Map<number, number> = new Map<number, number>(); 715 for (let i = 0, len = arr.length; i < len; i++) { 716 let ca = arr[i]; 717 ca.ts = ca.ts - this.startTs; 718 if (ca.dur === null || ca.dur === undefined) { 719 ca.dur = this.totalDur - ca.ts; 720 } 721 if (type === 'freq') { 722 this.getEffectiveFrequencyDur(ca); 723 } 724 if (ca.dur > 0) { 725 if (map.has(ca.cpu)) { 726 map.get(ca.cpu)!.push(ca); 727 } else { 728 map.set(ca.cpu, [ca]); 729 } 730 sumMap.set(ca.cpu, (sumMap.get(ca.cpu) || 0) + ca.dur); 731 } 732 } 733 let target: Map<number, CpuAnalysis[]> = new Map<number, CpuAnalysis[]>(); 734 //再根据频点值进行分组求和 735 for (let key of map.keys()) { 736 let obj = this.filterMap(map, key); 737 let cpuArr = (Object.values(obj) as CpuAnalysis[]) 738 .sort((a, b) => { 739 if (type === 'freq') { 740 return b.sum - a.sum; 741 } else { 742 return a.value - b.value; 743 } 744 }) 745 .slice(0, 20); 746 let value = this.setTargetMapValue(cpuArr, sumMap, key); 747 target.set(key, value as CpuAnalysis[]); 748 } 749 return target; 750 } 751 752 private handlerFreqThreadData(arr: FreqThread[]): unknown { 753 let cpuFreqArr: CpuMeasure[] = (this.cpuFreqMap.get(this.cpu) || []).filter((it) => it.value === this.freq); 754 let map: Map< 755 number, 756 { tid: number; tName: string; pid: number; pName: string; dur: number; durStr: string; ratio: string } 757 > = new Map(); 758 let sumFreqDur = 0; 759 cpuFreqArr.map((it) => { 760 sumFreqDur += it.dur; 761 let freqEndTs = it.ts + it.dur; 762 let threads = arr.filter((f) => Math.min(f.ts + f.dur, freqEndTs) - Math.max(f.ts, it.ts) > 0); 763 for (let tf of threads) { 764 let tfEndTs = tf.ts + tf.dur; 765 let dur = Math.min(freqEndTs, tfEndTs) - Math.max(it.ts, tf.ts); 766 if (map.has(tf.tid)) { 767 map.get(tf.tid)!.dur = map.get(tf.tid)!.dur + dur; 768 map.get(tf.tid)!.durStr = getProbablyTime(map.get(tf.tid)!.dur); 769 } else { 770 map.set(tf.tid, { 771 tid: tf.tid, 772 tName: this.threadMap.get(tf.tid) || 'null', 773 pid: tf.pid, 774 pName: this.processMap.get(tf.pid) || 'null', 775 dur: dur, 776 ratio: '0', 777 durStr: getProbablyTime(dur), 778 }); 779 } 780 } 781 }); 782 let target = Array.from(map.values()).sort((a, b) => b.dur - a.dur); 783 return target 784 .map((it) => { 785 it.ratio = ((it.dur / sumFreqDur) * 100).toFixed(2); 786 return it; 787 }) 788 .slice(0, 20); 789 } 790 private filterThreadCpuUsageArr(arr: unknown, sumBig: number, sumMid: number, sumSmall: number): void { 791 //@ts-ignore 792 return arr.reduce((group: unknown, item: { total: number; pid: number; tid: number; cpu: number }) => { 793 const { tid } = item; 794 //@ts-ignore 795 let tidObj: unknown = group[`${tid}`]; 796 let cpuType: string = 'mid'; 797 if (this.bigCores.includes(item.cpu)) { 798 cpuType = 'big'; 799 sumBig += item.total; 800 } 801 if (this.midCores.includes(item.cpu)) { 802 cpuType = 'mid'; 803 sumMid += item.total; 804 } 805 if (this.smallCores.includes(item.cpu)) { 806 cpuType = 'small'; 807 sumSmall += item.total; 808 } 809 if (tidObj) { 810 //@ts-ignore 811 tidObj.big += cpuType === 'big' ? item.total : 0; 812 //@ts-ignore 813 tidObj.mid += cpuType === 'mid' ? item.total : 0; 814 //@ts-ignore 815 tidObj.small += cpuType === 'small' ? item.total : 0; 816 //@ts-ignore 817 tidObj.total += item.total; 818 //@ts-ignore 819 tidObj[`cpu${item.cpu}`] = item.total; 820 } else { 821 //@ts-ignore 822 group[`${tid}`] = { 823 pid: item.pid, 824 pName: this.processMap.get(item.pid) || 'null', 825 tid: item.tid, 826 tName: this.threadMap.get(item.tid) || 'null', 827 total: item.total, 828 big: cpuType === 'big' ? item.total : 0, 829 mid: cpuType === 'mid' ? item.total : 0, 830 small: cpuType === 'small' ? item.total : 0, 831 }; 832 //@ts-ignore 833 group[`${tid}`][`cpu${item.cpu}`] = item.total; 834 } 835 return group; 836 }, {}); 837 } 838 //加工Top20线程大中小核占用率数据 839 private handlerThreadCpuUsageData(arr: Array<ThreadCpuUsage>): Map<string, ThreadCpuUsage[]> { 840 let sumBig = 0; 841 let sumMid = 0; 842 let sumSmall = 0; 843 let reduceObj = this.filterThreadCpuUsageArr(arr, sumBig, sumMid, sumSmall); 844 // @ts-ignore 845 let source: unknown[] = Object.values(reduceObj); 846 for (let obj of source) { 847 // @ts-ignore 848 obj.bigPercent = sumBig === 0 ? '0' : ((obj.big / sumBig) * 100).toFixed(2); 849 // @ts-ignore 850 obj.midPercent = sumMid === 0 ? '0' : ((obj.mid / sumMid) * 100).toFixed(2); 851 // @ts-ignore 852 obj.smallPercent = sumSmall === 0 ? '0' : ((obj.small / sumSmall) * 100).toFixed(2); 853 // @ts-ignore 854 obj.bigTimeStr = getProbablyTime(obj.big); 855 // @ts-ignore 856 obj.midTimeStr = getProbablyTime(obj.mid); 857 // @ts-ignore 858 obj.smallTimeStr = getProbablyTime(obj.small); 859 } 860 let map: Map<string, Array<ThreadCpuUsage>> = new Map<string, Array<ThreadCpuUsage>>(); 861 // @ts-ignore 862 map.set('total', source.sort((a, b) => b.total - a.total).slice(0, 20)); 863 // @ts-ignore 864 map.set('big', source.sort((a, b) => b.big - a.big).slice(0, 20)); 865 // @ts-ignore 866 map.set('mid', source.sort((a, b) => b.mid - a.mid).slice(0, 20)); 867 // @ts-ignore 868 map.set('small', source.sort((a, b) => b.small - a.small).slice(0, 20)); 869 // @ts-ignore 870 return map; 871 } 872 private filterThreadFreqData(arr: unknown, sumDur: number): unknown { 873 //@ts-ignore 874 return arr.reduce((group: unknown, tf: { freqArr: unknown }) => { 875 //@ts-ignore 876 for (let fa of tf.freqArr) { 877 const { cpu, freq } = fa; 878 //@ts-ignore 879 if (group[`${cpu}-${freq}`]) { 880 //@ts-ignore 881 group[`${cpu}-${freq}`].time = group[`${cpu}-${freq}`].time + fa.dur; 882 //@ts-ignore 883 //@ts-ignore 884 group[`${cpu}-${freq}`].timeStr = getProbablyTime(group[`${cpu}-${freq}`].time); 885 //@ts-ignore 886 group[`${cpu}-${freq}`].ratio = ((group[`${cpu}-${freq}`].time / sumDur) * 100).toFixed(2); 887 } else { 888 //@ts-ignore 889 group[`${cpu}-${freq}`] = { 890 freq: freq, 891 cpu: cpu, 892 time: fa.dur, 893 timeStr: getProbablyTime(fa.dur), 894 ratio: ((fa.dur / sumDur) * 100).toFixed(2), 895 totalDur: sumDur, 896 }; 897 } 898 } 899 return group; 900 }, {}); 901 } 902 903 private handlerThreadFreqData( 904 arr: { 905 cpu: number; 906 dur: number; 907 ts: number; 908 freqArr: { cpu: number; freq: number; dur: number }[]; 909 }[] 910 ): Array<unknown> { 911 let sumDur: number = 0; 912 arr.map((it) => { 913 it.freqArr = []; 914 let itEndTs = it.ts + it.dur; 915 let freqArr: CpuMeasure[] = this.cpuFreqMap.get(it.cpu) || []; 916 let threadFreqArr = freqArr.filter( 917 (f) => 918 (it.ts >= f.ts && it.ts <= f.ts + f.dur) || 919 (it.ts <= f.ts && itEndTs >= f.ts + f.dur) || 920 (itEndTs > f.ts && itEndTs <= f.ts + f.dur) 921 ); 922 for (let tf of threadFreqArr) { 923 let tfEndTs = tf.ts + tf.dur; 924 it.freqArr.push({ 925 cpu: it.cpu, 926 freq: tf.value as number, 927 dur: Math.min(itEndTs, tfEndTs) - Math.max(it.ts, tf.ts), 928 }); 929 } 930 sumDur += it.dur; 931 return it; 932 }); 933 let obj: unknown = this.filterThreadFreqData(arr, sumDur); 934 //@ts-ignore 935 let target = Object.values(obj); 936 //@ts-ignore 937 return target.sort((a, b) => b.time - a.time); 938 } 939} 940 941export class CpuUsage { 942 cpu: number = 0; 943 usage: number = 0; 944} 945 946export class Irq { 947 cpu: number = 0; 948 value: string = ''; 949 block: string = ''; 950 max: number = 0; 951 min: number = 0; 952 avg: number = 0; 953 sum: number = 0; 954 ratio: string = ''; 955} 956 957export class CpuMeasure { 958 cpu: number = 0; 959 value: number | string = 0; 960 block: string = ''; 961 ts: number = 0; 962 dur: number = 0; 963} 964 965export class CpuAnalysis { 966 cpu: number = 0; 967 value: number = 0; 968 sum: number = 0; 969 min: number = 0; 970 max: number = 0; 971 avg: number = 0; 972 count: number = 0; 973 ratio: string = ''; 974 block: string = ''; 975} 976 977export class ThreadCpuUsage { 978 cpu: number = 0; 979 pid: number = 0; 980 pName: string = ''; 981 tid: number = 0; 982 tName: string = ''; 983 total: number = 0; 984 big: number = 0; 985 mid: number = 0; 986 small: number = 0; 987 bigPercent: string = ''; 988 bigTimeStr: string = ''; 989 midPercent: string = ''; 990 midTimeStr: string = ''; 991 smallPercent: string = ''; 992 smallTimeStr: string = ''; 993} 994 995export class FreqThread { 996 pid: number = 0; 997 pName: string = ''; 998 tid: number = 0; 999 tName: string = ''; 1000 dur: number = 0; 1001 durStr: string = ''; 1002 ts: number = 0; 1003 freq: number = 0; 1004} 1005