· 12 min read
Chrome WebGPU 디버깅을 AI에게 시키는 법 — MCP + Xcode CLI How to Let AI Debug Chrome WebGPU — MCP + Xcode CLI
Chrome DevTools MCP로 AI가 브라우저를 직접 조작하게 하고, xctrace로 Metal 레벨까지 내려가는 GPU 디버깅 파이프라인 구축기. Building a GPU debugging pipeline where AI controls the browser via Chrome DevTools MCP and dives down to Metal level with xctrace.
WebGPU 코드를 작성하다 보면 디버깅이 고통스럽다. 셰이더에 printf를 찍을 수도 없고, GPU 타이밍은 브라우저 프로파일러에 잘 안 잡히고, 렌더링 결과가 이상해도 어디서 잘못됐는지 알기 어렵다.
나는 이 문제를 두 가지 도구로 해결했다. Chrome DevTools MCP로 AI가 브라우저를 직접 조작하게 하고, Xcode의 xctrace로 Metal 레벨까지 내려가는 방식이다. 이 글에서는 이 파이프라인을 어떻게 구축하고 사용하는지 정리한다.
전체 구조
[AI (Claude Code)]
│
├── Chrome DevTools MCP ──→ [Chrome 브라우저]
│ evaluate_script └── WebGPU 앱
│ take_screenshot
│ list_console_messages
│
└── Bash (xctrace) ──→ [Xcode Instruments]
Metal System Trace └── Dawn → Metal 분석브라우저 레벨 디버깅은 MCP가, GPU 드라이버 레벨은 xctrace가 담당한다.
1. Chrome DevTools MCP 설정
설치
chrome-devtools-mcp 서버를 Claude Code의 MCP 설정에 추가한다. Google Chrome 팀이 공식으로 관리하는 패키지다.
// .claude/settings.local.json
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
}
}
}이러면 AI가 mcp__chrome-devtools__* 도구들을 사용할 수 있게 된다.
주요 도구
| 도구 | 용도 | GPU 디버깅에서의 역할 |
|---|---|---|
evaluate_script | 브라우저에서 JS 실행 | GPU 상태 조회, 디버그 모드 전환 |
take_screenshot | 화면 캡처 | 렌더링 결과 시각 확인 |
list_console_messages | 콘솔 로그 확인 | 셰이더 컴파일 에러, WebGPU 워닝 |
navigate_page | 페이지 이동/리로드 | 캐시 무시 리로드 (ignoreCache: true) |
2. GPU 디버깅용 계측 포인트 준비
MCP가 있어도 조회할 수 있는 데이터가 없으면 소용없다. WebGPU 앱에 미리 계측 포인트를 심어둬야 한다.
런타임 상태 노출
// GPU 업로드 통계
window.__webgpuClipmapStats = {
uploadCount: 0,
origin: [0, 0, 0],
textureSize: [512, 512, 8],
lastUploadMs: 0,
};
// 프레임 타이밍
window.__metrics = {
snapshot() {
return {
gpuMs: this._gpuMs,
cpuDrawMs: this._cpuDrawMs,
frameGapMs: this._frameGapMs,
};
}
};AI가 evaluate_script로 이 값들을 조회해서 상태를 판단한다.
디버그 셰이더 모드
// 디버그 뷰 전환 (0=normal, 1=render path, 2=step heatmap)
window.setDebugView = (mode) => {
settings.webgpuDebugMode = mode;
};셰이더 안에서 debugMode에 따라 다른 출력을 내보낸다:
if (uniforms.debugMode == 1u) {
// 렌더 경로 시각화: DDA=파랑, heightmap=초록, sky=빨강
return vec4f(0.0, 1.0, 0.0, 1.0);
}
if (uniforms.debugMode == 2u) {
// 레이마칭 step 수를 heatmap으로 표시
let heat = f32(steps) / f32(maxSteps);
return vec4f(heat, 1.0 - heat, 0.0, 1.0);
}AI가 디버그 모드를 켜고 스크린샷을 찍으면, “heightmap 영역이 안 그려지고 있다” 같은 판단을 시각적으로 할 수 있다.
3. AI의 디버깅 루프
실제로 AI가 MCP를 사용하는 패턴은 이렇다:
1. navigate_page → localhost 접속
2. take_screenshot → 현재 상태 확인
3. evaluate_script → 디버그 모드 전환
4. take_screenshot → 디버그 뷰 확인
5. evaluate_script → 상태 데이터 조회
6. (문제 파악 → 코드 수정 → 빌드)
7. navigate_page → 캐시 무시 리로드
8. take_screenshot → 수정 결과 비교실전 예시: 데이터가 GPU에 안 올라가는 문제
// AI가 evaluate_script로 실행
const stats = window.__webgpuClipmapStats;
console.log('uploadCount:', stats.uploadCount);
// → uploadCount: 0 ← 업로드가 아예 안 되고 있음// 텍스처 데이터 직접 검증
const mod = await import('/js/grid-state.js');
let nonZero = 0;
for (const grid of mod.gridState.grids.values()) {
for (const h of grid.surfaceHeight) {
if (h > 0) nonZero++;
}
}
console.log(`height nonZero=${nonZero}/262144`);
// → height nonZero=0/262144 ← 높이 데이터가 전부 0이 정도면 “셰이더 문제가 아니라 데이터 업로드 문제”라는 결론을 AI가 스스로 내릴 수 있다.
팁: 스크린샷보다 evaluate_script
스크린샷은 토큰을 많이 먹는다. 가능하면 evaluate_script로 텍스트 기반 진단을 먼저 하고, 시각적 확인이 필요할 때만 스크린샷을 쓰는 게 효율적이다.
Claude Code 스킬에 이 규칙을 넣어두면 AI가 자연스럽게 따른다:
# /browser 스킬
기본적으로 evaluate_script로 경량 진단을 수행한다.
스크린샷은 시각적 확인이 반드시 필요한 경우에만 사용한다.4. 브라우저 밖으로: Xcode xctrace
Chrome DevTools MCP로 해결 안 되는 문제가 있다. 브라우저 밖에서 일어나는 일이다.
내 경우 GPU 시간은 5-14ms, CPU 시간은 0.6ms인데 프레임 간 gap이 88-173ms였다. JS 프로파일러에도 안 잡히고, MCP로 할 수 있는 건 다 해봤다. GPU 드라이버 레벨로 내려가야 했다.
macOS에서 WebGPU = Metal
Chrome의 WebGPU는 Dawn 라이브러리를 통해 Metal로 번역된다. Metal 레벨을 보려면 Xcode의 Instruments를 써야 한다.
준비: Chrome GPU 프로세스에 접근하기
Chrome은 GPU 작업을 별도 프로세스에서 한다. 그리고 코드서명 때문에 디버거 attach가 안 된다. 이걸 해결하는 스크립트:
#!/bin/bash
# setup-metal-debug.sh
# 1. Chrome 복사
CHROME_SRC="/Applications/Google Chrome.app"
CHROME_DST="/tmp/ChromeDebug.app"
cp -R "$CHROME_SRC" "$CHROME_DST"
# 2. 코드서명 제거 (디버거 attach 허용)
codesign --remove-signature "$CHROME_DST/Contents/MacOS/Google Chrome"
codesign --remove-signature "$CHROME_DST/Contents/Frameworks/Google Chrome Framework.framework"
# 3. Metal validation 활성화하여 실행
METAL_DEVICE_WRAPPER_TYPE=1 \
MTL_DEBUG_LAYER=1 \
"$CHROME_DST/Contents/MacOS/Google Chrome" \
--enable-unsafe-webgpu \
--disable-dawn-features=disallow_unsafe_apis \
--remote-debugging-port=9222 \
"$@"xctrace로 Metal System Trace 뜨기
# Chrome GPU 프로세스 PID 찾기
GPU_PID=$(pgrep -f "Google Chrome.*--type=gpu-process")
# Metal System Trace 캡처 (10초)
xctrace record \
--template 'Metal System Trace' \
--attach "$GPU_PID" \
--time-limit 10s \
--output /tmp/webgpu-trace.trace캡처가 끝나면 Instruments에서 열어볼 수 있다:
open /tmp/webgpu-trace.traceAI에게 xctrace 결과 분석 시키기
Instruments GUI는 AI가 직접 조작할 수 없다. 대신 xctrace export로 데이터를 추출해서 AI에게 넘길 수 있다:
# trace 파일에서 테이블 목록 확인
xctrace export --input /tmp/webgpu-trace.trace --toc
# 특정 테이블 추출
xctrace export --input /tmp/webgpu-trace.trace \
--xpath '/trace-toc/run/data/table[@schema="metal-gpu-event"]' \
> /tmp/metal-events.xmlAI가 이 XML을 파싱해서 Command Buffer 수, 인코딩 시간, 대기 시간 등을 분석할 수 있다.
5. 디버깅 레벨별 정리
| 레벨 | 도구 | AI 접근 | 찾을 수 있는 것 |
|---|---|---|---|
| JS / WebGPU API | Chrome DevTools MCP | 직접 | 셰이더 에러, API 호출 실수, 데이터 전달 문제 |
| 렌더링 결과 | MCP 스크린샷 + 디버그 셰이더 | 직접 | 렌더링 아티팩트, 잘못된 영역, 깊이/노멀 문제 |
| 프레임 타이밍 | evaluate_script + 계측 포인트 | 직접 | GPU/CPU 시간, 프레임 gap, 업로드 지연 |
| GPU 드라이버 | xctrace + export | 간접 (텍스트 분석) | Command Buffer 수, 동기화 오버헤드, 드라이버 병목 |
핵심은 각 레벨에서 “여기서는 원인이 안 보인다”를 확인하고 다음 레벨로 내려가는 것이다. JS에서 안 보이면 셰이더를, 셰이더에서 안 보이면 드라이버를 봐야 한다.
실제로 찾은 것
이 파이프라인으로 실제로 찾아낸 문제 하나를 소개한다.
WebGPU 코드에서 프레임당 5개의 render command를 호출하고 있었다. Chrome DevTools로 보면 JS 실행 시간은 0.6ms로 문제가 없다. 그런데 프레임이 느리다.
xctrace로 Metal Trace를 뜨니 120개의 Command Buffer가 생성되고 있었다. Dawn이 WebGPU → Metal 번역 과정에서 과도한 동기화 Barrier를 주입하면서 5개 명령이 120개로 쪼개진 것이다.
이건 MCP만으로는 절대 못 찾는다. Metal 레벨까지 내려가야 보이는 문제다.
정리
WebGPU 디버깅에 AI를 활용하려면:
- Chrome DevTools MCP를 설치해서 AI가 브라우저를 직접 조작하게 한다
- 앱에 계측 포인트를 심어서 AI가
evaluate_script로 상태를 조회할 수 있게 한다 - 디버그 셰이더 모드를 만들어서 렌더링 경로를 시각화할 수 있게 한다
- 브라우저 레벨에서 해결 안 되면 xctrace로 Metal Trace를 뜨고, 결과를 AI에게 넘겨서 분석시킨다
가장 중요한 건 2번이다. MCP는 도구일 뿐이고, AI가 실제로 진단에 쓸 수 있는 데이터를 앱에서 제공해야 한다. window.__webgpuClipmapStats 같은 전역 객체 하나가 스크린샷 열 장보다 정보량이 많다.
이 글에서 다룬 디버깅 파이프라인은 OFF(Open Field Framework)의 WebGPU 렌더러 개발 중에 구축한 것이다.

