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 { BaseElement, element } from '../../../base-ui/BaseElement';
17import { SpSchedulingAnalysis } from './SpSchedulingAnalysis';
18import { DrawerCpuTabs } from './DrawerCpuTabs';
19import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie';
20import { LitDrawer } from '../../../base-ui/drawer/LitDrawer';
21import '../../../base-ui/drawer/LitDrawer';
22import './DrawerCpuTabs';
23import { procedurePool } from '../../database/Procedure';
24import { info } from '../../../log/Log';
25import { LitSelect } from '../../../base-ui/select/LitSelect';
26import '../../../base-ui/progress-bar/LitProgressBar';
27import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar';
28import { pieChartColors } from '../../../base-ui/chart/pie/LitChartPieData';
29import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil';
30import { TabCpuAnalysisHtml } from './TabCpuAnalysis.html';
31
32@element('tab-cpu-analysis')
33export class TabCpuAnalysis extends BaseElement {
34  private cpuUsageGrid: HTMLDivElement | undefined;
35  private cpuUsageChart: HTMLDivElement | undefined;
36  private drawer: LitDrawer | undefined | null;
37  private cpuPieMap: Map<number, LitChartPie> = new Map<number, LitChartPie>();
38  private schedulingSelect: LitSelect | undefined | null;
39  private drawerCpuTabs: DrawerCpuTabs | undefined | null;
40  private progress: LitProgressBar | null | undefined;
41  private loadingUsage: boolean = false;
42  private loadingPieData: boolean = false;
43
44  initElements(): void {
45    this.progress = this.shadowRoot!.querySelector<LitProgressBar>('#loading');
46    this.cpuUsageGrid = this.shadowRoot?.querySelector('#cpu_usage_table') as HTMLDivElement;
47    this.cpuUsageChart = this.shadowRoot?.querySelector('#cpu_usage_chart') as HTMLDivElement;
48    this.schedulingSelect = this.shadowRoot?.querySelector<LitSelect>('#scheduling_select');
49    this.drawer = this.shadowRoot!.querySelector<LitDrawer>('#drawer-right');
50    this.drawerCpuTabs = this.shadowRoot?.querySelector<DrawerCpuTabs>('#drawer-cpu-tabs');
51    this.schedulingSelect!.onchange = (e): void => {
52      this.loadingPieData = true;
53      this.progress!.loading = this.loadingUsage || this.loadingPieData; //@ts-ignore
54      this.queryPieChartDataByType((e as unknown).detail.text);
55    };
56    this.drawer!.onClose = (): void => {
57      this.drawerCpuTabs!.clearData();
58    };
59  }
60
61  init(): void {
62    this.cpuPieMap.clear();
63    this.cpuUsageGrid!.innerHTML = '';
64    this.cpuUsageChart!.innerHTML = '';
65    this.schedulingSelect!.value = '1';
66    this.cpuUsageGrid!.append(this.createUsageItem('usage', '%'));
67    for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) {
68      let cpuPie = new LitChartPie();
69      cpuPie.className = 'pie-chart';
70      this.cpuPieMap.set(i, cpuPie);
71      this.cpuUsageGrid!.append(this.createUsageItem(`CPU: ${i}`, 0));
72      this.cpuUsageChart!.append(this.createUsageChartItem(i, cpuPie));
73    }
74    this.loadingUsage = true;
75    this.loadingPieData = true;
76    this.progress!.loading = this.loadingUsage || this.loadingPieData;
77    this.queryLogicWorker('scheduling-getCpuUsage', 'query Cpu Usage Time:', (res): void => {
78      //@ts-ignore
79      if (res && res.length > 0) {
80        this.cpuUsageGrid!.innerHTML = '';
81        this.cpuUsageGrid!.append(this.createUsageItem('usage', '%'));
82        if (res instanceof Array) {
83          for (let re of res) {
84            this.cpuUsageGrid!.append(this.createUsageItem(`CPU: ${re.cpu}`, ((re.usage || 0) * 100).toFixed(2)));
85          }
86        }
87      }
88      this.loadingUsage = false;
89      this.progress!.loading = this.loadingUsage || this.loadingPieData;
90    });
91    this.queryPieChartDataByType('CPU Idle');
92    SpStatisticsHttpUtil.addOrdinaryVisitAction({
93      event: 'CPU Data',
94      action: 'trace_tab',
95    });
96  }
97
98  queryPieChartDataByType(type: string): void {
99    SpStatisticsHttpUtil.addOrdinaryVisitAction({
100      event: `Analysis ${type}`,
101      action: 'scheduling_analysis',
102    });
103    let tip = '';
104    if (type === 'CPU Frequency') {
105      tip = 'freq:';
106    } else if (type === 'CPU Idle') {
107      tip = 'idle:';
108    } else {
109      tip = 'irq:';
110    }
111    this.queryLogicWorker(`scheduling-${type}`, `query ${type} Analysis Time:`, (res): void => {
112      for (let key of this.cpuPieMap.keys()) {
113        this.cpuPieMap.get(key)!.config = {
114          appendPadding: 10, //@ts-ignore
115          data: res.get(key) || [],
116          angleField: 'sum',
117          colorField: 'value',
118          radius: 0.8,
119          tip: (obj): string => {
120            return `<div>
121                                    <div>${tip}${
122              // @ts-ignore
123              obj.obj.value
124            }</div> 
125                                    <div>ratio:${
126                                      // @ts-ignore
127                                      obj.obj.ratio
128                                    }%</div>
129                                </div>
130                                `;
131          },
132          label: {
133            type: 'outer',
134            color:
135              type !== 'CPU Idle'
136                ? undefined
137                : (it): string => {
138                    //@ts-ignore
139                    return pieChartColors[(it as unknown).value];
140                  },
141          },
142          interactions: [
143            {
144              type: 'element-active',
145            },
146          ],
147        };
148      }
149      this.loadingPieData = false;
150      this.progress!.loading = this.loadingUsage || this.loadingPieData;
151    });
152  }
153
154  queryLogicWorker(cpuAnalysisType: string, log: string, handler: (res: unknown) => void): void {
155    let cpuAnalysisTime = new Date().getTime();
156    procedurePool.submitWithName(
157      'logic0',
158      cpuAnalysisType,
159      {
160        endTs: SpSchedulingAnalysis.endTs,
161        total: SpSchedulingAnalysis.totalDur,
162      },
163      undefined,
164      handler
165    );
166    let durTime = new Date().getTime() - cpuAnalysisTime;
167    info(log, durTime);
168  }
169
170  createUsageItem(name: string, value: unknown): HTMLDivElement {
171    let div = document.createElement('div');
172    div.className = 'usage_item_box';
173    div.innerHTML = `<div class="usage_item">${name}</div><div class="usage_item">${value}</div>`;
174    return div;
175  }
176
177  createUsageChartItem(cpu: number, pie: LitChartPie): HTMLDivElement {
178    let div = document.createElement('div');
179    div.className = 'usage_chart';
180    div.style.cursor = 'pointer';
181    div.innerHTML = `
182            <div style="height: 40px;line-height: 40px;margin-left: 10px">CPU: ${cpu}</div>
183        `;
184    div.append(pie);
185    div.addEventListener('click', (): void => {
186      if (this.loadingUsage || this.loadingPieData) {
187        return;
188      }
189      this.drawer!.drawerTitle = `CPU: ${cpu}`;
190      this.drawer!.visible = true;
191      this.drawerCpuTabs!.init(cpu, this.schedulingSelect!.value);
192    });
193    return div;
194  }
195
196  initHtml(): string {
197    return TabCpuAnalysisHtml;
198  }
199}
200