* Copyright (C) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SpSystemTrace } from '../SpSystemTrace';
import { info } from '../../../log/Log';
import { TraceRow } from '../trace/base/TraceRow';
import { ColorUtils } from '../trace/base/ColorUtils';
import { CpuFreqLimitRender, CpuFreqLimitsStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCpuFreqLimits';
import { CpuFreqStruct, FreqRender } from '../../database/ui-worker/ProcedureWorkerFreq';
import { CpuStateRender, CpuStateStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCpuState';
import { folderSupplier, folderThreadHandler, rowThreadHandler } from './SpChartManager';
import { Utils } from '../trace/base/Utils';
import { cpuFreqDataSender } from '../../database/data-trafic/cpu/CpuFreqDataSender';
import { cpuStateSender } from '../../database/data-trafic/cpu/CpuStateSender';
import { cpuFreqLimitSender } from '../../database/data-trafic/cpu/CpuFreqLimitDataSender';
import {
getCpuLimitFreqId,
getCpuLimitFreqMax,
queryCpuFreq,
queryCpuMaxFreq,
queryCpuStateFilter,
} from '../../database/sql/Cpu.sql';
import { BaseStruct } from '../../bean/BaseStruct';
export class SpFreqChart {
private readonly trace: SpSystemTrace;
constructor(trace: SpSystemTrace) {
this.trace = trace;
}
async init(parentRow?: TraceRow<BaseStruct>, traceId?: string): Promise<void> {
let freqList = await queryCpuFreq(traceId);
let cpuStateFilterIds = await queryCpuStateFilter(traceId);
this.trace.stateRowsId = cpuStateFilterIds;
let cpuFreqLimits = await getCpuLimitFreqId(traceId);
let cpuFreqLimitsMax = await getCpuLimitFreqMax(cpuFreqLimits.map((limit) => limit.maxFilterId).join(','), traceId);
if (freqList.length > 0) {
let folderRow = this.createFolderRow(traceId);
folderRow.rowId = 'Cpu Frequency';
folderRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ_ALL;
folderRow.name = 'Cpu Frequency';
folderRow.selectChangeHandler = this.trace.selectChangeHandler;
this.trace.rowsEL?.appendChild(folderRow);
info('Cpu Freq data size is: ', freqList!.length);
await this.addFreqRows(freqList, folderRow, traceId);
if (parentRow) {
parentRow.addChildTraceRow(folderRow);
} else {
this.trace.rowsEL?.appendChild(folderRow);
}
}
if (cpuStateFilterIds.length > 0) {
let folderRowState = this.createFolderRow();
folderRowState.rowId = 'Cpu State';
folderRowState.rowType = TraceRow.ROW_TYPE_CPU_STATE_ALL;
folderRowState.name = 'Cpu State';
folderRowState.selectChangeHandler = this.trace.selectChangeHandler;
this.trace.rowsEL?.appendChild(folderRowState);
this.addStateRows(cpuStateFilterIds, folderRowState, traceId);
if (parentRow) {
parentRow.addChildTraceRow(folderRowState);
} else {
this.trace.rowsEL?.appendChild(folderRowState);
}
}
if (cpuFreqLimits.length > 0) {
let folderRowLimit = this.createFolderRow();
folderRowLimit.rowId = 'Cpu Freq Limit';
folderRowLimit.rowType = TraceRow.ROW_TYPE_CPU_FREQ_LIMITALL;
folderRowLimit.name = 'Cpu Freq Limit';
folderRowLimit.selectChangeHandler = this.trace.selectChangeHandler;
this.trace.rowsEL?.appendChild(folderRowLimit);
this.addFreqLimitRows(cpuFreqLimits, cpuFreqLimitsMax, folderRowLimit, traceId);
if (parentRow) {
parentRow.addChildTraceRow(folderRowLimit);
} else {
this.trace.rowsEL?.appendChild(folderRowLimit);
}
}
}
createFolderRow(traceId?: string): TraceRow<BaseStruct> {
let folder = TraceRow.skeleton<BaseStruct>(traceId);
folder.rowParentId = '';
folder.folder = true;
folder.style.height = '40px';
folder.rowHidden = folder.expansion;
folder.setAttribute('children', '');
folder.supplier = folderSupplier();
folder.onThreadHandler = folderThreadHandler(folder, this.trace);
return folder;
}
async addFreqRows(
freqList: Array<{ cpu: number; filterId: number }>,
folderRow: TraceRow<BaseStruct>,
traceId?: string
): Promise<void> {
let freqMaxList = await queryCpuMaxFreq(traceId);
CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq;
let maxFreqObj = Utils.getFrequencyWithUnit(freqMaxList[0].maxFreq);
CpuFreqStruct.maxFreq = maxFreqObj.maxFreq;
CpuFreqStruct.maxFreqName = maxFreqObj.maxFreqName;
for (let i = 0; i < freqList.length; i++) {
const it = freqList[i];
let traceRow = TraceRow.skeleton<CpuFreqStruct>(traceId);
traceRow.rowId = `${it.filterId}`;
traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ;
traceRow.rowParentId = '';
traceRow.style.height = '40px';
traceRow.name = `Cpu ${it.cpu} Frequency`;
traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
traceRow.selectChangeHandler = this.trace.selectChangeHandler;
traceRow.supplierFrame = (): Promise<CpuFreqStruct[]> => cpuFreqDataSender(it.cpu, traceRow);
traceRow.focusHandler = (): void => {
this.trace?.displayTip(
traceRow,
CpuFreqStruct.hoverCpuFreqStruct,
`<span>${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct?.value!)} kHz</span>`
);
};
traceRow.findHoverStruct = (): void => {
CpuFreqStruct.hoverCpuFreqStruct = traceRow.getHoverStruct(true, false, 'value');
};
traceRow.onThreadHandler = rowThreadHandler<FreqRender>(
'freq',
'context',
{
type: `freq${it.cpu}`,
},
traceRow,
this.trace
);
folderRow!.addChildTraceRow(traceRow);
}
}
addStateRows(
cpuStateFilterIds: Array<{ cpu: number; filterId: number }>,
folderRowState: TraceRow<BaseStruct>,
traceId?: string
): void {
for (let it of cpuStateFilterIds) {
let cpuStateRow = TraceRow.skeleton<CpuStateStruct>(traceId);
cpuStateRow.rowId = `${it.filterId}`;
cpuStateRow.rowType = TraceRow.ROW_TYPE_CPU_STATE;
cpuStateRow.rowParentId = '';
cpuStateRow.style.height = '40px';
cpuStateRow.name = `Cpu ${it.cpu} State`;
cpuStateRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
cpuStateRow.selectChangeHandler = this.trace.selectChangeHandler;
cpuStateRow.supplierFrame = async (): Promise<CpuStateStruct[]> => {
let rs = await cpuStateSender(it.filterId, cpuStateRow);
rs.forEach((t) => (t.cpu = it.cpu));
return rs;
};
cpuStateRow.focusHandler = (): void => {
this.trace.displayTip(
cpuStateRow,
CpuStateStruct.hoverStateStruct,
`<span>State: ${CpuStateStruct.hoverStateStruct?.value}</span>`
);
};
cpuStateRow.findHoverStruct = (): void => {
CpuStateStruct.hoverStateStruct = cpuStateRow.getHoverStruct();
};
cpuStateRow.onThreadHandler = rowThreadHandler<CpuStateRender>(
'cpu-state',
'cpuStateContext',
{
type: `cpu-state-${it.cpu}`,
cpu: it.cpu,
},
cpuStateRow,
this.trace
);
folderRowState!.addChildTraceRow(cpuStateRow);
}
}
addFreqLimitRows(
cpuFreqLimits: Array<CpuFreqRowLimit>,
cpuFreqLimitsMax: Array<{ maxValue: number; filterId: number }>,
folderRowLimit: TraceRow<BaseStruct>,
traceId?: string
): void {
for (let limit of cpuFreqLimits) {
let findMax = Utils.getFrequencyWithUnit(
cpuFreqLimitsMax.find((maxLimit) => maxLimit.filterId === limit.maxFilterId)?.maxValue || 0
);
let cpuFreqLimitRow = TraceRow.skeleton<CpuFreqLimitsStruct>(traceId);
cpuFreqLimitRow.rowId = `${limit.cpu}`;
cpuFreqLimitRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ_LIMIT;
cpuFreqLimitRow.rowParentId = '';
cpuFreqLimitRow.style.height = '40px';
cpuFreqLimitRow.name = `Cpu ${limit.cpu} Freq Limit`;
cpuFreqLimitRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
cpuFreqLimitRow.selectChangeHandler = this.trace.selectChangeHandler;
cpuFreqLimitRow.setAttribute('maxFilterId', `${limit.maxFilterId}`);
cpuFreqLimitRow.setAttribute('minFilterId', `${limit.minFilterId}`);
cpuFreqLimitRow.setAttribute('cpu', `${limit.cpu}`);
cpuFreqLimitRow.supplierFrame = async (): Promise<CpuFreqLimitsStruct[]> => {
const res =
await cpuFreqLimitSender(limit.maxFilterId, limit.minFilterId, limit.cpu, cpuFreqLimitRow);
res.forEach((item) => (item.cpu = limit.cpu));
return res;
};
cpuFreqLimitRow.focusHandler = (ev): void => {
this.trace.displayTip(
cpuFreqLimitRow,
CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct,
`<span>Max Freq: ${ColorUtils.formatNumberComma(
CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.max || 0
)} kHz</span><span>Min Freq: ${ColorUtils.formatNumberComma(
CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.min || 0
)} kHz</span>`
);
};
cpuFreqLimitRow.findHoverStruct = (): void => {
CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = cpuFreqLimitRow.getHoverStruct();
};
cpuFreqLimitRow.onThreadHandler = rowThreadHandler<CpuFreqLimitRender>(
'cpu-limit-freq',
'context',
{
type: `cpu-limit-freq-${limit.cpu}`,
cpu: limit.cpu,
maxFreq: findMax?.maxFreq || 0,
maxFreqName: findMax?.maxFreqName || '',
},
cpuFreqLimitRow,
this.trace
);
folderRowLimit!.addChildTraceRow(cpuFreqLimitRow);
}
}
}
export class CpuFreqRowLimit {
cpu: number = 0;
maxFilterId: number = 0;
minFilterId: number = 0;
}