コンテンツにスキップ

UE5 SDK

Framedash UE5 SDK (C++ プラグイン) を使用して、パフォーマンステレメトリを自動収集する方法を説明します。

  • Unreal Engine 5.3 以上
  • Blueprint-only プロジェクトは、対応するコンパイル済みパッケージで利用可能(ソースビルドには C++ プロジェクトとツールチェーンが必要)

Blueprint-only プロジェクトには、Fab の公開ページ または GitHub Releases ページ のコンパイル済みパッケージを使います。使用するエンジンと対象プラットフォームに合うパッケージを選んでください。GitHub では UE 5.3〜5.8 向けの framedash-ue5-v<version>-ue<engine>.zip(例: UE 5.6 なら -ue5.6)を配布しており、Win64 向けのコンパイル済み Binaries を含むため、Launcher 版エンジンのプロジェクトはリビルドなしで利用できます。

ソースからビルドする場合や、コンパイル済みパッケージが対象としていないプラットフォーム向けには、公開ミラーをクローンします。この経路では C++ プロジェクトとツールチェーンが必要です。ソースの Framedash.uplugin はエンジンバージョンを固定していないため、Framedash.Build.cs が対応する全プラットフォーム(Win64 / Mac / iOS / Android / Unix)でビルドできます:

git clone https://github.com/crane-valley/framedash-ue5-sdk.git

その後、プロジェクトに追加します:

  1. プラグインを Plugins/Framedash ディレクトリに配置
  2. .uproject に追加:
{
"Plugins": [
{
"Name": "Framedash",
"Enabled": true
}
]
}
  1. プロジェクトに C++ モジュールがあり、C++ からプラグインを呼び出す場合は、その Build.cs にモジュール依存を追加:
PrivateDependencyModuleNames.Add("Framedash");
  1. ソースプラグイン、ソースビルド版エンジン、またはコンパイル済みパッケージの対象外プラットフォームを使う場合はプロジェクトをリビルド

DefaultGame.ini に以下を追加すると、サブシステム起動時に自動で初期化されます:

[/Script/Framedash.FramedashSettings]
ApiKey=your-api-key
bAutoInitialize=True

オプションで BuildIdSamplingRatePlayerId も設定可能です:

[/Script/Framedash.FramedashSettings]
ApiKey=your-api-key
bAutoInitialize=True
BuildId=1.0.0
SamplingRate=1.0
PlayerId=player-123

PlayerId は開発者が指定するプレイヤー識別子です。 空のままにすると、イベントは匿名として送信され、SDK は No player_id set. Events will be sent as anonymous. とログに出力します。

コンパイル済みのデフォルト EndpointUrl はすでに https://ingest.framedash.dev/v1/events を指しているため、ローカルまたはセルフホストの ingest エンドポイントを使う場合のみ設定が必要です。その場合は値を二重引用符で囲んでください:

EndpointUrl="https://ingest.framedash.dev/v1/events"

これらの設定は Project Settings > Plugins > Framedash からも編集できます。

C++ から初期化コードを書く必要はありません。

設定ファイルを使用せず、コードから直接初期化することもできます:

#include "FramedashSubsystem.h"
void AMyGameMode::BeginPlay()
{
Super::BeginPlay();
if (auto* Subsystem = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
FString ApiKey = FPlatformMisc::GetEnvironmentVariable(TEXT("FRAMEDASH_API_KEY"));
Subsystem->InitializeTelemetry(ApiKey);
}
}

InitializeTelemetry には EndpointUrlBuildId のオプション引数もあります。CI 環境で便利です:

if (auto* Subsystem = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
FString ApiKey = FPlatformMisc::GetEnvironmentVariable(TEXT("FRAMEDASH_API_KEY"));
FString BuildId = FPlatformMisc::GetEnvironmentVariable(TEXT("FRAMEDASH_BUILD_ID"));
// EndpointUrl に空文字列を渡してデフォルト値を使用
Subsystem->InitializeTelemetry(ApiKey, TEXT(""), BuildId);
}

