Generating .pgd File for Windows PGO in Unreal Engine

Hi, I’m currently working on generating PGO data for our Unreal project on Windows. However, I’ve encountered an issue during the .pgd file generation step. Here’s the process I’m following:

1. Compile the game with UBT using the following arguments:

-LTCG -ThinLTO -PGOProfile2. Run the game using Gauntlet with a custom PGONode:

​ClientRole.CommandLine += "-pgoprofile" ​ClientRole.CommandLine += "-ExecCmds=\"automation List;RunTests StartsWith:Plugin+StartsWith:_Game+StartsWith:Project.Functional Tests;Quit\""3. After successful execution, ${PROJECT_NAME}!1.pgc is generated at ${PROJECT_ROOT}\Platforms\Windows\Build\PGO

4.Then I try to generate the .pgd file with pgomgr.exe:

${PROJECT_ROOT}\Saved\StagedBuilds\Windows\${PROJECT_NAME}\Binaries\Win64\pgomgr.exe /merge:1 *.pgc MyGame.pgdBut I receive the following error:

PGOMGR : fatal error PG0081: Unable to open file 'MyGame.pgd' for reading.Any suggestions or guidance would be greatly appreciated. Am I missing a step here?

Hello,

The pgomgr documentation doesn’t discuss the support of wildcards for the PGC files.

I recommend trying the merge command by specifying the full PGC name or not specify any file which should result in merge all files in the folder.

Regards,

Martin

Are you sure that you are using the right pgomgr exe? Each toolchain comes with its own version. I would recommend that you call the pgomgr through the full path for the toolchain that was used to compiled the game.

Version 5.5 will use toolchain 14.38 if it’s installed but will default to the lastest installed version if it’s not there. You can refer to the compilation log to know which toolchain was used. Search for an entry that looks like this:

Using Visual Studio 2022 14.38.33141 toolchain (C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130) and Windows 10.0.22621.0 SDK (C:\Program Files (x86)\Windows Kits\10).

You can find the officially supported toolchain and SDK for each platform in the json files that are under each platform;s Config folder. The Windows info is in Engine\Config\Windows\Windows_SDK.json

I recommend that you install the recommended toolchain and Windows SDK so you use the same we QA’ed.

I contacted the Fortnite team to ask for advice and they suggest you try using full paths such as:

D:\build\<...>\pgomgr.exe /merge D:\build\<...>/YourProjectClient-Win64-Shipping.pgd

Regarding Clang, it is an option for the Windows client. The UBT code fully supports it the version you are using and we are aware of licensees that are already using it. They are reporting faster compilation times and runtime performance improvements but the generated executable is a bit bigger than with VS. You can check in Engine\Config\Windows\Windows_SDK.json to find the supported Clang version for any engine release. We do have regular compilation jobs to validate that the code compiles with Clang for the Windows target but we are not running extensive tests. Things should be fine based on licensee reports.

We can’t really comment on the reason why the Windows code doesn’t merge the data when gathering it as it’s been a while. Although, this makes a fair case for a feature request so that all platforms work the same way. I will log it in our systems.

Regarding the file open issue, have you considered it could be related to anti-virus or other file scanning software? You can try using a monitoring tool such as ProcMon to capture systems calls related to the PGD file. https://learn.microsoft.com/en\-us/sysinternals/downloads/procmon

You should filter on file with the PGD extension which should result in a list of operations.

You seem to have filtered on pgomgr.exe which would not collect interference from other tools\processes. I recommend filtering on Profile.pgd to eliminate the possibility of issues related to a security\audit software.

The command line in the log does appear correct based on the tool doc: https://learn.microsoft.com/en\-us/cpp/build/pgomgr?view\=msvc\-170

Did you move the PGD file that is produced at compile time to the location of the PGC files? It should be under <Project>\Binaries\Win64

We have the same problem regarding the performance of the instrumented builds and we also rely on Replays\Gauntlet. The process is time consuming by nature so most teams that use it wait for the end of the project.

For a specific state of the code base, you can merge multiple runs of profiling into the PGD file. You can have multiple replays that you profile and merge. (per level, per game mode…)

As the PGD is generated from a specific state of the code base. It can go stale really quickly as the code is evolving. It’s best to regularly flush the data and do some new profiling sessions to ensure that the data collected still reflect the current behavior of the code.

