"매 GPU 작업은 비동기 — gl.finish() 의 X, query object 의 O". WebGL 의 draw call 은 GPU command buffer 에 enqueue 만 되므로 CPU 측 performance.now() 만으로 측정 시 실제 GPU 시간과 ms 단위 misalignment 발생. EXT_disjoint_timer_query_webgl2 가 매 정답.
gpu.requestAdapter() (WebGPU) — 매 native timestamp-query feature.
Chrome DevTools Performance → GPU track.
Spector.js — frame capture + per-call cost.
매 응용
60→120Hz upgrade 시 frame budget shrink (16.6→8.3ms) 의 bottleneck localization.
Mobile WebGL 의 thermal throttling 감지 (GPU time 의 점진적 increase).
PWA 게임 의 input→render latency end-to-end 측정.
💻 패턴
Timer Query — frame GPU time 측정
constext=gl.getExtension('EXT_disjoint_timer_query_webgl2');constqueries=[];functionframe(){constq=gl.createQuery();gl.beginQuery(ext.TIME_ELAPSED_EXT,q);drawScene();gl.endQuery(ext.TIME_ELAPSED_EXT);queries.push({q,frameId:frameCount++});// resolve 매 several frame later (async)
for(leti=queries.length-1;i>=0;i--){const{q,frameId}=queries[i];constavailable=gl.getQueryParameter(q,gl.QUERY_RESULT_AVAILABLE);constdisjoint=gl.getParameter(ext.GPU_DISJOINT_EXT);if(available&&!disjoint){constns=gl.getQueryParameter(q,gl.QUERY_RESULT);console.log(`frame ${frameId} GPU: ${(ns/1e6).toFixed(2)} ms`);gl.deleteQuery(q);queries.splice(i,1);}}requestAnimationFrame(frame);}
Anti — gl.finish() blocking
// X — pipeline stall, 매 production 에서 절대 사용 X
constt0=performance.now();drawScene();gl.finish();// CPU↔GPU sync barrier
constt1=performance.now();// t1-t0 는 측정 대상이 아닌 stall 의 cost
Input→render latency (RAIL model)
letinputTs=0;canvas.addEventListener('pointerdown',e=>{inputTs=e.timeStamp;// 매 hardware timestamp
});functionframe(now){if(inputTs>0&&pendingInputProcessed){constlatency=now-inputTs;if(latency>100)console.warn(`input→render: ${latency}ms`);inputTs=0;}drawScene();requestAnimationFrame(frame);}
Disjoint detection (thermal throttling)
functioncheckThermal(){constdisjoint=gl.getParameter(ext.GPU_DISJOINT_EXT);if(disjoint){// 매 GPU 가 context switch / power state 변경 — measurement invalid
metricsBuffer.flush('thermal_event');}}