コンテンツにスキップ

Godot のパフォーマンス回帰を CI で検出する

Godot のパフォーマンス回帰をマージ前に止めるには、各ビルドのテレメトリーに build_id を付け、CI 上でプロファイリングシナリオを実行し、framedash perf-diff でパイプラインをゲートします。 候補ビルドが既知の良好なベースラインに対してしきい値を超えて悪化すると、コマンドは非ゼロで終了し、ジョブを失敗させます。 このガイドでは、Framedash の Godot SDK(.NET ビルドの Godot 4.3 以降向けの C# アドオン)でこの仕組みを構築します。

ビルドのタグ付けと回帰ゲートの考え方は、CI 統合プロファイリングを参照してください。

1. CI のビルド ID でタグ付けする

Section titled “1. CI のビルド ID でタグ付けする”

CI のコミットやビルド識別子を build_id として SDK に渡すと、その実行のすべてのイベントが一つのビルドに紐付きます。 framedash run-profile-test(手順 4)がエクスポートする変数 FRAMEDASH_BUILD_ID を読み取り、テレメトリーの build_id をゲートが待つ値に一致させます。

TelemetrySDK.Initialize(
apiKey: System.Environment.GetEnvironmentVariable("FRAMEDASH_API_KEY"),
buildId: System.Environment.GetEnvironmentVariable("FRAMEDASH_BUILD_ID"));

別の変数(たとえば CI_COMMIT_SHA)でビルドをタグ付けする場合は、その同じ値を run-profile-test--build-id にも渡して両者を一致させてください。 一致しないと、ゲートは取り込まれない build_id を待ち続けてタイムアウトします。 Godot SDK は Unity SDK と同じ C# テレメトリー API を共有します。 インストールと .NET のセットアップは Godot SDK ガイドを参照してください。

2. 自動セッションにタグを付ける

Section titled “2. 自動セッションにタグを付ける”

テストのエントリーポイントで自動セッション API を一度呼び出します。 BeginAutomatedSessionFromEnvironment() は、framedash run-profile-test がエクスポートする FRAMEDASH_BUILD_ID / FRAMEDASH_GIT_BRANCH / FRAMEDASH_GIT_COMMIT / FRAMEDASH_TEST_SCENARIO を読み取ります。 これにより、イベントごとのタグ付けコードなしで、すべてのイベントにビルドと branch/commit/scenario が付与されます。

TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();
// ... プロファイリングシナリオを実行 ...
TelemetrySDK.Instance.EndAutomatedSession();

3. CI 向けに C# ソリューションをビルドする

Section titled “3. CI 向けに C# ソリューションをビルドする”

Godot エディターの Build は、C# プロジェクトの .csproj.sln を生成します。 godot --headless --build-solutions --quit既存のソリューションをコンパイルするだけで、エディターで一度も開いたことのないプロジェクトでは終了コード 0 でもプロジェクトファイルを書き出さないことがあり、CI 専用プロジェクトにはビルド対象が存在しません。 CI で安全な手順は、.csproj を自分で手書きしてから .NET SDK でビルドすることです。

<!-- プロジェクトルートの <project>.csproj。Godot.NET.Sdk のバージョンはエンジンに合わせる -->
<Project Sdk="Godot.NET.Sdk/4.6.3">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>
Terminal window
dotnet build

ヘッドレスの --build-solutions だけでは不十分な理由と、手書きの .csproj の全文は、Godot SDK ページの一度も開いていないプロジェクトの注意点を参照してください。 プロジェクトをエディターで一度開ける場合は、そこで Build をクリックし、生成された .csproj / .sln をコミットしてもかまいません。

Godot にはオフラインキューがないため、短命なヘッドレス実行は配信の完了前に終了することがあります。 プロファイリングシーンで Flush() を呼び、verbose ログに HTTP 202 の行が出るまでプロセスを生かしておいてください。 ソリューション生成の注意点と、フラッシュして待機する例は Godot SDK ガイドにあります。

framedash run-profile-testFRAMEDASH_* セッション変数をエクスポートし、プロファイリングコマンドを起動し、テレメトリーの取り込みを待ってから、ベースラインに対して perf-diff ゲートを実行します。

Terminal window
framedash run-profile-test \
--command "godot --headless --path ." \
--scenario nightly --api-key-file ci-read.key \
--baseline "$BASE_SHA" --threshold 5 --fail-on-regression

ゲートは analytics:read キーでテレメトリーを読み取り、起動されるゲームは別の events:write 取り込みキーでテレメトリーを送信します。 ゲートキーは --api-key-file で渡し、FRAMEDASH_API_KEY はゲームの取り込みキー用に残してください。

手動でステップを実行することもできます。 framedash run-profile-test は自身が起動したコマンドの中でしか FRAMEDASH_BUILD_ID を設定しないため、自分で実行を回す場合は好きなビルド ID で自分で FRAMEDASH_BUILD_ID をエクスポートし(手順 1 の初期化コードがこれを読みます)、同じ値を --candidate にも使ってください。

Terminal window
export FRAMEDASH_BUILD_ID="$GITHUB_SHA"
# ... launch your profiling run so the SDK tags telemetry with this build id ...
framedash builds --days 30
framedash perf-diff --baseline "$BASE_SHA" --candidate "$FRAMEDASH_BUILD_ID" \
--threshold 5 --fail-on-regression

perf-diff はフレームタイム、メモリ、GPU 時間、マップロード時間(load_time_ms)、ディスク I/O(io.read_bytes / io.read_time_ms / io.read_ops)を、値が小さいほど良い(lower-is-better)指標として比較します。 マップロードと io.* のサンプルには Godot SDK 0.1.4 以降が必要です。 --metric で対象指標を一つに絞ったり、--map--platform で対象マップやプラットフォームを絞ったりできます。

プルリクエストごとにゲートを実行する最小構成のワークフローです。 perf-diff にはベースラインのコミットが必要なため fetch-depth: 0 を指定し、analytics:read キーはシークレットから ci-read.key に書き出します。

name: perf-regression
on: pull_request
jobs:
perf-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # perf-diff needs the baseline commit
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.x"
- name: Install the Framedash CLI
run: npm install -g @framedash/cli
- name: Build the C# solution
run: dotnet build
- name: Run the perf-diff gate
env:
FRAMEDASH_API_KEY: ${{ secrets.FRAMEDASH_INGEST_KEY }} # events:write, used by the game
FRAMEDASH_READ_KEY: ${{ secrets.FRAMEDASH_READ_KEY }} # analytics:read, used by the gate
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
printf '%s' "$FRAMEDASH_READ_KEY" > ci-read.key
framedash run-profile-test \
--command "godot --headless --path ." \
--scenario nightly --api-key-file ci-read.key \
--baseline "$BASE_SHA" --threshold 5 --fail-on-regression

ゲームを起動するには、ランナー上に Godot の .NET エディターが必要です(先行ステップでインストールするか、同梱したコンテナイメージを使ってください)。 2 つのキーは別物です。ゲームは FRAMEDASH_API_KEYevents:write キーで送信し、ゲートは ci-read.keyanalytics:read キーで読み取ります。

GitHub はフォーク PR から起動されたワークフローにシークレットを渡さないため、この pull_request ゲートは同一リポジトリ(信頼済み)の PR でのみ動作します。 フォーク PR を受け入れる公開リポジトリでは、ジョブをガードするか(たとえば github.event.pull_request.head.repo.fork が true のときスキップする)、別の信頼済みワークフローからゲートを実行し、信頼できない PR のコードにキーを渡さないでください。

CLI がないパイプラインでも、同じ比較を REST で利用できます。 GET /v1/projects/{id}/builds がビルド ID を一覧し、GET /v1/projects/{id}/builds/compare が 2 つのビルドを比較します。 後者は baselinecandidate を必須とし、days / mapId / platform / fresh=1 を受け付けます。 詳細は API 概要を参照してください。