初期化が完了すると、以下のデータが自動的に収集されます:

  • FPS / Frame Time: stat unit 相当のデータ
  • GPU Time: RHI が利用可能な場合に報告する GPU フレーム時間
  • Memory: プラットフォームが報告する使用中の物理メモリ
if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
const FVector PlayerLocation(1000.0f, 2000.0f, 50.0f);
Framedash->Track(TEXT("player_death"), TEXT("Map01"), PlayerLocation);
}

カスタム属性・メトリクス付き

Section titled “カスタム属性・メトリクス付き”

追加のメタデータを付与する場合は TrackWithData を使用します:

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
const FVector PlayerLocation(1000.0f, 2000.0f, 50.0f);
TMap<FString, FString> Attributes;
Attributes.Add(TEXT("cause"), TEXT("fall_damage"));
TMap<FString, double> Metrics;
Metrics.Add(TEXT("health"), 0.0);
Framedash->TrackWithData(
TEXT("player_death"), TEXT("Map01"),
PlayerLocation, Attributes, Metrics);
}

ランタイムのサンプリングオーバーライド

Section titled “ランタイムのサンプリングオーバーライド”

グローバルな SamplingRate(プロジェクト設定)はすべての Player ソースのイベントに適用され、自動イベントはサンプリングの対象外です。 高頻度なイベントは、グローバルレートを上書きするイベント名ごとのレートを個別に設定できます。

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
Framedash->SetEventSamplingRate(TEXT("ai_pathfind_step"), 0.05f); // 約 5%
Framedash->RemoveEventSamplingRate(TEXT("ai_pathfind_step")); // グローバルに戻す
}

SetEventSamplingRate(const FString& EventName, float Rate) はレートを [0, 1] にクランプして設定し、RemoveEventSamplingRate(const FString& EventName) はそのオーバーライドを削除します。 どちらも Blueprint から呼び出せます。

UE5 SDK 0.1.6 以降で利用できます。 サブシステムはレベルの読み込みにかかった時間を計測し、map_load イベントとして報告できます。 このイベントはビルド比較(perf-diff)のリグレッションゲートと、ダッシュボードのロード時間チャートに使われます。 BeginMapLoadEndMapLoadReportMapLoad はいずれも Blueprint から呼び出せます。

自分で制御するロードを囲みます。

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
Framedash->BeginMapLoad(TEXT("Level_01"));
// ... レベルを開く ...
Framedash->EndMapLoad();
}

BeginMapLoad は、ポーズや time dilation の影響を受けない単調増加クロックでタイマーを開始します。 EndMapLoad はそれを止めてイベントを送出します。 EndMapLoad の前に再度 BeginMapLoad を呼ぶと、保留中の計測は置き換えられます。

カスタムローダーやストリーミングローダーで既に時間を計測している場合は、その値を直接報告できます。

Framedash->ReportMapLoad(TEXT("Level_01"), 1234.0); // ロード時間(ミリ秒)

ReportMapLoad は、ロード時間が NaN、無限大、または負の値のとき、そのサンプルを丸ごと破棄します(クランプはしません)。

どちらの経路も、metrics["load_time_ms"]attributes["map_name"] を持つ map_load イベントを送出します。 このイベントは意図的に map_id を空にしているため、空間ヒートマップとアクティベーションゲートの対象外になります。 これらの呼び出しはゲームスレッドで実行され、例外を投げず、初期化の前は何もしません。 カスタムローダーやストリーミングローダーがワーカースレッドで完了する場合は、EndMapLoadReportMapLoad を呼ぶ前にゲームスレッドへ戻してください(たとえば AsyncTask(ENamedThreads::GameThread, ...) を使います)。 SDK はスレッドの受け渡しを代行しないため、別スレッドからの呼び出しはイベントを無言で破棄します。

UE5 SDK 0.1.6 以降で利用できます。 SDK はディスク読み取りのカウンターを、io.read_bytesio.read_time_msio.read_ops というメトリクスキーで perf_heartbeat イベントに付与できます。 各値は前回の heartbeat からの差分で、実際にサンプルが取得できてから初めてキーが付きます(ゼロ埋めはしません)。 他のパフォーマンスメトリクスと同様に、io.* は perf-diff / builds-compare のリグレッションゲートとダッシュボードのチャートに使われます。 io.* のしきい値アラートはありません。

