* Copyright (C) 2026 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 { TraceRow } from '../trace/base/TraceRow';
import { ioSender } from '../../database/data-trafic/IOSender';
import { IORender, IOStruct } from '../../database/ui-worker/ProcedureWorkerIO';
import { ColorUtils } from '../trace/base/ColorUtils';
import { queryAllIOProcess } from '../../database/sql/IO.sql';
import { renders } from '../../database/ui-worker/ProcedureWorker';
import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
import { BaseStruct } from 'src/trace/database/ui-worker/ProcedureWorkerCommon';
* System IO Chart:
*/
const SYSTEM_IO_LANE_HEIGHT = '48px';
export class SpSystemIOChart {
private trace: SpSystemTrace;
constructor(trace: SpSystemTrace) {
this.trace = trace;
}
async init(): Promise<void> {
const processes = await queryAllIOProcess();
if (!processes || processes.length === 0) {
return;
}
await this.initFolderAndLanes();
}
private async initFolderAndLanes(): Promise<void> {
const folder = TraceRow.skeleton<BaseStruct>();
folder.rowId = 'SystemIO';
folder.index = 0;
folder.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM_GROUP;
folder.rowParentId = '';
folder.rowHidden = false;
folder.style.height = '40px';
folder.folder = true;
folder.name = 'System IO';
folder.addTemplateTypes('HiEBpf');
folder.favoriteChangeHandler = this.trace.favoriteChangeHandler;
folder.selectChangeHandler = this.trace.selectChangeHandler;
folder.supplierFrame = (): Promise<Array<BaseStruct>> => new Promise<Array<BaseStruct>>((resolve) => resolve([]));
folder.onThreadHandler = (useCache): void => {
folder.canvasSave(this.trace.canvasPanelCtx!);
if (folder.expansion) {
this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height);
} else {
(renders.empty as EmptyRender).renderMainThread(
{
context: this.trace.canvasPanelCtx,
useCache: useCache,
type: '',
},
folder
);
}
folder.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
};
this.trace.rowsEL?.appendChild(folder);
this.initLane(folder, 0, 'Logical Read', `io-system-logical-read`, ColorUtils.MD_PALETTE[0], 1);
this.initLane(folder, 1, 'Logical Write', `io-system-logical-write`, ColorUtils.MD_PALETTE[8], 2);
this.initLane(folder, 2, 'Physical Read', `io-system-physical-read`, ColorUtils.MD_PALETTE[2], 3);
this.initLane(folder, 3, 'Physical Write', `io-system-physical-write`, ColorUtils.MD_PALETTE[10], 4);
}
private initLane(
folder: TraceRow<BaseStruct>,
type: number,
name: string,
rowId: string,
chartColor: string,
index: number
): void {
const row = TraceRow.skeleton<IOStruct>();
row.rowId = rowId;
row.index = index;
row.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM_IO;
row.rowParentId = folder.rowId;
row.rowHidden = !folder.expansion;
row.style.height = SYSTEM_IO_LANE_HEIGHT;
row.setAttribute('children', '');
row.name = name;
row.supplierFrame = async (): Promise<IOStruct[]> => {
return ioSender(type, TraceRow.range?.scale || 50, row, -1);
};
row.favoriteChangeHandler = this.trace.favoriteChangeHandler;
row.selectChangeHandler = this.trace.selectChangeHandler;
row.focusHandler = (): void => this.focusIOHandler(row);
row.findHoverStruct = (): void => {
IOStruct.hoverIOStruct = row.getHoverStruct(false) || null;
};
row.onThreadHandler = (useCache): void => {
let context: CanvasRenderingContext2D;
if (row.currentContext) {
context = row.currentContext;
} else {
context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
}
row.canvasSave(context);
(renders['io'] as IORender).renderMainThread(
{
context: context,
useCache: useCache,
type: `io-system-${name}`,
chartColor: chartColor,
},
row
);
row.canvasRestore(context, this.trace);
};
folder.addChildTraceRow(row);
}
private focusIOHandler(row: TraceRow<IOStruct>): void {
let num = 0;
let tip = '';
if (IOStruct.hoverIOStruct) {
num = IOStruct.hoverIOStruct.size ?? 0;
const group10Ms = IOStruct.hoverIOStruct.group10Ms ?? false;
if (num > 0) {
tip = `<span>${num}${group10Ms ? ' (10.00ms)' : ''}</span>`;
}
}
this.trace?.displayTip(row, IOStruct.hoverIOStruct, tip);
}
}