Martin

Hi, thank you for your help. I’ve also tried running the following commands to merge the

.pgc file—using both relative and absolute paths, with and without explicitly specifying the

.pgc filename—but none of them worked.

```

Directory of D:\Dev\MyProj\UE\MyGame\Platforms\Windows\Build\PGO

06/26/2025 12:03 PM <DIR> .

06/26/2025 11:42 AM <DIR> ..

06/26/2025 11:55 AM 144,392,192 MyGame-Win64-Test!1.pgc

```

Here are the commands I attempted, along with the corresponding error from

pgomgr.exe:

```

pgomgr.exe /merge test.pgd

# PGOMGR : fatal error PG0081: Unable to open file ‘test.pgd’ for reading.

pgomgr.exe /merge:1 test.pgd

# Same error

pgomgr.exe /merge MyGame-Win64-Test!1.pgc Test.pgd

# Same error

pgomgr.exe /merge:1 MyGame-Win64-Test!1.pgc Test.pgd

# Same error

pgomgr.exe /merge:1 MyGame-Win64-Test!1.pgc ./Test.pgd

# Same error

pgomgr.exe /merge:1 D:\…\MyGame-Win64-Test!1.pgc D:\…\MyGame-Win64-Test.pgd

# Same error

```

It seems the tool is unable to read or create the .pgd file regardless of how the inputs are specified. I’d appreciate any insights or suggestions.

I’m currently using version 14.38.33130, which is eventually copied into the Saved\StagedBuilds\Windows\${ProjectName}\Binaries\Win64 folder through the PrepareRuntimeDependencies function in VCToolChain.cs.

I’ve also tried using other versions of pgomgr.exe within the MSVC toolchain, but they all result in the same error.

[Image Removed]

I’m considering switching to the Clang compiler for our Windows build instead of MSVC. For our previous game title, I successfully generated profile.profdata for the PS5, Switch, iOS, and Android PGO builds using Clang.

Do you have any recommendations or foresee any potential issues with adopting Clang for the Windows build as well?

Thanks in advance!

Thank you for the response.

I’ve already tried various combinations of relative and absolute paths, but I still get the same error:

PGOMGR : fatal error PG0081: Unable to open file.

I’m also a bit curious—why doesn’t the WinBasePGOPlatform::GatherResults function run the MergeCommand

directly like it does for other Clang-based platforms?

I tried using Process Monitor to trace the system calls, and noticed that pgomgr.exe attempts to read the .pgd file instead of creating it. That behavior seems a bit mysterious to me, especially since the .pgd file doesn’t exist yet.

I’ve attached the full log file from ProcMon for reference

Thanks

"10:42:42.1752038 PM","pgomgr.exe","58084","CreateFile","E:\PGO\Profile.pgd","NAME NOT FOUND","Desired Access: Generic Read, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, AllocationSize: n/a"

I’ve attached a Process Monitor log file that filters events related to

Profile.pgd.

HI, I wasn’t aware that running a PGI build generates a .pgd file under <Project>\Binaries\Win64. After relocating the .pgd file to the directory containing the .pgc files, I was able to merge them using pgomgr.exe successfully.

​We’re currently using the following compiler flags for PGI builds:

-LTCG -ThinLTO -PGOProfile

At runtime, the log reports:

LogInit: This binary is optimized with LTO: yes, PGO: no, instrumented for PGO data collection: yes

The resulting performance makes manual gameplay virtually impossible. While some slowdown is expected due to PGI instrumentation, the degradation on Windows is significantly more severe than on other platforms.

For comparison, our PGI test build on PS5 maintains approximately 30 FPS for our game, whereas the Windows equivalent drops to just 1–2 FPS.

I’ve attached a screenshot from Unreal Insights to illustrate the performance behavior.

To work around this limitation, I’m relying on the replay system or Gauntlet AutomationTests to drive profiling flow. However, the extremely low frame rate makes the overall process considerably time-consuming.

Is this dramatic slowdown a known limitation of PGI on Windows? If so, are there recommended mitigations?

Additionally, I’d appreciate clarification on the lifecycle of the .pgd file generated by PGI builds. Should it be treated as a persistent “base” profile reused across future merges? Or is it expected to be regenerated for each profiling run? Would running pgomgr.exe /clear before merging profiles help avoid outdated or conflicting data?