• 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, 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