You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AdLike2048/assets/script/game/PerfSampler.ts

83 lines
2.9 KiB

3 weeks ago
import { Director, director, game } from 'cc';
import { ThermalProfile } from './ThermalProfile';
import { PerfReport } from './PerfReport';
/** 战斗内 FPS 滑动窗口(帧数,约 1s@60) */
const WINDOW_FRAMES = 60;
/**
* 战斗 FPS 采样:窗口上报 PF-BTL-FPS,离局汇总 PF-BTL-SESS(含目标帧率 gap)。
*/
export class PerfSampler {
private static _active = false;
private static _targetFps = 60;
private static _windowBuf: number[] = [];
private static _windowLeft = 0;
private static _sessionBuf: number[] = [];
/** 地图可交互后开始采样 */
static beginBattle(): void {
if (PerfSampler._active) return;
ThermalProfile.resolve();
PerfSampler._targetFps = ThermalProfile.current.battleFrameRate;
PerfReport.reportBattleRuntimeConfig();
PerfSampler._active = true;
PerfSampler._windowBuf = [];
PerfSampler._sessionBuf = [];
PerfSampler._windowLeft = WINDOW_FRAMES;
director.on(Director.EVENT_AFTER_UPDATE, PerfSampler._onFrame, PerfSampler);
}
/** 战斗 UI teardown:汇总并上报 */
static endBattle(): void {
if (!PerfSampler._active) return;
director.off(Director.EVENT_AFTER_UPDATE, PerfSampler._onFrame, PerfSampler);
PerfSampler._active = false;
PerfSampler._flushWindow(true);
PerfSampler._flushSession();
PerfReport.resetBattlePerfSession();
}
private static _onFrame(): void {
const dt = game.deltaTime || 0;
if (dt <= 0) return;
const fps = 1 / dt;
PerfSampler._windowBuf.push(fps);
PerfSampler._sessionBuf.push(fps);
PerfSampler._windowLeft--;
if (PerfSampler._windowLeft <= 0) {
PerfSampler._flushWindow(false);
PerfSampler._windowLeft = WINDOW_FRAMES;
PerfSampler._windowBuf = [];
}
}
private static _flushWindow(force: boolean): void {
if (PerfSampler._windowBuf.length === 0) return;
if (!force && PerfSampler._windowBuf.length < WINDOW_FRAMES / 2) return;
const stats = PerfSampler._stats(PerfSampler._windowBuf);
PerfReport.reportBattleFps(stats.avg, stats.p10, PerfSampler._targetFps);
}
private static _flushSession(): void {
if (PerfSampler._sessionBuf.length === 0) return;
const stats = PerfSampler._stats(PerfSampler._sessionBuf);
PerfReport.reportBattleSessionFps(
stats.avg,
stats.p10,
PerfSampler._targetFps,
PerfSampler._sessionBuf.length,
);
PerfSampler._sessionBuf = [];
}
private static _stats(buf: number[]): { avg: number; p10: number } {
const sorted = [...buf].sort((a, b) => a - b);
const sum = sorted.reduce((a, b) => a + b, 0);
const avg = sum / sorted.length;
const p10Idx = Math.floor(sorted.length * 0.1);
const p10 = sorted[p10Idx] ?? avg;
return { avg, p10 };
}
}