Multiple teams in Unity have been working on improving iteration time of player builds the past few releases. You should have noticed faster IL2CPP builds during the 2020 release cycle and even more improvements are coming in 2021.
To this end, we have been working on a new option for IL2CPP that generates much less code (up to 50% less). This allows for both faster iteration times and smaller executable files. There may be a small runtime performance impact due to the different code generation.
This graph shows improvements to compile times with this option enabled:
We are asking that you try out this new option with your IL2CPP builds. We want to know if you see real world performance issues when running with this option. Also, let us know if the builds are faster and smaller.
Note: This is available in alpha builds only, from 2021.2.0a17 onward.
How to Enable: Change the āIL2CPP Code Generationā setting drop down in the Build Player window to āFaster (smaller) buildsā. The default and previous behavior is the āFaster runtimeā setting.
Any difference in FPS or startup your applications see when running with this option enabled.
The profile.json file in the generated IL2CPP C++ output folder (next to build output folder) for builds with and without this option. You can also send for cold and warm (incremental) builds. This allows us to see where build time is being spent and saved.
You can also send stats on generated C++ output size and final binary size.
Respond to this thread with any questions or findings. Additionally, you can DM me if you have information you donāt want to share in public.
Sounds interesting!
Iām wondering a bit why you share detailed graphs about the build times but not about the possible performance regression. Weāre using a lot of generics so it would certainly be interesting which microbenchmarks show what slowdowns, and also how the above examples do in terms of performance. Mind sharing that?
I shared the build times as the benefits of this option are clear. It is unclear what the negative impacts are for real projects. When running test projects we didnāt see negative performance impact beyond ~10% of script time in a frame. Thatās why we are asking for more feedback, to have a larger sample size for finding regressions.
Here is an example microbenchmark:
public class EqualityComparerEnum
{
private MyEnum _enum;
private EqualityComparer<MyEnum> _comparer;
public EqualityComparerEnum()
{
var rand = new Random(12345);
_enum = (MyEnum)rand.Next(0, 3);
_comparer = EqualityComparer<MyEnum>.Default;
}
[Benchmark]
public void CallToEnumEqualityComparerGetHashCode()
{
_comparer.GetHashCode(_enum);
}
enum MyEnum
{
A,
B,
C,
D
}
}
This (the call to GetHashCode) runs an order of magnitude slower (~12x) with full generic sharing enabled.
Unfortunately, I donāt have any projects to really test the changes on but I just want to add my two cents.
Personally, Iād rather have longer build times for more performance. The Release setting could be close to final and faster with these new changes while Master could take longer but maximizes performance.
Presumably this will be a configurable setting. Especially because there is bound to be corner-case code where sharing generics proves to be very slow (like the micro-benchmark mentioned above).
Glad to see this! I would try this out if we were on the Alpha. Looking forward to seeing what other people observe.
I observed a shorter build time when trying this out, but I immediately get nullreferenceexception when I run the build (happening when loading an addresable scene). Building with mono works though.
So I have to say that Iād much rather it works than it being fast hehe
Unity 2019.4.21f1
Clean -
Build completed with a result of 'Succeeded' in 1431 seconds (1431279 ms)
Build completed with a result of 'Succeeded' in 468 seconds (467873 ms)
Build completed with a result of 'Succeeded' in 462 seconds (462387 ms)
Unity 2020.2.6f1
Clean - Build completed with a result of 'Succeeded' in 1052 seconds (1051999 ms)
Build completed with a result of 'Succeeded' in 136 seconds (135982 ms)
Build completed with a result of 'Succeeded' in 135 seconds (134927 ms)
Unity 2021.2.0a6.1011
Clean - Build completed with a result of 'Succeeded' in 681 seconds (681159 ms)
Build completed with a result of 'Succeeded' in 102 seconds (102462 ms)
Build completed with a result of 'Succeeded' in 105 seconds (105499 ms)
Iāve just ran some tests and got surprising results, in that building is SLOWER than before!
(Note: All builds are development builds, with ILC2PP configuration āmasterā)
Build Time
Build Size
I was quite careful in testing, making sure to close unity between each build (& after upgrading before making B.) so this is quite weird. Iāve also made some profiler snapshots for each build, Iāll send you a DM with those & some extra details (like the profile.json) later today.
Thanks for your testing of this @TimHeijden ! I took a look at your build profiler output and have a few thoughts.
I see you are building in master/āReleasePlusā build config. This enables LTO (link time optimization). While this may help performance, itās not something you want to iterate with as it is extremely expensive. It looks like 95% of your entire build time is the link event. Iād suggest Release for your daily work and itās something we should note more clearly to improve iteration.
I see you are using the VS 2017 toolchain. We have found the VS 2019 linker much faster. It may be something else to keep in mind when you can upgrade.
It seems like the āCā case didnāt pickup the environment variable. You will want to make sure it is set, and kill/restart Unity and Unity Hub.
If you have time and are interested in providing more data, I would suggest:
Just doing runs for āBā and āCā cases. This is the most interesting data points for this new option.
Use Release rather than ReleasePlus/master config.
Again, for āCā case make sure environment variable is set and all instances of Unity/UnityHub are killed to pick up new value
Do both clean (which is what your data seems to come from) and incremental builds. Tweak one line in a script and build again, as all things should be faster but we are mainly focused on this incremental use case.
Hey Jon, thanks for clarifying the main use case youāre looking for. I think Iāll do another test later today and otherwise next week. I had killed unity & the hub, so its strange that āCā didnāt pickup the environment variableā¦ will check more closely. (I had assumed it worked because the build time was so much shorter again)
As for building āReleasePlusā, I was already fully aware that its not really intended for iteration, but I was also very curious about the possible performance drop and thus thought Iād use the āoptimumā setting for that. Note that Iām also very much of the opinion that unity devs should be able to choose for the maximum runtime performance, especially when developing for slower platforms than PC and trying to hit a stable FPS, 10% extra performance cost for scripting is quite a lot!
In addition, I am indeed using VS2017. This is because some platforms require use of 2017 rather than 2019. Good to know that 2019 is faster though, will keep that in mind!
Couldnāt help myself, did it right away. This time I used the IL2CPP configuration āreleaseā instead, and also did cold/warm tests. All builds are using Unity 2021.1.0a8
I hope this time the environment variable stuck properly. Stats may be slightly skewed because I restarted my PC between no-env & env builds.
Iāve noticed faster builds lately (I generally update to the latest alpha when I notice it, or soon thereafter). Actually there have even been times I was like did it really finish already? For WebGL thatās a pretty big deal So yeahā¦ whatever youāre doing, thanks.
@joncham A very long moment is spent waiting for the Microsoft Incremental Linker. I noticed that this process is single thread. On console, we are wasting a considerable amount of time because of this. Would it be possible to analyze if you could use all available CPU cores? Thank you!