전체 글 목록으로

병합 전에 CI에서 게임 성능 비교하기

리팩터링한 코드가 기능 테스트를 모두 통과해도 매 프레임의 처리량은 늘어날 수 있습니다. 개발자가 직접 작성했든 Claude Code나 Codex가 작성했든 마찬가지입니다. 동작이 올바른지 확인하는 테스트만으로는 대상 하드웨어에서의 실행 비용을 알 수 없습니다.

성능 검사에는 반복 가능한 작업 부하와 실측한 베이스라인이 필요합니다. Framedash의 perf-diff는 두 빌드의 텔레메트리를 비교하고, run-profile-test는 테스트 명령을 실행한 뒤 비교까지 수행합니다. 게임은 개발팀의 PC나 CI 러너에서 실행합니다. 이 결과로 병합을 막기 전에 무엇을 측정하는 비교인지, 변경하지 않은 빌드에서도 얼마나 편차가 생기는지부터 확인해야 합니다.

변경하지 않은 베이스라인부터 반복 측정하기

레벨 안의 고정 경로를 이동하는 것처럼 매번 같은 방식으로 실행할 수 있는 시나리오를 하나 고릅니다. 베이스라인 빌드를 측정하고, 코드를 바꾸지 않은 채 한 번 더 실행한 다음 후보 빌드를 측정합니다. 다음 조건을 동일하게 유지하고 결과와 함께 기록하세요.

  • 하드웨어, OS, 그래픽 드라이버, 전원 설정
  • 엔진과 SDK 버전, 빌드 구성, 그래픽 API
  • 해상도, 품질 설정, VSync, 프레임 레이트 제한
  • 시나리오, 카메라 이동 경로, 워밍업, 측정 시간, 텔레메트리 설정

반복 실행하면 한 번의 베이스라인 측정으로는 알 수 없는 편차가 드러납니다. 변경하지 않은 빌드끼리도 예정한 임계값을 넘는다면, CI 실패 판정을 켜기 전에 실행 환경이나 테스트 절차를 점검합니다. 예제에 나온 비율을 그대로 가져오는 것만으로는 게임의 측정 잡음을 추정할 수 없습니다.

서로 다른 조건의 데이터가 섞이지 않게 하는 것도 필요합니다. perf-diff는 조회 기간에 해당하는 텔레메트리를 build_id별로 집계하며, 기본 기간은 최근 30일입니다. 같은 ID를 재사용한 실행은 같은 집계에 포함됩니다. ci.scenario는 메타데이터이며, 이 명령이 해당 값으로 시나리오를 자동 필터링하지는 않습니다. 실행이나 구성을 따로 비교해야 한다면 측정용 빌드 ID를 구분하고, 원본 커밋은 ci.commit에 남깁니다. 베이스라인과 후보 모두 선택한 기간 안에 보관 중인 데이터가 있어야 합니다.

P50 게이트의 판정 방식 이해하기

perf-diff는 수집된 지표의 P50과 P95를 보여 줍니다. P50은 중앙값이며, 성능 회귀 게이트는 P50의 변화율로 판정합니다. P95는 표본 값의 상위 구간을 살펴보는 값으로, 종료 코드를 결정하지 않습니다.

CLI를 설치하고 설정했다면 다음 예제로 프레임 타임을 검사할 수 있습니다.

framedash perf-diff \
  --baseline "$BASELINE_BUILD_ID" --candidate "$CANDIDATE_BUILD_ID" \
  --api-key-file ci-read.key --metric frame_time \
  --threshold 5 --fail-on-regression

두 ID에는 SDK가 실제로 보낸 값을 넣고, FRAMEDASH_PROJECT_ID에는 측정할 프로젝트 ID를 설정합니다. 비공개 파일 ci-read.key에는 analytics:read 권한이 있는 키를 저장합니다. 여기서 5%는 허용 폭의 예시이지 권장 임계값은 아닙니다.

베이스라인이 양수일 때 프레임 타임 P50이 10 ms에서 10.5 ms로 늘면 증가율이 정확히 5%이므로 이 게이트를 통과합니다. 10.6 ms라면 6% 증가이므로 실패합니다. 이는 판정 방식을 설명하기 위한 수치입니다. 증가율이 허용 폭 안에 있어도 보고서의 isRegression은 true일 수 있으며, CLI는 --threshold를 별도로 적용합니다. P95만 나빠지면 통과할 수 있으므로, 간헐적인 끊김이 중요한 시나리오에서는 상위 백분위수도 확인해야 합니다.

