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