frame time, draw call, buffer upload 측정하기
GPU를 쓰면 자동으로 빠를 것 같지만, editor에서는 입력 지연과 buffer upload가 더 큰 문제가 되기도 합니다.
renderer stats를 누적하는 코드
프레임마다 새 stats를 만들고 renderer의 주요 작업 지점에서 숫자를 올립니다.
function beginFrameStats() {
return {
start: performance.now(),
frameMs: 0,
drawCalls: 0,
bufferUploadBytes: 0,
textureUploads: 0,
worstFrameMs: 0
};
}
function endFrameStats(stats, previousWorst = 0) {
stats.frameMs = performance.now() - stats.start;
stats.worstFrameMs = Math.max(previousWorst, stats.frameMs);
return stats;
}
function uploadBuffer(gl, target, data, usage, stats) {
gl.bufferData(target, data, usage);
stats.bufferUploadBytes += data.byteLength;
}
function drawArrays(gl, mode, first, count, stats) {
gl.drawArrays(mode, first, count);
stats.drawCalls += 1;
}
FPS보다 먼저 볼 것
frame time
worst frame
input latency while dragging
draw calls
buffer upload bytes
평균 FPS가 괜찮아도 drag 중 한두 프레임이 튀면 사용자는 느리다고 느낍니다.
rolling window로 튀는 프레임을 잡는다
function createFrameMeter(size = 120) {
const samples = [];
return {
push(frameMs) {
samples.push(frameMs);
if (samples.length > size) samples.shift();
},
snapshot() {
const sorted = [...samples].sort((a, b) => a - b);
const avg = samples.reduce((sum, value) => sum + value, 0) / samples.length;
return {
avgMs: avg,
p95Ms: sorted[Math.floor(sorted.length * 0.95)] ?? 0,
maxMs: sorted[sorted.length - 1] ?? 0
};
}
};
}
editor에서는 평균보다 p95, max가 중요합니다. drag, zoom, text editing 중 한 프레임이 튀는 순간 사용자가 바로 느끼기 때문입니다.
오늘의 핵심
성능은 느낌으로 판단하지 않습니다. editor debug panel에 작은 숫자를 계속 노출해두는 것이 좋습니다.