[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,108 +1,183 @@
|
||||
---
|
||||
id: wiki-2026-0508-gpu-webgl-파이프라인의-미세-지연-micro-lat
|
||||
title: GPU WebGL 파이프라인의 미세 지연(Micro latency) 측정 사례
|
||||
title: GPU WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-035B08]
|
||||
aliases: [WebGL Micro-latency, GPU Pipeline Latency, WebGL Profiling]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
tags: [auto-reinforced]
|
||||
verification_status: applied
|
||||
tags: [webgl, gpu, performance, latency, profiling]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Continuous Worker - GPU_[[WebGL|WebGL]] 파이프라인의 미세 지연(Micro-latency) 측정 사례"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: javascript
|
||||
framework: webgl2
|
||||
---
|
||||
|
||||
# [[GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례|GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례]]
|
||||
# GPU WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> GPU/WebGL 파이프라인의 미세 지연(Micro-latency)은 CPU, GPU 및 브라우저 추상화 계층 간의 상호작용에서 발생하는 서브 프레임(Sub-frame) 수준의 시간 지연을 의미하며, 사용자 몰입도를 저하시키는 주요 원인입니다 [1]. 이를 정확히 측정하기 위해 WebGL/[[WebGPU|WebGPU]]의 타이머 API, 브라우저 내부의 성능 프로파일링 도구, 그리고 고속 카메라와 오실로스코프를 활용한 하드웨어 기반 측정 등 다양한 접근법이 활용되고 있습니다 [2-6]. 그러나 보안 취약점(Spectre, Meltdown 등)으로 인해 정밀한 시간 측정 기능이 브라우저 차원에서 양자화([[Quantization|Quantization]])되거나 제한되는 등 여러 측정 상의 제약이 따르고 있습니다 [3, 7].
|
||||
## 매 한 줄
|
||||
> **"매 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` 가 매 정답.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **API 수준의 그래픽 타이머 측정 (API-Level Timing)**
|
||||
* **WebGL 타이머 쿼리:** `EXT_disjoint_timer_query` 확장은 렌더링 파이프라인을 중단하지 않고 GPU 명령어 세트의 실행 시간을 측정할 수 있도록 고안되었습니다 [2, 8]. 그러나 이 고정밀 타이머가 Spectre 및 Meltdown과 같은 캐시 부채널 공격([[Side-channel Attack|Side-channel Attack]]s)에 악용될 수 있다는 보안 연구 결과에 따라, 대부분의 브라우저 벤더는 해당 확장을 비활성화하거나 해상도를 엄격하게 양자화(Quantization)하였습니다 [2, 3, 9-11].
|
||||
* **WebGPU 타임스탬프 쿼리:** WebGPU는 `timestamp-query` 기능을 통해 나노초 단위의 정밀한 측정을 지원하도록 설계되었습니다 [3, 12]. 하지만 역시 타이밍 공격을 방지하기 위해 사이트 격리(Site isolation) 여부에 따라 타임스탬프의 해상도가 100 마이크로초 수준으로 양자화되거나 비격리 컨텍스트에서는 아예 노출되지 않는 보안 조치가 적용됩니다 [3, 7, 13, 14]. 개발자는 로컬 환경에서 브라우저 플래그(`enable-webgpu-developer-features`)를 켜서 이러한 제한을 우회할 수 있습니다 [7, 15].
|
||||
## 매 핵심
|
||||
|
||||
* **브라우저 내부 프로파일링 도구 ([[Browser|Browser]]-Internal Profiling)**
|
||||
* **[[Chrome DevTools|Chrome DevTools]] (Performance 패널):** 애플리케이션의 런타임 트레이스를 캡처하여 메인 스레드 차단 및 프레임 드롭을 진단할 수 있습니다 [16]. CPU 스로틀링(Throttling) 기능을 통해 고사양 기기에서 모바일 기기의 성능을 시뮬레이션함으로써, 강력한 하드웨어 성능에 가려져 있던 미세 지연을 드러낼 수 있습니다 [4, 16].
|
||||
* **[[Chrome|Chrome]] Tracing (`about:tracing`):** 브라우저의 다중 프로세스 아키텍처를 세밀하게 분석할 수 있습니다. "CrGpuMain"과 "CrRendererMain" 스레드의 활성 상태를 비교하여 시스템이 CPU 바운드인지 GPU 바운드인지 판별하며, 긴 가비지 컬렉션 주기나 네트워크 대기 등으로 인해 발생하는 유휴 시간(Idle-time) 미세 지연을 파악하는 데 필수적입니다 [4, 17-19].
|
||||
### 매 측정 대상 분리
|
||||
- **CPU time**: JS → WebGL command 인코딩 (validate, draw call dispatch).
|
||||
- **GPU time**: shader 실행 + raster + blend.
|
||||
- **Present latency**: swapchain → display 의 frame pacing (compositor 의존).
|
||||
|
||||
* **하드웨어 지원 측정 방식 ([[Hardware|Hardware]]-Assisted Latency Measurement)**
|
||||
* 소프트웨어 기반의 측정은 디스플레이 컨트롤러나 물리적 모니터 자체에서 발생하는 지연을 포착할 수 없으므로, 매우 정밀한 연구를 위해서는 하드웨어 보조 기법이 요구됩니다 [5].
|
||||
* **고속 카메라 기법:** 1000Hz(밀리초당 1프레임)로 녹화하는 고속 카메라와 LED 입력 트리거를 사용하여, 버튼 클릭부터 디스플레이에 시각적 변화가 나타나기까지의 전체 "입력 대 디스플레이(Input-to-Display)" 지연을 측정합니다 [5].
|
||||
* **오실로스코프와 포토다이오드:** 모니터에 부착한 포토다이오드로 시각적 변화에 따른 빛의 강도 변화를 전압 스파이크로 감지하고, 이를 입력 장치의 전기 신호와 오실로스코프에서 비교하여 밀리초 미만의 정밀도로 종단 간 지연을 측정합니다 [6].
|
||||
### 매 측정 수단
|
||||
- `EXT_disjoint_timer_query_webgl2` — GPU timestamp query, ns 정밀도.
|
||||
- `gpu.requestAdapter()` (WebGPU) — 매 native timestamp-query feature.
|
||||
- Chrome DevTools Performance → GPU track.
|
||||
- `Spector.js` — frame capture + per-call cost.
|
||||
|
||||
* **운영 체제 및 드라이버 수준의 미세 지연 오버헤드**
|
||||
* **컨텍스트 생성 지연 (Context Creation Latency):** WebGL/WebGPU 컨텍스트 생성은 브라우저가 OS 그래픽 스택과 직접 소통해야 하는 동기식 작업으로 드라이버에 따라 심각한 지연을 유발합니다. (예: Mesa 50ms, NVIDIA 120ms, FGLRX 200ms) 이는 페이지 로드 시 메인 스레드의 가시적인 프리징을 야기합니다 [20-22].
|
||||
* **[[ANGLE|ANGLE]] 변환 오버헤드:** Windows 플랫폼에서는 WebGL의 OpenGL ES 호출을 Direct3D로 변환하기 위해 ANGLE 계층을 거치며, 드로우 콜([[Draw Call|Draw Call]])마다 몇 마이크로초의 미세 지연이 부가됩니다. 이 지연은 수천 번의 드로우 콜이 발생하는 씬에서 누적되어 GPU가 여유로운 상황에서도 CPU 병목(Bottleneck) 현상을 일으킵니다 [21, 23, 24].
|
||||
### 매 응용
|
||||
1. 60→120Hz upgrade 시 frame budget shrink (16.6→8.3ms) 의 bottleneck localization.
|
||||
2. Mobile WebGL 의 thermal throttling 감지 (GPU time 의 점진적 increase).
|
||||
3. PWA 게임 의 input→render latency end-to-end 측정.
|
||||
|
||||
* **[[JavaScript|JavaScript]] 우회 측정 방법**
|
||||
* 일부 브라우저(예: Chrome)에서는 성능 및 구조상의 이유로 `gl.finish()`가 비정상적으로 `gl.flush()`로 작동하기 때문에 렌더링 지연을 직접 측정할 수 없습니다 [11]. 이를 우회하기 위해 `gl.readPixels()`를 사용하여 단일 픽셀을 강제로 읽어 모든 그래픽 프로세스를 지연시키고 동기화한 뒤, 그 오버헤드를 `performance.now()`로 측정 및 차감하여 실제 작업의 렌더링 시간을 추정하는 기법이 활용되기도 합니다 [25, 26].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
### Timer Query — frame GPU time 측정
|
||||
```javascript
|
||||
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
|
||||
const queries = [];
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Spectre and Meltdown|Spectre and Meltdown]], WebGPU [[Timestamp Queries|Timestamp Queries]], EXT_disjoint_timer_query
|
||||
- **Projects/Contexts:** Chrome DevTools [[Performance Panel|Performance Panel]], [[ANGLE (Almost Native Graphics Layer Engine)|ANGLE (Almost Native Graphics Layer Engine]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 WebGL의 `gl.finish()` 함수는 본래 GPU 파이프라인의 실행 완료를 기다리는 기능이나, Chrome에서는 `gl.flush()`로 별칭(alias) 지정되어 있어, 이를 사용해 실제 렌더링 지연 시간을 측정하려는 시도는 작동하지 않습니다 [11, 27]. 또한 `EXT_disjoint_timer_query` 확장이나 `performance.now()` 등의 도구 역시 각각 보안 문제(캐시 기반 정보 유출) 및 제한적인 렌더링 조건 탓에 순수하고 완벽한 미세 지연 측정 도구로 사용하기에는 한계가 존재합니다 [3, 11, 28].
|
||||
function frame() {
|
||||
const q = gl.createQuery();
|
||||
gl.beginQuery(ext.TIME_ELAPSED_EXT, q);
|
||||
drawScene();
|
||||
gl.endQuery(ext.TIME_ELAPSED_EXT);
|
||||
queries.push({ q, frameId: frameCount++ });
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// resolve 매 several frame later (async)
|
||||
for (let i = queries.length - 1; i >= 0; i--) {
|
||||
const { q, frameId } = queries[i];
|
||||
const available = gl.getQueryParameter(q, gl.QUERY_RESULT_AVAILABLE);
|
||||
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
|
||||
if (available && !disjoint) {
|
||||
const ns = 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);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Anti — gl.finish() blocking
|
||||
```javascript
|
||||
// X — pipeline stall, 매 production 에서 절대 사용 X
|
||||
const t0 = performance.now();
|
||||
drawScene();
|
||||
gl.finish(); // CPU↔GPU sync barrier
|
||||
const t1 = performance.now();
|
||||
// t1-t0 는 측정 대상이 아닌 stall 의 cost
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Input→render latency (RAIL model)
|
||||
```javascript
|
||||
let inputTs = 0;
|
||||
canvas.addEventListener('pointerdown', e => {
|
||||
inputTs = e.timeStamp; // 매 hardware timestamp
|
||||
});
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
function frame(now) {
|
||||
if (inputTs > 0 && pendingInputProcessed) {
|
||||
const latency = now - inputTs;
|
||||
if (latency > 100) console.warn(`input→render: ${latency}ms`);
|
||||
inputTs = 0;
|
||||
}
|
||||
drawScene();
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Disjoint detection (thermal throttling)
|
||||
```javascript
|
||||
function checkThermal() {
|
||||
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
|
||||
if (disjoint) {
|
||||
// 매 GPU 가 context switch / power state 변경 — measurement invalid
|
||||
metricsBuffer.flush('thermal_event');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### WebGPU — native timestamp query
|
||||
```javascript
|
||||
const querySet = device.createQuerySet({ type: 'timestamp', count: 2 });
|
||||
const encoder = device.createCommandEncoder();
|
||||
const pass = encoder.beginRenderPass({
|
||||
...,
|
||||
timestampWrites: { querySet, beginningOfPassWriteIndex: 0, endOfPassWriteIndex: 1 }
|
||||
});
|
||||
pass.draw(...);
|
||||
pass.end();
|
||||
encoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);
|
||||
// readback async
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### Frame pacing (requestVideoFrameCallback)
|
||||
```javascript
|
||||
videoEl.requestVideoFrameCallback((now, meta) => {
|
||||
const presentLatency = meta.presentationTime - meta.captureTime;
|
||||
// 매 actual display 까지의 latency 측정
|
||||
});
|
||||
```
|
||||
|
||||
### Sliding-window p99 측정
|
||||
```javascript
|
||||
const samples = new Float32Array(120); // 2s @ 60Hz
|
||||
let idx = 0;
|
||||
function record(ms) {
|
||||
samples[idx++ % samples.length] = ms;
|
||||
if (idx % 60 === 0) {
|
||||
const sorted = [...samples].sort((a, b) => a - b);
|
||||
console.log('p50:', sorted[60], 'p99:', sorted[118]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| WebGL2 + 매 정밀 측정 | `EXT_disjoint_timer_query_webgl2` |
|
||||
| WebGPU 가능 | timestampWrites |
|
||||
| Quick debug | Spector.js capture |
|
||||
| Production telemetry | sliding-window p99 + disjoint flag |
|
||||
| Cross-browser fallback | CPU time only + acknowledged limitation |
|
||||
|
||||
**기본값**: WebGL2 + timer query async readback, p99/disjoint 매 telemetry.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[WebGL]] · [[GPU]]
|
||||
- 변형: [[WebGPU]] · [[Vulkan]]
|
||||
- 응용: [[Web-Game-Performance]] · [[Three.js]]
|
||||
- Adjacent: [[Frame-Pacing]] · [[Browser-Compositor]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: WebGL/WebGPU 앱 의 frame budget 초과 진단, 60→120Hz 마이그레이션, mobile thermal 분석.
|
||||
**언제 X**: 일반 DOM perf (use Performance API), Canvas2D (no GPU query).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **gl.finish() in frame loop**: pipeline stall, 매 측정값 자체 가 왜곡.
|
||||
- **performance.now() only**: GPU async 의 무시 — frame 의 N+2 까지 결과 가 안 나올 수 있음.
|
||||
- **disjoint flag 무시**: thermal/power state 변경 시 measurement 가 garbage 인데 그대로 report.
|
||||
- **single sample**: GC, compositor jitter 의 무시 — 매 p99 측정 필수.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Khronos `EXT_disjoint_timer_query_webgl2` spec, Chrome DevTools docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — WebGL micro-latency 측정 패턴 정리 |
|
||||
|
||||
Reference in New Issue
Block a user