自動サンプリングはオプトインです。 Project Settings > FramedashTrack Disk IObTrackDiskIo、既定はオフ)を有効にすると、SDK は同期的なディスク読み取りを数える IPlatformFile ラッパーを連結します。 IoDispatcher / IoStore の経路(zen loader、Nanite ストリーミング)が処理する読み取りはこのラッパーを迂回するため、Nanite が多い I/O ではカウンターが少なめに出ます。

ReportIoSample は Blueprint から呼び出せ、この設定に関係なくサンプルを供給します。

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
Framedash->ReportIoSample(/*Bytes=*/1048576, /*ReadTimeMs=*/3.2, /*Ops=*/12);
}

UE5 SDK 0.1.7 以降で利用できます。 Track Memory DetailbTrackMemoryDetail、既定はオフ)を有効にすると、SDK は heartbeat の周期でメモリカテゴリ別の使用量をサンプリングし、perf_heartbeat イベントに mem.* メトリクスとして付与します。

  • mem.vram:RHI が報告する使用中のテクスチャメモリ(バイト、ストリーミング + 非ストリーミングのテクスチャ割り当ての合計)。RHIGetTextureMemoryStats から読み取り、特別な起動フラグなしにどの RHI でも利用できます。ヘッドレス / -nullrhi ビルドでは付与されません。
  • mem.textures / mem.meshes / mem.audio:Low-Level Memory トラッカー(LLM)の各タグのバイト数。LLM がビルドに組み込まれ、かつ -llm 付きで起動された場合にのみ付与されます。LLM が無効なときは mem.vram のみが付きます。

追跡されていないカテゴリはキー自体が現れません(未収集を意味し、収集された 0 とは区別されます)。

これらのキーは perf_heartbeat に加えて、位置情報付き(map_id が空でない)イベントにも付与されます。perf_heartbeatmap_id が空で空間ヒートマップのグリッドに入らないため、セルごとのメモリヒートマップを作れるよう、同じサンプルを位置情報付きイベントにも載せます。 位置情報付きイベントに載るのは 10 秒周期の heartbeat で更新されるキャッシュ済みサンプルで、イベントごとのサンプリングは発生しません。 TrackWithDatametrics マップで自分の mem.* キーを渡した場合は、そちらの値が優先されます。

有効化は Project Settings > Plugins > Framedash > Track Memory Detail、または Config/DefaultGame.inibTrackMemoryDetail=True で行います。 既定はオフで、既定のセッションはゼロアロケーションのイベント経路を維持します。 mem.vram は perf-diff(ビルド比較)の比較対象メトリクスにもなります。

エディター内クラウドヒートマップ

Section titled “エディター内クラウドヒートマップ”

UE5 SDK 0.1.7 以降で利用できます。 プラグインの FramedashEditor モジュールは、クラウドで集計済みのヒートマップをエディター内に取得・表示する Framedash Heatmap タブを追加します。 Window メニュー > Framedash > Framedash Heatmap から開きます。

はじめに Project Settings > Plugins > Framedash Heatmap で、読み取り用 API キー(Read API Key、analytics:read スコープ)とプロジェクト ID(Project ID)を設定します。 API Base URL の既定値は https://app.framedash.dev です。

UE5 SDK 0.1.11 以降では、Read API Key を空のままにして、Unreal Editor を起動する前に FRAMEDASH_ANALYTICS_API_KEY を設定できます。環境変数の値はエディター設定へ保存されません。Project Settings に Read API Key を入力した場合は、その値が環境変数より優先されます。

パネルでは次の操作ができます。

  • マップ一覧の取得と選択
  • 期間(日数)、セルサイズ、イベント名フィルターの指定
  • クラウドからの集計済みヒートマップセルの取得
  • 取得したヒートマップ全体が収まるようにレベルビューポートをフレーミング

UE5 SDK 0.1.13 以降では、Play-in-Editor(PIE)以外の状態でデータを取得し、表示したい各レベルビューポートの Show > Framedash Heatmap を有効にします。Show フラグは既定でオフで、ビューポートごとに独立しています。プレイテストを妨げないようPIE中はヒートマップが一時停止し、PIE終了後に各ビューポートの以前の選択が復元されます。

