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