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 { SpSystemTrace } from '../SpSystemTrace';
17import { info } from '../../../log/Log';
18import { TraceRow } from '../trace/base/TraceRow';
19import { ColorUtils } from '../trace/base/ColorUtils';
20import { CpuFreqLimitRender, CpuFreqLimitsStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCpuFreqLimits';
21import { CpuFreqStruct, FreqRender } from '../../database/ui-worker/ProcedureWorkerFreq';
22import { CpuStateRender, CpuStateStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCpuState';
23import { folderSupplier, folderThreadHandler, rowThreadHandler } from './SpChartManager';
24import { Utils } from '../trace/base/Utils';
25import { cpuFreqDataSender } from '../../database/data-trafic/cpu/CpuFreqDataSender';
26import { cpuStateSender } from '../../database/data-trafic/cpu/CpuStateSender';
27import { cpuFreqLimitSender } from '../../database/data-trafic/cpu/CpuFreqLimitDataSender';
28import {
29  getCpuLimitFreqId,
30  getCpuLimitFreqMax,
31  queryCpuFreq,
32  queryCpuMaxFreq,
33  queryCpuStateFilter,
34} from '../../database/sql/Cpu.sql';
35import { BaseStruct } from '../../bean/BaseStruct';
36
37export class SpFreqChart {
38  private readonly trace: SpSystemTrace;
39
40  constructor(trace: SpSystemTrace) {
41    this.trace = trace;
42  }
43
44  async init(parentRow?: TraceRow<BaseStruct>, traceId?: string): Promise<void> {
45    let freqList = await queryCpuFreq(traceId);
46    let cpuStateFilterIds = await queryCpuStateFilter(traceId);
47    //@ts-ignore
48    this.trace.stateRowsId = cpuStateFilterIds;
49    let cpuFreqLimits = await getCpuLimitFreqId(traceId);
50    let cpuFreqLimitsMax = await getCpuLimitFreqMax(cpuFreqLimits.map((limit) => limit.maxFilterId).join(','), traceId);
51    if (freqList.length > 0) {
52      let folderRow = this.createFolderRow(traceId);
53      folderRow.rowId = 'Cpu Frequency';
54      folderRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ_ALL;
55      folderRow.name = 'Cpu Frequency';
56      folderRow.selectChangeHandler = this.trace.selectChangeHandler;
57      this.trace.rowsEL?.appendChild(folderRow);
58      info('Cpu Freq data size is: ', freqList!.length);
59      await this.addFreqRows(freqList, folderRow, traceId);
60      if (parentRow) {
61        parentRow.addChildTraceRow(folderRow);
62      } else {
63        this.trace.rowsEL?.appendChild(folderRow);
64      }
65    }
66    if (cpuStateFilterIds.length > 0) {
67      let folderRowState = this.createFolderRow();
68      folderRowState.rowId = 'Cpu State';
69      folderRowState.rowType = TraceRow.ROW_TYPE_CPU_STATE_ALL;
70      folderRowState.name = 'Cpu State';
71      folderRowState.selectChangeHandler = this.trace.selectChangeHandler;
72      this.trace.rowsEL?.appendChild(folderRowState);
73      this.addStateRows(cpuStateFilterIds, folderRowState, traceId);
74      if (parentRow) {
75        parentRow.addChildTraceRow(folderRowState);
76      } else {
77        this.trace.rowsEL?.appendChild(folderRowState);
78      }
79    }
80    if (cpuFreqLimits.length > 0) {
81      let folderRowLimit = this.createFolderRow();
82      folderRowLimit.rowId = 'Cpu Freq Limit';
83      folderRowLimit.rowType = TraceRow.ROW_TYPE_CPU_FREQ_LIMITALL;
84      folderRowLimit.name = 'Cpu Freq Limit';
85      folderRowLimit.selectChangeHandler = this.trace.selectChangeHandler;
86      this.trace.rowsEL?.appendChild(folderRowLimit);
87      this.addFreqLimitRows(cpuFreqLimits, cpuFreqLimitsMax, folderRowLimit, traceId);
88      if (parentRow) {
89        parentRow.addChildTraceRow(folderRowLimit);
90      } else {
91        this.trace.rowsEL?.appendChild(folderRowLimit);
92      }
93    }
94  }
95
96  createFolderRow(traceId?: string): TraceRow<BaseStruct> {
97    let folder = TraceRow.skeleton<BaseStruct>(traceId);
98    folder.rowParentId = '';
99    folder.folder = true;
100    folder.style.height = '40px';
101    folder.rowHidden = folder.expansion;
102    folder.setAttribute('children', '');
103    folder.supplier = folderSupplier();
104    folder.onThreadHandler = folderThreadHandler(folder, this.trace);
105    return folder;
106  }
107
108  async addFreqRows(
109    freqList: Array<{ cpu: number; filterId: number }>,
110    folderRow: TraceRow<BaseStruct>,
111    traceId?: string
112  ): Promise<void> {
113    let freqMaxList = await queryCpuMaxFreq(traceId);
114    CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq;
115    let maxFreqObj = Utils.getFrequencyWithUnit(freqMaxList[0].maxFreq);
116    CpuFreqStruct.maxFreq = maxFreqObj.maxFreq;
117    CpuFreqStruct.maxFreqName = maxFreqObj.maxFreqName;
118    for (let i = 0; i < freqList.length; i++) {
119      const it = freqList[i];
120      let traceRow = TraceRow.skeleton<CpuFreqStruct>(traceId);
121      traceRow.rowId = `${it.filterId}`;
122      traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ;
123      traceRow.rowParentId = '';
124      traceRow.style.height = '40px';
125      traceRow.name = `Cpu ${it.cpu} Frequency`;
126      traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
127      traceRow.selectChangeHandler = this.trace.selectChangeHandler;
128      traceRow.supplierFrame = (): Promise<CpuFreqStruct[]> => cpuFreqDataSender(it.cpu, traceRow);
129      traceRow.focusHandler = (): void => {
130        this.trace?.displayTip(
131          traceRow,
132          CpuFreqStruct.hoverCpuFreqStruct,
133          `<span>${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct?.value!)} kHz</span>`
134        );
135      };
136      traceRow.findHoverStruct = (): void => {
137        CpuFreqStruct.hoverCpuFreqStruct = traceRow.getHoverStruct(true, false, 'value');
138      };
139      traceRow.onThreadHandler = rowThreadHandler<FreqRender>(
140        'freq',
141        'context',
142        {
143          type: `freq${it.cpu}`,
144        },
145        traceRow,
146        this.trace
147      );
148      folderRow!.addChildTraceRow(traceRow);
149    }
150  }
151
152  addStateRows(
153    cpuStateFilterIds: Array<{ cpu: number; filterId: number }>,
154    folderRowState: TraceRow<BaseStruct>,
155    traceId?: string
156  ): void {
157    for (let it of cpuStateFilterIds) {
158      let cpuStateRow = TraceRow.skeleton<CpuStateStruct>(traceId);
159      cpuStateRow.rowId = `${it.filterId}`;
160      cpuStateRow.rowType = TraceRow.ROW_TYPE_CPU_STATE;
161      cpuStateRow.rowParentId = '';
162      cpuStateRow.style.height = '40px';
163      cpuStateRow.name = `Cpu ${it.cpu} State`;
164      cpuStateRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
165      cpuStateRow.selectChangeHandler = this.trace.selectChangeHandler;
166      cpuStateRow.supplierFrame = async (): Promise<CpuStateStruct[]> => {
167        let rs = await cpuStateSender(it.filterId, cpuStateRow);
168        rs.forEach((t) => (t.cpu = it.cpu));
169        return rs;
170      };
171      cpuStateRow.focusHandler = (): void => {
172        this.trace.displayTip(
173          cpuStateRow,
174          CpuStateStruct.hoverStateStruct,
175          `<span>State: ${CpuStateStruct.hoverStateStruct?.value}</span>`
176        );
177      };
178      cpuStateRow.findHoverStruct = (): void => {
179        CpuStateStruct.hoverStateStruct = cpuStateRow.getHoverStruct();
180      };
181      cpuStateRow.onThreadHandler = rowThreadHandler<CpuStateRender>(
182        'cpu-state',
183        'cpuStateContext',
184        {
185          type: `cpu-state-${it.cpu}`,
186          cpu: it.cpu,
187        },
188        cpuStateRow,
189        this.trace
190      );
191      folderRowState!.addChildTraceRow(cpuStateRow);
192    }
193  }
194
195  addFreqLimitRows(
196    cpuFreqLimits: Array<CpuFreqRowLimit>,
197    cpuFreqLimitsMax: Array<{ maxValue: number; filterId: number }>,
198    folderRowLimit: TraceRow<BaseStruct>,
199    traceId?: string
200  ): void {
201    for (let limit of cpuFreqLimits) {
202      let findMax = Utils.getFrequencyWithUnit(
203        cpuFreqLimitsMax.find((maxLimit) => maxLimit.filterId === limit.maxFilterId)?.maxValue || 0
204      );
205      let cpuFreqLimitRow = TraceRow.skeleton<CpuFreqLimitsStruct>(traceId);
206      cpuFreqLimitRow.rowId = `${limit.cpu}`;
207      cpuFreqLimitRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ_LIMIT;
208      cpuFreqLimitRow.rowParentId = '';
209      cpuFreqLimitRow.style.height = '40px';
210      cpuFreqLimitRow.name = `Cpu ${limit.cpu} Freq Limit`;
211      cpuFreqLimitRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
212      cpuFreqLimitRow.selectChangeHandler = this.trace.selectChangeHandler;
213      cpuFreqLimitRow.setAttribute('maxFilterId', `${limit.maxFilterId}`);
214      cpuFreqLimitRow.setAttribute('minFilterId', `${limit.minFilterId}`);
215      cpuFreqLimitRow.setAttribute('cpu', `${limit.cpu}`);
216      cpuFreqLimitRow.supplierFrame = async (): Promise<CpuFreqLimitsStruct[]> => {
217        const res =
218          await cpuFreqLimitSender(limit.maxFilterId, limit.minFilterId, limit.cpu, cpuFreqLimitRow);
219        res.forEach((item) => (item.cpu = limit.cpu));
220        return res;
221      };
222      cpuFreqLimitRow.focusHandler = (ev): void => {
223        this.trace.displayTip(
224          cpuFreqLimitRow,
225          CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct,
226          `<span>Max Freq: ${ColorUtils.formatNumberComma(
227            CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.max || 0
228          )} kHz</span><span>Min Freq: ${ColorUtils.formatNumberComma(
229            CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.min || 0
230          )} kHz</span>`
231        );
232      };
233      cpuFreqLimitRow.findHoverStruct = (): void => {
234        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = cpuFreqLimitRow.getHoverStruct();
235      };
236      cpuFreqLimitRow.onThreadHandler = rowThreadHandler<CpuFreqLimitRender>(
237        'cpu-limit-freq',
238        'context',
239        {
240          type: `cpu-limit-freq-${limit.cpu}`,
241          cpu: limit.cpu,
242          maxFreq: findMax?.maxFreq || 0,
243          maxFreqName: findMax?.maxFreqName || '',
244        },
245        cpuFreqLimitRow,
246        this.trace
247      );
248      folderRowLimit!.addChildTraceRow(cpuFreqLimitRow);
249    }
250  }
251}
252
253export class CpuFreqRowLimit {
254  cpu: number = 0;
255  maxFilterId: number = 0;
256  minFilterId: number = 0;
257}
258