· 12 min read

Chrome WebGPU 디버깅을 AI에게 시키는 법 — MCP + Xcode CLI

Chrome DevTools MCP로 AI가 브라우저를 직접 조작하게 하고, xctrace로 Metal 레벨까지 내려가는 GPU 디버깅 파이프라인 구축기.

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.trace

AI에게 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.xml

AI가 이 XML을 파싱해서 Command Buffer 수, 인코딩 시간, 대기 시간 등을 분석할 수 있다.

5. 디버깅 레벨별 정리

레벨도구AI 접근찾을 수 있는 것
JS / WebGPU APIChrome 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를 활용하려면:

  1. Chrome DevTools MCP를 설치해서 AI가 브라우저를 직접 조작하게 한다
  2. 앱에 계측 포인트를 심어서 AI가 evaluate_script로 상태를 조회할 수 있게 한다
  3. 디버그 셰이더 모드를 만들어서 렌더링 경로를 시각화할 수 있게 한다
  4. 브라우저 레벨에서 해결 안 되면 xctrace로 Metal Trace를 뜨고, 결과를 AI에게 넘겨서 분석시킨다

가장 중요한 건 2번이다. MCP는 도구일 뿐이고, AI가 실제로 진단에 쓸 수 있는 데이터를 앱에서 제공해야 한다. window.__webgpuClipmapStats 같은 전역 객체 하나가 스크린샷 열 장보다 정보량이 많다.


이 글에서 다룬 디버깅 파이프라인은 OFF(Open Field Framework)의 WebGPU 렌더러 개발 중에 구축한 것이다.

Related Posts

View All Posts »

.NET 서버 메모리 누수 잡기 — dotnet-gcdump로 안 보이는 할당 폭탄

.NET 서버 메모리가 2분 만에 136MB에서 14GB로 폭증했다. dotnet-gcdump와 dotnet-counters로도 안 잡히는 할당 폭탄을 추적하고, 그 과정을 재사용 가능한 스킬로 만든 이야기.

#Aethelgard #AI #Claude #GameDev
self-hosted CI에 Claude Code 구독 물리기 — PR 자동 분석·테스트 파이프라인

self-hosted CI에 Claude Code 구독 물리기 — PR 자동 분석·테스트 파이프라인

API가 아닌 Claude Code 구독을 self-hosted runner에 물려, CI가 돌 때마다 테스트 자동화와 PR 변경 분석을 수행하는 파이프라인. AI와 함께 코딩하니 테스트가 늘고, 테스트가 늘으니 CI가 필요해진 흐름을 정리했다.

#Aethelgard #AI #Claude #GameDev
AI에게 게임 월드를 만들라고 시켰더니 — AI-Driven Game Engine Development #1

AI에게 게임 월드를 만들라고 시켰더니 — AI-Driven Game Engine Development #1

AI가 월드를 자율적으로 만들려면 뭘 준비해야 하는가. 도구를 설계하고, 시행착오를 거치고, 벽 없는 미로에서 교훈을 얻기까지.

#OFF #AI #Claude #GameDev