UE5 SDK
說明如何使用 Framedash UE5 SDK(C++ 外掛程式)自動收集效能遙測資料。
- Unreal Engine 5.3 以上
- 純 Blueprint 專案可使用相符的預先編譯套件;從原始碼建置需要 C++ 專案與工具鏈
對於純 Blueprint 專案,請使用 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接著將其加入專案:
- 將外掛程式放置於
Plugins/Framedash目錄 - 在
.uproject中新增:
{ "Plugins": [ { "Name": "Framedash", "Enabled": true } ]}- 如果專案包含 C++ 模組並從 C++ 呼叫外掛程式,請在該模組的
Build.cs中加入相依性:
PrivateDependencyModuleNames.Add("Framedash");- 使用原始碼外掛程式、原始碼建置的引擎或預先編譯套件未涵蓋的目標時,重新建置專案
方法 A:自動初始化(建議)
Section titled “方法 A:自動初始化(建議)”在 DefaultGame.ini 中新增以下內容,子系統將在啟動時自動初始化:
[/Script/Framedash.FramedashSettings]ApiKey=your-api-keybAutoInitialize=True也可以設定可選欄位,如 BuildId、SamplingRate 和 PlayerId:
[/Script/Framedash.FramedashSettings]ApiKey=your-api-keybAutoInitialize=TrueBuildId=1.0.0SamplingRate=1.0PlayerId=player-123PlayerId 是開發者提供的玩家識別碼。若留空,事件將以匿名方式傳送,且 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++ 初始化程式碼。
方法 B:透過 C++ 手動初始化
Section titled “方法 B:透過 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 還接受可選的 EndpointUrl 和 BuildId 參數,在 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);}自動收集資料
Section titled “自動收集資料”初始化完成後,以下資料將自動收集:
- 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 呼叫。
地圖載入耗時擷取
Section titled “地圖載入耗時擷取”自 UE5 SDK 0.1.6 起可用。子系統可以測量關卡載入所需的時間,並將其作為 map_load 事件回報,進入建置比對(perf-diff)迴歸閘門以及儀表板的載入耗時圖表。BeginMapLoad、EndMapLoad 和 ReportMapLoad 都可從 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); // 載入耗時(毫秒)當載入耗時為 NaN、無限大或負值時,ReportMapLoad 會整個丟棄該樣本(不會夾限)。
兩條路徑都會發出攜帶 metrics["load_time_ms"] 與 attributes["map_name"] 的 map_load 事件。該事件刻意將 map_id 留空,因此不會進入空間熱力圖和啟用閘門。這些呼叫在遊戲執行緒上執行,不會擲出例外,且在初始化之前為無操作。當自訂載入器或串流載入器在工作執行緒上完成時,請在呼叫 EndMapLoad 或 ReportMapLoad 之前先切回遊戲執行緒(例如藉由 AsyncTask(ENamedThreads::GameThread, ...))。SDK 不會替你進行執行緒封送,從其他執行緒發起的呼叫會靜默丟棄該事件。
磁碟 I/O 指標
Section titled “磁碟 I/O 指標”自 UE5 SDK 0.1.6 起可用。SDK 可以把磁碟讀取計數器以 io.read_bytes、io.read_time_ms、io.read_ops 這幾個指標鍵附加到 perf_heartbeat 事件上。每個值都是相對上一次 heartbeat 的增量,而且只有在真正擷取到樣本之後這些鍵才會出現(不會填零)。與其他效能指標一樣,io.* 會進入 perf-diff / builds-compare 迴歸閘門以及儀表板圖表。io.* 沒有閾值警示。
自動取樣是選擇性開啟的。在 Project Settings > Framedash 中啟用 Track Disk IO(bTrackDiskIo,預設關閉),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);}記憶體分類指標
Section titled “記憶體分類指標”UE5 SDK 0.1.7 及更新版本可用。啟用 Track Memory Detail(bTrackMemoryDetail,預設關閉)後,SDK 會按 heartbeat 週期取樣各記憶體分類的用量,並作為 mem.* 指標附加到 perf_heartbeat 事件上:
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_heartbeat 的 map_id 為空、不會進入空間熱力圖網格,SDK 會把同一取樣也放到帶位置的事件上,從而支援逐格的記憶體熱力圖。帶位置的事件攜帶的是按 10 秒 heartbeat 週期更新的快取取樣,不會發生逐事件取樣。若你在 TrackWithData 的 metrics 對應中傳入自己的 mem.* 鍵,則以你的值為準。
在 Project Settings > Plugins > Framedash > Track Memory Detail 啟用,或在 Config/DefaultGame.ini 中設定 bTrackMemoryDetail=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
Section titled “無頭 / CI”要在沒有互動式編輯器工作階段的情況下執行遊戲(用於 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 包裝範例:
$fdArgs = '"<Project>.uproject"','"<MapPath>"',"-game","-nullrhi","-nosound","-unattended","-nosplash","-stdout"$p = Start-Process -FilePath "UnrealEditor-Cmd.exe" -ArgumentList $fdArgs -PassThruif (-not $p.WaitForExit(120000)) { $p.Kill() } # 120 秒上限;行程不會自行終止路徑引數用內嵌雙引號('"<Project>.uproject"')包裹,因此包含空格的專案路徑也不會在 Start-Process 引數拆分時損壞。在 Linux runner 上改用 timeout 120 UnrealEditor-Cmd ...。請為上限留出足夠餘裕,讓 HTTP 2xx 行在 kill 之前落地。GNU timeout 在終止執行時會以狀態碼 124 結束,因此請以記錄中的 HTTP 2xx 行而非結束碼作為成功判準,記錄檢查通過後將 124 視為預期結果。macOS 預設沒有 GNU timeout:安裝 coreutils(brew install coreutils)並使用 gtimeout,或用上面 PowerShell 那樣的延遲後 kill 的方式包裹啟動。
當你對 -stdout 做管線或重新導向時,該串流是區塊緩衝的,因此一次已經成功的執行可能看起來卡住了(例如停在 Waiting on static mesh...,但 HTTP 202 其實已經發生)。權威記錄是 Saved/Logs/<Project>.log;在其中 grep SendBatch: 和 Batch sent successfully (HTTP。這些行只有在開啟詳細記錄時才會出現,因此啟動時請加上 -LogCmds="LogFramedash Verbose"(見上文詳細記錄)。如果必須即時解析 stdout,請加上 -FORCELOGFLUSH。
離線佇列只在正常關閉或暫時性傳送失敗時寫入,強制 kill 時不會寫入。如果執行在傳輸完成清除之前正常關閉,緩衝的事件會寫入 Saved/Framedash/offline-queue.json,並在下次初始化、世界開始 tick 後傳送。相反,強制 kill 會遺失仍在緩衝中的事件,因此在 CI 中不要依賴佇列,請在 kill 行程之前等待記錄中的 HTTP 2xx 行。請讓執行保持足夠長以完成清除,或再執行一次以清空佇列。見疑難排解。
編輯器內快速開始範例
Section titled “編輯器內快速開始範例”外掛程式在 Plugins/Framedash/Samples/InEditorQuickstart 附帶了一個用於驗證設定的範例。使用相符的預先編譯套件時,Blueprint 方案可在純 Blueprint 專案中運作,無需編譯 C++。已有 C++ 模組的專案也可以複製並編譯隨附的 C++ Actor(FramedashQuickstartActor)。
此範例假定兩個前提:
- 具有
events:write範圍的 Ingest API 金鑰 - 透過儀表板 Maps > Generate demo 註冊的
map_id
兩條路徑在執行時都會傳送一個綁定地圖的 Track 事件,這正是在儀表板中啟用專案的觸發條件。
Blueprint 方案
Section titled “Blueprint 方案”UFramedashSubsystem 在 Framedash 類別下可從 Blueprint 呼叫,因此你無需撰寫任何 C++,即可從 Blueprint 圖表傳送啟用事件:
- 開啟 Level Blueprint(Blueprints > Open Level Blueprint),從 Event BeginPlay 節點開始。
- 從 Get Game Instance 拖出,再加入一個 Get Subsystem 節點並將其類別設定為 Framedash Subsystem。該輸出接腳就是
UFramedashSubsystem執行個體。 - 從子系統接腳呼叫 Track(類別 Framedash)。將 Event Name 設為類似
quickstart_ping,將 Map Id 設為你產生的map_id,並將 Position 設為關卡內任意位置(例如 Player Start 的位置)。若還想附加attributes/metrics,請改用 Track With Data。 - 將 Event BeginPlay 連到 Track 呼叫,使其在執行時執行。
按下 Play,綁定地圖的 Track 事件即會在儀表板中啟用專案。
CI / 自動工作階段
Section titled “CI / 自動工作階段”在自動化測試或效能剖析執行中,請為整個工作階段打標籤,使每個事件都攜帶 CI 建置及其 branch/commit/scenario。在啟動時呼叫一次自動工作階段 API(BuildId、Branch、Commit、Scenario 均為選填的 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_BUILD_ID、FRAMEDASH_GIT_BRANCH、FRAMEDASH_GIT_COMMIT 和 FRAMEDASH_TEST_SCENARIO(這些正是 framedash run-profile-test 匯出的變數):
if (auto* Framedash = GetGameInstance()->GetSubsystem<UFramedashSubsystem>()){ Framedash->BeginAutomatedSessionFromEnvironment(); // ... 執行自動化情境 ... Framedash->EndAutomatedSession();}自動工作階段會為工作階段內的每個事件標上 build_id 覆寫和 ci.branch / ci.commit / ci.scenario 屬性,這正是進入建置比對(perf-diff)CI 閘門的依據。它不會改變任何事件的 source:SDK 自身的自動事件(session_start、perf_heartbeat)始終是 source=automated,而你的 Track 事件始終是 source=player,在 CI 與正常遊玩中都一樣。完整流水線見 CI 剖析。