옵션과 실패 사유는 다음과 같이 구분합니다.

  • --fail-on-regression이 없으면 성능 회귀가 있어도 결과만 출력합니다. 이 옵션을 붙이면 증가율이 임계값을 초과할 때 종료 코드 1을 반환합니다. 기본 임계값은 0%입니다.
  • --metric은 게이트 판정에 사용할 지표를 고릅니다. 보고서에는 다른 지표도 포함될 수 있습니다. 생략하면 비교 가능한 모든 지표를 검사하고, 데이터가 없는 지표는 건너뜁니다. 따라서 프레임 타임 검사를 통과했다고 해서 GPU 시간까지 확인한 것은 아닙니다.
  • 선택한 범위에 비교 가능한 지표가 하나도 없으면 종료 코드 1을 반환합니다. 이는 측정된 성능 저하가 아니라 근거 데이터의 부족을 뜻합니다. 인증 오류나 잘못된 ID 등으로도 명령이 실패할 수 있으므로, 코드를 고치기 전에 진단 메시지를 읽어야 합니다.

그 밖에 지원하는 지표는 memory, gpu_time, io.read_bytes, io.read_time_ms, io.read_ops, load_time_ms, mem.vram입니다. 각 지표에 해당하는 데이터를 실제로 수집해야 하며, I/O와 맵 로드 측정에는 SDK 측 설정도 필요합니다. 게이트는 이들 지표의 증가를 모두 악화로 취급합니다. I/O와 로드 시간은 유효한 베이스라인이 0에서 양수로 바뀌면 백분율 임계값과 관계없이 실패합니다. 0을 기준으로 한 백분율 변화는 정의할 수 없기 때문입니다.

--map과 --platform으로 데이터 범위를 좁힐 수 있지만, 두 머신이나 시나리오의 측정 조건이 같은지까지 검증하지는 않습니다. --metric load_time_ms는 --map과 함께 쓸 수 없습니다. 맵 로드 이벤트에는 이 필터가 사용하는 map_id가 없기 때문입니다.

CI에서 시나리오 실행하기

반복 실행한 보고서를 판단에 쓸 수 있게 되면 게임 실행과 성능 비교를 같은 CI 작업에 넣습니다. 아래는 Bash 예제입니다. ./ci/profile-game.sh는 직접 준비할 스크립트를 뜻하며, Framedash에 포함된 파일이 아닙니다. 스크립트는 대상 빌드를 실행하고, 시나리오와 텔레메트리 전송을 완료한 다음, 테스트 결과에 맞는 상태 코드로 종료해야 합니다.

framedash run-profile-test \
  --command "./ci/profile-game.sh" \
  --build-id "$CANDIDATE_BUILD_ID" --commit "$GITHUB_SHA" \
  --scenario plaza-loop --api-key-file ci-read.key \
  --baseline "$BASELINE_BUILD_ID" --metric frame_time \
  --threshold 5 --fail-on-regression

GITHUB_SHA는 GitHub Actions가 제공하는 커밋 값입니다. 다른 CI에서는 해당 시스템의 값으로 바꾸세요. 베이스라인은 미리 측정해 두어야 합니다. 판정 기준을 조정하는 동안에는 --fail-on-regression을 빼고 결과만 관찰할 수 있습니다.

run-profile-test는 값이 있는 경우 FRAMEDASH_BUILD_ID, FRAMEDASH_GIT_BRANCH, FRAMEDASH_GIT_COMMIT, FRAMEDASH_TEST_SCENARIO를 자식 프로세스에 전달합니다. Unity와 Godot C#에서는 SDK를 초기화한 뒤 테스트 진입점에서 다음과 같이 읽을 수 있습니다.

Framedash.TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();
// Run the scenario, then flush and wait using your SDK's CI procedure.
Framedash.TelemetrySDK.Instance.EndAutomatedSession();

이 코드는 세션 태깅만 보여 주는 발췌이며, 완성된 테스트 구현은 아닙니다. UE5에서는 UFramedashSubsystem에 대응하는 메서드가 있습니다. 세션은 최상위 build_id 필드와 ci.branch, ci.commit, ci.scenario 속성을 설정합니다. 세션과 러너 설정은 CI 연동 프로파일링 안내에 있습니다. 세션이 끝났다고 버퍼의 이벤트가 서버에 도착한 것은 아닙니다. 사용하는 SDK의 플러시와 대기 절차를 따르고, 전송이 끝나기 전에는 게임을 종료하지 마세요.

두 프로세스에는 별도의 키를 사용합니다. CLI는 ci-read.key의 analytics:read 키로 데이터를 읽고, 게임은 events:write 키로 데이터를 보냅니다. 읽기용 키를 --api-key-file로 전달하면 게임 초기화 코드가 FRAMEDASH_API_KEY에서 수집용 키를 읽을 수 있습니다. 두 키 모두 CI 비밀 변수나 비공개 파일에서 관리하고, 소스 저장소나 로그에 남기지 마세요.

