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.
82 lines
2.9 KiB
82 lines
2.9 KiB
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 };
|
|
}
|
|
}
|
|
|