計測済みZ座標を持つセルは、その高さにクラウドボクセルとして表示され、2Dレスポンスは平面のまま表示されます。ヒートマップはビューポートのメインシーンパスで描画されるため、通常のF9スクリーンショットと高解像度ビューポートスクリーンショットの両方に写ります。

SDK は LogFramedash カテゴリにログを出します。 統合中に送信を確認するには、詳細ログを付けてゲームを起動します。

-LogCmds="LogFramedash Verbose"

コンソールから Log LogFramedash Verbose で実行時に有効化することもできます。 送信時は SendBatch: N events -> https://ingest.framedash.dev/v1/events に続けて HTTP の結果を記録します。 イベントが届かない場合はトラブルシューティングを参照してください。

対話的なエディターセッションなしでゲームを実行するには(CI や検証のため)、まずエディターターゲットをビルドし、その後 null RHI でゲームを起動します。

プラグインを追加したら、コマンドラインからエディターターゲットをビルドします。 エディター UI は不要です。

"<EngineRoot>\Engine\Build\BatchFiles\Build.bat" <ProjectName>Editor Win64 Development -Project="<full path>\<ProjectName>.uproject"

続いて、null RHI でゲームモードを起動します。 <MapPath> は実在するフルマップパスに置き換えてください。 Third Person テンプレートでは、UE 5.3〜5.5 が /Game/ThirdPerson/Maps/ThirdPersonMap、5.6 以降が /Game/ThirdPerson/Lvl_ThirdPerson を提供します。

UnrealEditor-Cmd.exe <Project>.uproject <MapPath> -game -nullrhi -nosound -unattended -nosplash -stdout

-game は終わりのないゲームループを開始し、自分では終了しません。 CI では外部のタイムアウトやプロセス kill で実行を打ち切り、プロセスの終了ではなくログの HTTP 2xx 行を成功の合図として扱ってください。 -unattended-nosplash を付けると、実行が非対話的になります。

ゲームは自分で終了しないため、フラッシュが完了する時間を確保したうえでプロセスを kill するタイムアウトで起動を包んでください。 最小構成の PowerShell ラッパー例:

Terminal window
$fdArgs = '"<Project>.uproject"','"<MapPath>"',"-game","-nullrhi","-nosound","-unattended","-nosplash","-stdout"
$p = Start-Process -FilePath "UnrealEditor-Cmd.exe" -ArgumentList $fdArgs -PassThru
if (-not $p.WaitForExit(120000)) { $p.Kill() } # 120 秒で打ち切り。プロセスは自分では終了しない

