• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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