렌더링 성능을 측정할 때는 렌더링 켜기

UE5의 -nullrhi는 일반적인 렌더링을 비활성화합니다. 헤드리스 로직 테스트에는 사용할 수 있지만 렌더링 작업 부하를 재현하지 못하며, 의미 있는 GPU 성능 비교도 할 수 없습니다. 그래픽 성능을 측정하려면 대상 GPU에서 렌더링을 켜고 두 빌드의 설정을 같게 유지해야 합니다. 다른 엔진의 그래픽 비활성화 모드도 같은 원칙으로 다룹니다.

측정이 끝났는지 확인하기

run-profile-test는 후보 빌드의 성능 이벤트 수가 실행 전보다 증가할 때까지 기다립니다. 덕분에 재실행 시 기존 데이터만으로 대기를 끝내는 일은 막을 수 있지만, 새 실행의 모든 이벤트가 도착했다는 보장은 아닙니다. 게임 프로세스가 실패하거나 시간 초과로 종료되면 러너도 실패하며, 성능 회귀 판정으로 넘어가지 않습니다.

기존 perf-diff 게이트에는 통계적으로 충분한 최소 표본 수를 확인하는 기능이 없고, 앞서 나열한 측정 조건을 모두 검증하지도 않습니다. 테스트 절차에 표본 수, 세션 수, 시나리오 완료 여부, SDK 로그 확인을 포함하세요. 표본이 적어도 비교 결과는 나올 수 있지만, 출시 판단의 근거로 충분하지 않을 수 있습니다.

여기서 백분위수는 서버에 수집된 텔레메트리 표본을 나타내며, 렌더링된 모든 프레임을 반드시 포함하지는 않습니다. 주기적인 하트비트와 이벤트 시점의 스냅샷은 짧은 끊김을 놓칠 수 있고, 이벤트 빈도가 달라지면 표본 분포도 달라질 수 있습니다. 구간을 정해 프레임마다 측정해야 하는 Unity 프로젝트라면 별도의 Unity 성능 실행 비교 파일럿에서 run-diff로 베이스라인, 변경 없는 반복 실행, 후보를 비교할 수 있습니다. 이 기능은 프레임 간격 분포와 수집 완료 여부를 보여 줍니다. 이 글의 P50 성능 회귀 판정을 적용하거나 perf-diff에 P95 실패 조건을 추가하는 기능은 아닙니다.

차이를 조사하고 같은 조건에서 수정 검증하기

비교 가능한 결과가 임계값을 넘으면 먼저 같은 조건에서 다시 실행합니다. 차이가 계속 나타나면 영향을 받은 작업 부하를 좁히고 엔진 프로파일러로 캡처합니다. 프레임 타임이나 메모리 증가는 증상을 알려 주지만, 원인이 된 함수나 할당까지 가리키지는 않습니다.

시나리오에서 위치와 등록된 맵 ID를 포함한 이벤트를 보낸다면 성능 히트맵으로 부하가 높은 영역을 찾는 데 도움을 받을 수 있습니다. 그 지점이 후보 빌드 때문에 느려졌다고 판단하기 전에 빌드와 다른 활성 필터를 확인하세요. 빌드 비교 자체에 맵 설정이 필수인 것은 아닙니다.

에이전트에게 Framedash의 읽기 전용 MCP 도구로 근거 데이터를 살펴보게 할 수도 있습니다. get_heatmap 같은 집계 도구에는 analytics:read가 필요하고, query로 SQL을 직접 실행하려면 data:admin이 추가로 필요합니다. 직접 쿼리가 꼭 필요한 조사에만 더 넓은 권한을 부여하세요. 텔레메트리를 읽을 수 있다고 에이전트의 원인 설명이나 코드 변경이 검증된 것은 아닙니다. 프로파일러로 가설을 확인하고, 패치를 리뷰하고, 수정한 빌드를 같은 시나리오로 측정해야 합니다.

명령 옵션은 CLI 레퍼런스에 있습니다. Claude Code 플러그인에는 MCP 설정과 연동 안내가 포함되어 있습니다.

claude plugin marketplace add crane-valley/framedash-claude-plugin
claude plugin install framedash@framedash

변경 없이 반복했을 때의 편차를 파악할 수 있는 시나리오 하나부터 시작하세요. 베이스라인, 후보 보고서, 테스트 설정, 이후의 수정 검증 결과를 풀 리퀘스트에 함께 남기면 리뷰어가 성능 변화를 허용할 수 있는지 판단할 근거가 됩니다.

직접 관리하는 실행 환경에서 변경 전후 비교하기 Unity, UE5, Godot (C#) SDK를 사용할 수 있습니다.
무료로 시작하기 UnityUE5Godot (C#)