パスの引数は埋め込みの二重引用符('"<Project>.uproject"')で囲んでいるため、空白を含むプロジェクトパスでも Start-Process の引数分割で壊れません。 Linux ランナーでは代わりに timeout 120 UnrealEditor-Cmd ... を使います。 kill の前に HTTP 2xx 行が記録される余裕を持たせて上限を設定してください。 GNU の timeout は実行を打ち切ると終了コード 124 を返すため、成功判定は終了コードではなくログの HTTP 2xx 行で行い、そのログ確認が通れば 124 は想定どおりとして扱ってください。 macOS には既定で GNU の timeout がありません。 coreutils を入れて(brew install coreutilsgtimeout を使うか、上の PowerShell と同じく遅延後に kill する方法で起動を包んでください。

-stdout をパイプやリダイレクトに渡すと、ストリームがブロックバッファリングされます。 そのため、すでに成功している実行が停止したように見えることがあります(たとえば Waiting on static mesh... で固まっているように見えても、HTTP 202 はすでに発生しています)。 確実な記録は Saved/Logs/<Project>.log です。 このログから SendBatch:Batch sent successfully (HTTP を grep してください。 これらの行は詳細ログが有効なときだけ出力されるため、起動時に -LogCmds="LogFramedash Verbose" を付けてください(上の詳細ログを参照)。 標準出力をリアルタイムに解析する必要がある場合は -FORCELOGFLUSH を追加します。

オフラインキューが書き込まれるのは、正常なシャットダウンか一時的な送信失敗のときだけで、強制終了では書き込まれません。 フラッシュが完了する前に実行が正常にシャットダウンした場合は、バッファされたイベントが Saved/Framedash/offline-queue.json に書き込まれ、次の初期化時にワールドが tick した時点で送信されます。 一方、強制的な kill ではバッファに残ったイベントが失われるため、CI ではキューに頼らず、プロセスを kill する前にログの HTTP 2xx 行を待ってください。 フラッシュが済むまで実行を保つか、もう一度実行してキューを排出してください。 詳細はトラブルシューティングを参照してください。

エディター内クイックスタートサンプル

Section titled “エディター内クイックスタートサンプル”

プラグインには、セットアップを確認するためのサンプルが Plugins/Framedash/Samples/InEditorQuickstart に同梱されています。 対応するコンパイル済みパッケージを使えば、Blueprint レシピは Blueprint-only プロジェクトで動作し、C++ のコンパイルは不要です。 すでに C++ モジュールを持つプロジェクトでは、代わりに同梱の C++ アクター(FramedashQuickstartActor)をコピーしてコンパイルできます。

このサンプルは 2 つの前提を想定しています。

  • events:write スコープを持つ Ingest API キー
  • ダッシュボードの Maps > Generate demo で登録した map_id

どちらの経路でもプレイ時にマップに紐づいた Track イベントが送信され、これがダッシュボードでプロジェクトを有効化するきっかけになります。

UFramedashSubsystemFramedash カテゴリで Blueprint から呼び出せるため、C++ を書かずに Blueprint グラフから有効化イベントを送れます。

  1. Level BlueprintBlueprints > Open Level Blueprint)を開き、Event BeginPlay ノードから始めます。
  2. Get Game Instance を引き出し、続いて Get Subsystem ノードを追加してクラスを Framedash Subsystem に設定します。この出力ピンが UFramedashSubsystem のインスタンスです。
  3. サブシステムのピンから Track(カテゴリ Framedash)を呼び出します。Event Namequickstart_ping などに、Map Id を生成した map_id に、Position をレベル内の任意の位置(たとえば Player Start の位置)に設定します。attributes / metrics も付けたい場合は代わりに Track With Data を使います。
  4. Event BeginPlayTrack の呼び出しにつなぎ、プレイ時に実行されるようにします。

Play を押すと、マップに紐づいた Track イベントがダッシュボードでプロジェクトを有効化します。

自動テストやプロファイリング実行では、セッション全体にタグを付け、各イベントが CI のビルドとその branch / commit / scenario を持つようにします。 起動時に、自動セッション API を一度だけ呼び出します(BuildIdBranchCommitScenario はいずれも任意の FString で、メソッドは Blueprint からも呼び出せます)。

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
Framedash->BeginAutomatedSession(
/*BuildId=*/TEXT("build-123"),
/*Branch=*/TEXT("main"),
/*Commit=*/TEXT("abc1234"),
/*Scenario=*/TEXT("nightly"));
// ... 自動シナリオを実行する ...
Framedash->EndAutomatedSession();
}

CI では BeginAutomatedSessionFromEnvironment() を使うと便利です。 これは framedash run-profile-test が書き出す環境変数 FRAMEDASH_BUILD_IDFRAMEDASH_GIT_BRANCHFRAMEDASH_GIT_COMMITFRAMEDASH_TEST_SCENARIO を読み取ります。

if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>())
{
Framedash->BeginAutomatedSessionFromEnvironment();
// ... 自動シナリオを実行する ...
Framedash->EndAutomatedSession();
}

自動セッションは、セッション内のすべてのイベントに build_id の上書きと ci.branch / ci.commit / ci.scenario 属性を付与します。 これがビルド比較(perf-diff)の CI ゲートに使われます。 イベントの source は変わりません。 SDK 自身の自動イベント(session_startperf_heartbeat)は source=automated のまま、Track イベントは source=player のままで、これは CI でも通常のプレイでも同じです。 パイプライン全体は CI プロファイリング を参照してください。