* 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 { SpHiPerf } from './SpHiPerf';
import { SpCpuChart } from './SpCpuChart';
import { SpFreqChart } from './SpFreqChart';
import { SpFpsChart } from './SpFpsChart';
import { info } from '../../../log/Log';
import { SpNativeMemoryChart } from './SpNativeMemoryChart';
import { SpAbilityMonitorChart } from './SpAbilityMonitorChart';
import { SpProcessChart } from './SpProcessChart';
import { perfDataQuery } from './PerfDataQuery';
import { SpVirtualMemChart } from './SpVirtualMemChart';
import { SpEBPFChart } from './SpEBPFChart';
import { SpSystemIOChart } from './SpSystemIOChart';
import { SpSdkChart } from './SpSdkChart';
import { SpHiSysEnergyChart } from './SpHiSysEnergyChart';
import { VmTrackerChart } from './SpVmTrackerChart';
import { SpClockChart } from './SpClockChart';
import { SpXpowerChart } from './SpXpowerChart';
import { SpIrqChart } from './SpIrqChart';
import { renders } from '../../database/ui-worker/ProcedureWorker';
import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
import { TraceRow } from '../trace/base/TraceRow';
import { SpFrameTimeChart } from './SpFrameTimeChart';
import { Utils } from '../trace/base/Utils';
import { SpArkTsChart } from './SpArkTsChart';
import { MemoryConfig } from '../../bean/MemoryConfig';
import { FlagsConfig } from '../SpFlags';
import { SpLogChart } from './SpLogChart';
import { SpHiSysEventChart } from './SpHiSysEventChart';
import { SpAllAppStartupsChart } from './SpAllAppStartups';
import { procedurePool } from '../../database/Procedure';
import { SpSegmentationChart } from './SpSegmentationChart';
import { SpHangChart } from './SpHangChart';
import { SpPerfOutputDataChart } from './SpPerfOutputDataChart';
import {
queryAppStartupProcessIds,
queryDataDICT,
queryThreadAndProcessName,
} from '../../database/sql/ProcessThread.sql';
import { queryTaskPoolCallStack, queryTotalTime } from '../../database/sql/SqlLite.sql';
import { queryMemoryConfig } from '../../database/sql/Memory.sql';
import { SpLtpoChart } from './SpLTPO';
import { SpBpftraceChart } from './SpBpftraceChart';
import { sliceSender } from '../../database/data-trafic/SliceSender';
import { BaseStruct } from '../../bean/BaseStruct';
import { SpGpuCounterChart } from './SpGpuCounterChart';
import { SpUserFileChart } from './SpUserPluginChart';
import { SpImportUserPluginsChart } from './SpImportUserPluginsChart';
import { queryDmaFenceIdAndCat } from '../../database/sql/dmaFence.sql';
import { queryAllFuncNames } from '../../database/sql/Func.sql';
import { SpSnapShotChart } from './spSnapShotChart';
import { SpRecordTrace } from '../SpRecordTrace';
import { SpNetworkChart } from './SpNetworkChart';
import { ProcessNetworkDetailChart } from './ProcessNetworkDetailChart';
import { GlobalNetworkSummaryChart } from './GlobalNetworkSummaryChart';
export class SpChartManager {
static APP_STARTUP_PID_ARR: Array<number> = [];
private trace: SpSystemTrace;
public perf: SpHiPerf;
private cpu: SpCpuChart;
private freq: SpFreqChart;
private virtualMemChart: SpVirtualMemChart;
private fps: SpFpsChart;
private nativeMemory: SpNativeMemoryChart;
private abilityMonitor: SpAbilityMonitorChart;
private process: SpProcessChart;
private process2?: SpProcessChart;
private fileSystem: SpEBPFChart;
private systemIOChart: SpSystemIOChart;
private sdkChart: SpSdkChart;
private hiSyseventChart: SpHiSysEnergyChart;
private smapsChart: VmTrackerChart;
private clockChart: SpClockChart;
private xpowerChart: SpXpowerChart;
private irqChart: SpIrqChart;
private spAllAppStartupsChart!: SpAllAppStartupsChart;
private SpLtpoChart!: SpLtpoChart;
frameTimeChart: SpFrameTimeChart;
public arkTsChart: SpArkTsChart;
private logChart: SpLogChart;
private spHiSysEvent: SpHiSysEventChart;
private spSegmentationChart: SpSegmentationChart;
private hangChart: SpHangChart;
private spBpftraceChart: SpBpftraceChart;
private spPerfOutputDataChart: SpPerfOutputDataChart;
private spGpuCounterChart: SpGpuCounterChart;
private spUserFileChart: SpUserFileChart;
private spImportUserPluginsChart: SpImportUserPluginsChart;
private spSnapShotChart: SpSnapShotChart;
private spNetworkChart: SpNetworkChart;
private processNetworkDetailChart: ProcessNetworkDetailChart;
private globalNetworkSummaryChart: GlobalNetworkSummaryChart;
constructor(trace: SpSystemTrace) {
this.trace = trace;
this.perf = new SpHiPerf(trace);
this.fileSystem = new SpEBPFChart(trace);
this.systemIOChart = new SpSystemIOChart(trace);
this.cpu = new SpCpuChart(trace);
this.freq = new SpFreqChart(trace);
this.virtualMemChart = new SpVirtualMemChart(trace);
this.fps = new SpFpsChart(trace);
this.nativeMemory = new SpNativeMemoryChart(trace);
this.abilityMonitor = new SpAbilityMonitorChart(trace);
this.process = new SpProcessChart(trace);
this.sdkChart = new SpSdkChart(trace);
this.hiSyseventChart = new SpHiSysEnergyChart(trace);
this.smapsChart = new VmTrackerChart(trace);
this.clockChart = new SpClockChart(trace);
this.irqChart = new SpIrqChart(trace);
this.frameTimeChart = new SpFrameTimeChart(trace);
this.arkTsChart = new SpArkTsChart(trace);
this.logChart = new SpLogChart(trace);
this.spHiSysEvent = new SpHiSysEventChart(trace);
this.spAllAppStartupsChart = new SpAllAppStartupsChart(trace);
this.SpLtpoChart = new SpLtpoChart(trace);
this.spSegmentationChart = new SpSegmentationChart(trace);
this.hangChart = new SpHangChart(trace);
this.spBpftraceChart = new SpBpftraceChart(trace);
this.spPerfOutputDataChart = new SpPerfOutputDataChart(trace);
this.spGpuCounterChart = new SpGpuCounterChart(trace);
this.spUserFileChart = new SpUserFileChart(trace);
this.spImportUserPluginsChart = new SpImportUserPluginsChart(trace);
this.xpowerChart = new SpXpowerChart(trace);
this.spSnapShotChart = new SpSnapShotChart(trace);
this.processNetworkDetailChart = new ProcessNetworkDetailChart(trace);
this.globalNetworkSummaryChart = new GlobalNetworkSummaryChart(trace);
this.spNetworkChart = new SpNetworkChart(trace);
}
async initPreprocessData(progress: Function): Promise<void> {
progress('load data dict', 50);
this.process2 = undefined;
SpSystemTrace.DATA_DICT.clear();
SpChartManager.APP_STARTUP_PID_ARR = [];
let dict = await queryDataDICT();
if (FlagsConfig.getFlagsConfigEnableStatus('AppStartup')) {
let appStartUpPids = await queryAppStartupProcessIds();
appStartUpPids.forEach((it) => SpChartManager.APP_STARTUP_PID_ARR.push(it.pid));
}
await this.initTraceConfig();
dict.map((d) => SpSystemTrace.DATA_DICT.set(d.id, d.data));
await this.cacheDataDictToWorker();
SpSystemTrace.DATA_TASK_POOL_CALLSTACK.clear();
let taskPoolCallStack = await queryTaskPoolCallStack();
taskPoolCallStack.map((d) => SpSystemTrace.DATA_TASK_POOL_CALLSTACK.set(d.id, d));
progress('time range', 65);
await this.initTotalTime();
let ptArr = await queryThreadAndProcessName();
this.handleProcessThread(ptArr);
info('initData timerShaftEL Data initialized');
let funArr = await queryAllFuncNames();
this.handleFuncName(funArr);
}
async initCpu(progress: Function): Promise<void> {
progress('cpu', 70);
let result = await sliceSender();
SpProcessChart.threadStateList = result.threadMap;
SpProcessChart.processRowSortMap = result.processRowSortMap;
await this.cpu.init(result.count.cpu);
info('initData cpu Data initialized');
if (FlagsConfig.getFlagsConfigEnableStatus('Bpftrace')) {
await this.spBpftraceChart.init(null);
}
if (FlagsConfig.getFlagsConfigEnableStatus('UserPluginsRow')) {
await this.spUserFileChart.init(null)
}
if (FlagsConfig.getFlagsConfigEnableStatus('GpuCounter')) {
await this.spGpuCounterChart.init([]);
}
if (FlagsConfig.getFlagsConfigEnableStatus('SchedulingAnalysis')) {
await this.cpu.initCpuIdle0Data(progress);
await this.cpu.initSchedulingPTData(progress);
await this.cpu.initSchedulingFreqData(progress);
}
info('initData ProcessThreadState Data initialized');
progress('cpu rate', 75);
await this.initCpuRate(result.cpuUtiliRateArray);
info('initData Cpu Rate Data initialized');
progress('cpu freq', 80);
await this.freq.init();
info('initData Cpu Freq Data initialized');
}
async init(progress: Function): Promise<void> {
info('initData data parse end ');
await this.initPreprocessData(progress);
await this.initCpu(progress);
await this.logChart.init();
await this.spHiSysEvent.init();
if (SpRecordTrace.snapShotList.length > 0 && SpRecordTrace.isSnapShotCapture) {
await this.spSnapShotChart.init();
}
let idAndNameArr = await queryDmaFenceIdAndCat();
this.handleDmaFenceName(idAndNameArr as { id: number; cat: string; seqno: number; driver: string; context: string }[]);
if (FlagsConfig.getFlagsConfigEnableStatus('Hangs Detection')) {
progress('Hang init', 80);
await this.hangChart.init();
}
progress('Clock init', 82);
await this.clockChart.init();
progress('Xpower init', 83);
await this.xpowerChart.init();
progress('Irq init', 84);
await this.irqChart.init();
progress('Network init', 84.2);
await this.spNetworkChart.init();
progress('SpSegmentationChart inin', 84.5);
await this.spSegmentationChart.init();
await this.virtualMemChart.init();
progress('fps', 85);
await this.fps.init();
progress('native memory', 87);
await this.nativeMemory.initChart();
progress('ability monitor', 88);
await this.abilityMonitor.init();
progress('hiSysevent', 88.2);
await this.hiSyseventChart.init();
progress('vm tracker', 88.4);
await this.smapsChart.init();
progress('sdk', 88.6);
await this.sdkChart.init();
progress('perf', 88.8);
await this.perf!.init();
await perfDataQuery.initPerfCache();
progress('file system', 89);
await this.fileSystem!.init();
progress('system io', 89.2);
await this.systemIOChart.init();
progress('ark ts', 90);
await this.arkTsChart.initFolder();
await this.spAllAppStartupsChart.init();
await this.SpLtpoChart.init();
await this.frameTimeChart.init();
await this.spPerfOutputDataChart.init();
progress('process', 92);
this.process.clearCache();
this.process2?.clearCache();
this.process2 = undefined;
await this.process.initAsyncFuncData({
startTs: Utils.getInstance().getRecordStartNS(),
endTs: Utils.getInstance().getRecordEndNS(),
});
await this.process.initDeliverInputEvent();
await this.process.initTouchEventDispatch();
await this.process.init(false);
progress('display', 95);
}
async initDistributedChart(progress: Function, file1: string, file2: string): Promise<void> {
let funArr1 = await queryAllFuncNames('1');
let funArr2 = await queryAllFuncNames('2');
this.handleFuncName(funArr1, '1');
this.handleFuncName(funArr2, '2');
progress('load data dict', 50);
SpSystemTrace.DATA_DICT.clear();
SpChartManager.APP_STARTUP_PID_ARR = [];
SpSystemTrace.DATA_TASK_POOL_CALLSTACK.clear();
this.process.clearCache();
this.process2?.clearCache();
let trace1Folder = this.createFolderRow('trace-1', 'trace-1', file1);
let trace2Folder = this.createFolderRow('trace-2', 'trace-2', file2);
this.trace.rowsEL!.appendChild(trace1Folder);
this.trace.rowsEL!.appendChild(trace2Folder);
await this.initTotalTime(true);
await this.initDistributedTraceRow('1', trace1Folder, progress);
info(`trace 1 load completed`);
await this.initDistributedTraceRow('2', trace2Folder, progress);
info(`trace 2 load completed`);
}
async initDistributedTraceRow(traceId: string, traceFolder: TraceRow<unknown>, progress: Function): Promise<void> {
let ptArr = await queryThreadAndProcessName(traceId);
this.handleProcessThread(ptArr, traceId);
info(`initData trace ${traceId} timerShaftEL Data initialized`);
progress(`trace ${traceId} cpu`, 70);
let count = await sliceSender(traceId);
await this.cpu.init(count.count.cpu, traceFolder, traceId);
info(`initData trace ${traceId} cpu Data initialized`);
progress(`trace ${traceId} cpu freq`, 75);
await this.freq.init(traceFolder, traceId);
info(`initData trace ${traceId} cpu freq Data initialized`);
progress(`trace ${traceId} clock`, 80);
await this.clockChart.init(traceFolder, traceId);
info(`initData trace ${traceId} clock Data initialized`);
progress(`trace ${traceId} Irq`, 85);
await this.irqChart.init(traceFolder, traceId);
info(`initData trace ${traceId} irq Data initialized`);
progress(`trace ${traceId} process`, 92);
if (traceId === '2') {
if (!this.process2) {
this.process2 = new SpProcessChart(this.trace);
}
await this.process2.initAsyncFuncData(
{
startTs: Utils.getInstance().getRecordStartNS('2'),
endTs: Utils.getInstance().getRecordEndNS('2'),
},
traceId
);
await this.process2.init(true, traceFolder, traceId);
} else {
await this.process.initAsyncFuncData(
{
startTs: Utils.getInstance().getRecordStartNS('1'),
endTs: Utils.getInstance().getRecordEndNS('1'),
},
traceId
);
await this.process.init(true, traceFolder, traceId);
}
}
async initSample(ev: File) {
await this.initSampleTime(ev, 'bpftrace');
await this.spBpftraceChart.init(ev);
}
async initGpuCounter(ev: File): Promise<void> {
const res = await this.initSampleTime(ev, 'gpucounter');
await this.spGpuCounterChart.init(res);
}
async importSoFileUpdate(): Promise<void> {
SpSystemTrace.DATA_DICT.clear();
let dict = await queryDataDICT();
dict.map((d) => SpSystemTrace.DATA_DICT.set(d.id, d.data));
await this.cacheDataDictToWorker();
await perfDataQuery.initPerfCache();
await this.nativeMemory.initMemoryFrame();
await this.fileSystem.initFileCallchain();
this.perf.resetAllChartData();
}
handleProcessThread(arr: { id: number; name: string; type: string }[], traceId?: string): void {
Utils.getInstance().getProcessMap(traceId).clear();
Utils.getInstance().getThreadMap(traceId).clear();
for (let pt of arr) {
if (pt.type === 'p') {
Utils.getInstance().getProcessMap(traceId).set(pt.id, pt.name);
} else {
Utils.getInstance().getThreadMap(traceId).set(pt.id, pt.name);
}
}
}
handleFuncName(funcNameArray: Array<unknown>, traceId?: string): void {
if (traceId) {
funcNameArray.forEach((it) => {
Utils.getInstance().getCallStatckMap().set(`${traceId}_${it.id!}`, it.name);
Utils.getInstance().getCallStatckMap().set(it.name, it.colorIndex);
});
} else {
funcNameArray.forEach((it) => {
Utils.getInstance().getCallStatckMap().set(it.id, it.name);
Utils.getInstance().getCallStatckMap().set(it.name, it.colorIndex);
});
}
}
initTotalTime = async (isDistributed: boolean = false): Promise<void> => {
let res1 = await queryTotalTime('1');
let total = res1[0].total;
Utils.getInstance().trace1RecordStartNS = res1[0].recordStartNS;
Utils.getInstance().trace1RecordEndNS = Math.max(res1[0].recordEndNS, res1[0].recordStartNS + 1);
if (isDistributed) {
let res2 = await queryTotalTime('2');
total = Math.max(total, res2[0].total);
Utils.getInstance().trace2RecordStartNS = res2[0].recordStartNS;
Utils.getInstance().trace2RecordEndNS = Math.max(res2[0].recordEndNS, res2[0].recordStartNS + 1);
}
if (this.trace.timerShaftEL) {
if (total === 0) {
total = 1;
}
Utils.getInstance().totalNS = total;
this.trace.timerShaftEL.totalNS = total;
this.trace.timerShaftEL.getRangeRuler()!.drawMark = true;
this.trace.timerShaftEL.setRangeNS(0, total);
window.recordStartNS = Utils.getInstance().trace1RecordStartNS;
window.recordEndNS = Utils.getInstance().trace1RecordEndNS;
window.totalNS = total;
this.trace.timerShaftEL.loadComplete = true;
}
};
initSampleTime = async (ev: File, type: string): Promise<unknown> => {
let res;
let endNS = 30_000_000_000;
if (type === 'gpucounter') {
res = await this.spGpuCounterChart.getCsvData(ev);
const endTime = Number(res[res.length - 1].split(',')[0]);
const minIndex = this.spGpuCounterChart.getMinData(res) + 1;
const startTime = Number(res[minIndex].split(',')[0]);
endNS = Number((endTime - startTime).toString().slice(0, 11));
}
if (this.trace.timerShaftEL) {
let total = endNS;
let startNS = 0;
this.trace.timerShaftEL.totalNS = total;
this.trace.timerShaftEL.getRangeRuler()!.drawMark = true;
this.trace.timerShaftEL.setRangeNS(0, total);
(window as unknown).recordStartNS = startNS;
(window as unknown).recordEndNS = endNS;
(window as unknown).totalNS = total;
this.trace.timerShaftEL.loadComplete = true;
}
return res;
};
initCpuRate = async (rates: Array<{ cpu: number; ro: number; rate: number; }>): Promise<void> => {
if (this.trace.timerShaftEL) {
this.trace.timerShaftEL.cpuUsage = rates;
}
info('Cpu UtilizationRate data size is: ', rates.length);
};
initTraceConfig = async (): Promise<void> => {
queryMemoryConfig().then((result) => {
if (result && result.length > 0) {
const config = result[0];
MemoryConfig.getInstance().updateConfig(config.pid, config.iPid, config.processName, config.interval);
}
});
};
async cacheDataDictToWorker(): Promise<void> {
return new Promise((resolve) => {
procedurePool.submitWithName(
'logic0',
'cache-data-dict',
{ dataDict: SpSystemTrace.DATA_DICT },
undefined,
(res: unknown): void => {
resolve();
}
);
});
}
createFolderRow(rowId: string, rowType: string, rowName: string, traceId?: string): TraceRow<unknown> {
let row = TraceRow.skeleton<BaseStruct>(traceId);
row.setAttribute('disabled-check', '');
row.rowId = rowId;
row.rowType = rowType;
row.rowParentId = '';
row.folder = true;
row.style.height = '40px';
row.name = rowName;
row.supplier = folderSupplier();
row.onThreadHandler = folderThreadHandler(row, this.trace);
row.addEventListener('expansion-change', (evt) => {
if (!row.expansion) {
this.trace.clickEmptyArea();
}
});
return row;
}
handleDmaFenceName<T extends { id: number; cat: string; seqno: number; driver: string; context: string }>(arr: T[]): void {
Utils.DMAFENCECAT_MAP.clear();
for (let item of arr) {
Utils.DMAFENCECAT_MAP.set(item.id, item);
}
}
}
export const folderSupplier = (): () => Promise<BaseStruct[]> => {
return () => new Promise<Array<BaseStruct>>((resolve) => resolve([]));
};
export const folderThreadHandler = (row: TraceRow<BaseStruct>, trace: SpSystemTrace) => {
return (useCache: boolean): void => {
row.canvasSave(trace.canvasPanelCtx!);
if (row.expansion) {
trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
} else {
(renders.empty as EmptyRender).renderMainThread(
{
context: trace.canvasPanelCtx,
useCache: useCache,
type: '',
},
row
);
}
row.canvasRestore(trace.canvasPanelCtx!, trace);
};
};
export function rowThreadHandler<T>(
tag: string,
contextField: string,
arg: unknown,
row: TraceRow<unknown>,
trace: SpSystemTrace
) {
return (useCache: boolean): void => {
let context: CanvasRenderingContext2D = getRowContext(row, trace);
row.canvasSave(context);
arg.useCache = useCache;
if (contextField) {
arg[contextField] = context;
}
(renders[tag] as unknown).renderMainThread(arg, row);
row.canvasRestore(context, trace);
};
}
export const getRowContext = (row: TraceRow<unknown>, trace: SpSystemTrace): CanvasRenderingContext2D => {
if (row.currentContext) {
return row.currentContext;
} else {
return row.collect ? trace.canvasFavoritePanelCtx! : trace.canvasPanelCtx!;
}
};