Claude Code나 Codex가 작성한 코드는 단위 테스트를 통과해도 게임을 느리게 만들 수 있습니다. 리팩터링이나 기능 추가가 제대로 동작하더라도 프레임 타임, GPU 시간, 메모리 사용량까지 이전과 같다고 보장할 수는 없습니다. 따라서 CI에서는 ‘동작하는가’뿐 아니라 ‘이전 빌드보다 느려지지 않았는가’도 확인해야 합니다.
테스트가 통과해도 성능 저하는 놓칠 수 있다
코드 쓰는 수고가 줄면, 병목은 ‘쓰기’에서 ‘확인하기’로 옮겨 갑니다. 기능이 동작하는지는 테스트가 알아서 답을 냅니다. 하지만 그 코드가 방금 실기기 프레임 타임을 몇 밀리초 밀어 올리지는 않았는지는, 초록색 테스트가 알려 주지 않습니다.
변경이 늘어날수록, 그 하나하나를 사람이 손으로 프로파일링하기는 어려워집니다. 렌더 스레드에 무심코 할당이 늘고, 업데이트 루프의 계산량이 슬그머니 나빠지고, GC가 도는 빈도가 올라갑니다. 이런 것들은 모두 단위 테스트를 통과하고, 눈으로 하는 코드 리뷰도 빠져나가, 실기기에 올려서야 체감 저하로 드러납니다.
기능 테스트는 “동작하는가”를 확인합니다. 빌드 비교는 “이전보다 느려졌는가”를 확인합니다.
변경 전보다 성능이 나빠지는 것을 성능 회귀라고 합니다. 이 성능 회귀를 리뷰어의 알아챔이나 숙련자의 감에만 기대어 찾지 말고, 모든 빌드를 같은 기준으로 확인해야 합니다.
CI에서 성능 저하를 자동 검출하기
할 일은 단순합니다. 빌드마다 성능 텔레메트리를 모으고, 직전의 알려진 정상 빌드와 비교해서, 임계값을 넘어 나빠졌으면 CI를 실패시킵니다. 그러면 사람이 매번 숫자를 들여다보지 않아도, 성능 저하를 병합 전에 찾을 수 있습니다.
Framedash의 framedash perf-diff는 두 빌드의 프레임 타임, 메모리, GPU 시간에 대해 P50과 P95를 모두 내놓는 명령입니다. --fail-on-regression을 붙이면, 후보 빌드의 P50이 임계값을 넘어 나빠졌을 때 종료 코드 1을 반환해 CI를 실패시킵니다(판정은 P50 비교로 하고, P95는 참고로 함께 표시됩니다).
framedash perf-diff --baseline "$BASE_SHA" --candidate "$GITHUB_SHA" \
--threshold 5 --fail-on-regression
비교 대상은 프레임 타임, 메모리, GPU 시간에 더해 맵 로드 시간(load_time_ms)과 디스크 IO(io.*)입니다. 모두 작을수록 좋은 지표로 다뤄집니다. --metric으로 특정 지표만 비교하거나, --map과 --platform으로 비교 범위를 좁힐 수도 있습니다.
여기서 관건은 비교의 단위가 되는 build_id입니다. 어느 빌드의 숫자인지가 일의적으로 정해져 있지 않으면, 빌드끼리의 비교 자체가 성립하지 않습니다.
워크플로 전체 그림
에이전트가 쓴 코드의 성능을 병합 전에 확인하는 흐름을 따라가 봅시다.
임계값을 넘어 나빠지면 CI를 실패시키고, 텔레메트리를 이용한 원인 조사로 넘어갑니다.
CI에서 이 흐름을 한꺼번에 도는 것이 framedash run-profile-test입니다. 이 명령은 자동 세션용 FRAMEDASH_* 환경 변수를 써내고, 지정한 프로파일링용 빌드를 띄운 뒤, 그 텔레메트리가 수집되기를 기다렸다가, perf-diff로 베이스라인과 비교합니다.
framedash run-profile-test \
--command "./Build/Game.exe -nullrhi -ExecCmds='Automation RunTest Perf'" \
--scenario nightly --api-key-file ci-read.key \
--baseline "$BASE_SHA" --threshold 5 --fail-on-regression
띄워진 게임 쪽에서는, 자동 테스트 진입점에서 자동 세션 API를 한 번 호출합니다. SDK가 BeginAutomatedSessionFromEnvironment()를 부르면, run-profile-test가 써낸 FRAMEDASH_BUILD_ID / FRAMEDASH_GIT_BRANCH / FRAMEDASH_GIT_COMMIT / FRAMEDASH_TEST_SCENARIO를 읽어, 이후 모든 이벤트에 CI 빌드와 그 브랜치, 커밋, 시나리오가 자동으로 실립니다. 이벤트마다 태깅하는 코드는 필요 없습니다.
TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();
// ... 프로파일링 시나리오 실행 ...
TelemetrySDK.Instance.EndAutomatedSession();
운영상 주의가 하나 있습니다. 짧은 빌드나 헤드리스 실행은 SDK의 정기 플러시보다 먼저 종료될 수 있습니다. 텔레메트리가 실제로 전송될 때까지 실행을 살려 두세요(각 SDK의 CI와 헤드리스 실행 안내에 방법이 있습니다). 그런 다음 run-profile-test가 수집을 기다렸다가 성능을 비교합니다.
build_id는 최상위 필드로 기록되고, 브랜치와 커밋과 시나리오는 ci.branch / ci.commit / ci.scenario 속성에 실립니다. 이로써 에이전트가 낸 커밋의 build_id가 그대로 빌드 비교의 후보가 됩니다.
키의 구분만 주의하면 됩니다. CI의 비교 처리는 텔레메트리를 analytics:read 키로 읽고, 띄워진 게임은 별도의 events:write 수집용 키로 텔레메트리를 보냅니다. 이름 충돌을 피하려면, 비교용 키는 FRAMEDASH_API_KEY 환경 변수가 아니라 --api-key-file로 넘기고, FRAMEDASH_API_KEY는 게임의 수집용 키로 비워 둡니다.
CI가 성능 저하를 검출하면 어디를 볼까
perf-diff가 CI를 실패시켰을 때 알 수 있는 것은 어느 지표가 얼마나 나빠졌는지까지입니다. 어디서 나빠졌는지는 이 숫자만으로는 알 수 없습니다.
그럴 때 쓰는 것이 성능 히트맵입니다. FPS, 프레임 타임, GPU 시간, 메모리 사용량을 게임 맵 위에 셀 단위로 오버레이해 보여 줍니다. 디바이스나 빌드 프로파일로 좁힐 수 있어서, 성능이 나빠진 빌드의 어느 맵 어느 언저리가 무거워졌는지를 맵 위의 위치로 특정할 수 있습니다.
맵 위의 분포는 위치가 붙은 이벤트에서 그려집니다. 프로파일링 시나리오가 플레이어 위치를 등록된 맵 ID와 함께 보내면, SDK가 그 이벤트에 카메라 방향(요와 피치)을 자동으로 얹습니다. 이것만 갖춰지면, “build 1042의 desert_ruins, 북쪽을 본 한 구석에서 P95가 튄다”는 정도의 입도까지 쫓을 수 있습니다. 이로써 성능 저하는 재현 가능한 조사 대상이 됩니다.
텔레메트리를 에이전트의 원인 조사에 활용하기
여기까지의 흐름에는 아직 사람이 한 군데 남아 있습니다. 히트맵을 열어 원인을 좁히고, 고칠 코드를 쓰는 공정입니다.
이 공정도 에이전트에게 넘길 수 있습니다. Framedash의 MCP 서버는 텔레메트리에 대한 읽기 전용 도구와 리소스를 LLM에 공개합니다. 히트맵 그리드 데이터, 대시보드 KPI, 심지어 생 SQL 쿼리까지, 에이전트가 자연어 지시로 직접 끌어올 수 있습니다.
claude mcp add framedash \
-e FRAMEDASH_API_KEY=fd_xxx \
-e FRAMEDASH_PROJECT_ID=your-project-uuid \
-- npx -y @framedash/mcp-server
이로써 변경을 담당한 에이전트에게 성능이 나빠진 곳의 조사와 수정까지 이어서 맡길 수 있습니다. get_heatmap으로 맵 위의 무거운 곳을 훑고, query를 build_id로 좁혀 후보 빌드의 핫스팟을 뽑아내고, 원인의 짐작을 세워 코드를 고칩니다. 도구는 읽기 전용이라, 에이전트가 텔레메트리를 고쳐 쓰거나 지울 일은 없습니다. 수정이 성능 저하를 해소했는지는 다음 빌드의 같은 CI 성능 비교로 다시 확인합니다.
CI는 숫자로 성능 저하를 검출하고, 에이전트는 원인 후보를 조사합니다. 사람은 임계값을 정하고, 수정 방식이 타당한지를 마지막에 확인합니다.
시작하기
필요한 것은 게임에 SDK를 넣고 build_id를 CI에서 넘기는 것과, CI에 성능 비교를 하나 더하는 것입니다. SDK 통합은 몇 줄이면 되고, 지원 엔진은 Unity, UE5, Godot (C#)입니다.
- SDK와 CI의 구체적인 설정은 CI 연동 프로파일링에 정리되어 있습니다.
- 명령 목록은 CLI 레퍼런스를 참고하세요.
- 에이전트에게 쓰게 하려면, Claude Code 플러그인이 MCP 서버와 스킬을 한 번에 넣어 줍니다.
claude plugin marketplace add crane-valley/framedash-claude-plugin
claude plugin install framedash@framedash