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