I recently attempted to use the InlineGeneratedCpps mode in UBT in 5.6.1, which worked quite well. However,
When I attempted to set CppCompileWarningSettings.NonInlinedGenCppWarningLevel = WarningLevel.Error; in a module that had been converted but had an issue, it did not cause an error, nor warning, but a log line and build success. It’s doing a LogWarning in UBT, but perhaps anything short of a build exception is downgraded to a regular log.
Why did it have anything to print at all? Looking at the UBT mode, it checks for the presence of a UENUM in the header and skips it if present, with the comment “We can’t inline the gen.cpp when the header is using an enum”. Why not?
The UBT warning/error/log does not check this, so the file it claimed should be using an inlined cpp pairs with a header that’s full of UENUMs. Adding the suggested statement anyway seems to compile fine, but I don’t know what the implications might be for the build mode to have skipped these.
So I’m wondering which thing is correct for UENUM usage. I wouldn’t be able to enable the error for our modules until I can resolve it one way or the other, since it will fail on any cpps in this situation.
As an aside, how come more modules don’t enable this warning. The only one I see having set it in 5.6 is AutoRTFM, despite many modules having these inline statements. Is the plan to eventually enable the errors for all engine modules?
CL#47030988 addresses the problem when Errors are not properly handled.
I contacted the engine team regarding UENUMs being a cause for exclusion. The person that made that decision is not here anymore and the current team members don’t see a reason for it. You should try to get rid of the code that excludes those files.
At this point, there is no plan force inlining of the gen.cpp files.
I made some internal searches and I could find it’s a YMMV situation. The main benefit seems related to forward declaration but nothing concrete. I did find recommendations to profile the build times before changing.
The team was surprised by the worse compilation time. The generated code is simply inlined in the cpp. This should benefit from the PCH and\or the includes that are in the original cpp. The code has to be compiled so it’s unclear why doing it in a “standalone” way would be faster. Can you make sure that you are not running into paging related slowdowns? If you are using UBA, the pre-5.7 version can spawn too many processes which will result in paging at the OS level. This will slow things down and can even result in crashing some compilation processes when “running out of RAM”. I would recommend limiting the number of local compilation processes to RAM/3 when doing your test. The newer code will check the amount of free RAM and should be smarter when spawning processes.
If I’m not mistaken, the ‘Empty Standby list’ is the option that clears the cache. I you ended up paging, the disk cache would have been evicted when the RAM pressure went up. It’s really hard to get a pure measurement here.
Thanks for the advice and the CL to pull. I tried removing the code excluding those files, and everything compiled fine when those files were inlined, so I wanted to give you confirmation that it appears not to be needed.
I wanted to ask one more thing, though. As a test of this feature, I inlined the generated cpps for all of our studio’s engine-layer plugins, which came out to 452 cpp files. When I rebuilt the Editor for our game with remote compilation off (as a fair test), the compile time got about 10% worse (29.5 min to 32.3 min). There might be some variance there to account for other factors, but at best it did not improve the time. The only real release note about this macro in 5.1 said “This improves compile times because less header parsing is required.” So I figured I would mention that wasn’t the case in my testing, and I wondered if you had any tips or ideas why that might be the case. I did not try it on our actual game code, but these initial results don’t make me feel the need to unless there is a meaningful difference there. Thanks!
This test was using 5.6 UBA, but I disabled the remote executor for the test (and disabled my workstation as a helper) so that it would not be influenced by how many remote agents were available or which units they compiled. I believe as of 5.6, the local UBA executor will do a number of parallel actions that matches the physical core count for hyperthreaded cores - so for me, it was 32 actions on a 32 physical/64 logical core machine. It has 128 GB of RAM, and a very large pagefile to avoid the “out of RAM” issue.
One possible explanation could be that my test was to do “.build editor --full” with the inlined cpps, record the time, revert the changelist, and do “.build editor --full” again. Perhaps the first compilation caused the files to be cached/warm in the Windows filesystem, such that the second compile was shorter just on overall disk access time. But my thought is that even if I ran into paging-related slowdowns, the results between the two tests should have been consistent in their paging. Or, if it’s possible that the inlined cpps cause more paging issues, that would be a different downside. Either way, we were similarly surprised that the test was not a clear win.
Perhaps an engineer at Epic could make the same change to not exclude headers with UEnums and run InlineGeneratedCpps over something like Fornite or Lyra and gather some non-distributed compile times to see if my results are reproducible. I also wonder if there is any difference in Editor vs. Game targets - I only tried Editor, but maybe there could be a difference with monolithic targets. Just guessing at possibilities.