Every change I make to my code base results in a compiler run and domain reload that’s long enough for me to take a bathroom break. Here are some specific facts:
I’m using Ubuntu MATE 20.04.
I’m using Unity 2020.1.1f1.
My editor is JetBrains Rider 2020.1.4.
My CPU is a Intel Core i7-4810MQ CPU at 2.80GHz.
I have 32GB of RAM.
Both Unity and my project are installed on a ext4-formatted SSD.
There are 192 asmdef’s in my project, broken down as follows:
114 of these come from UPM packages. Not all of these are actually used by my project; a lot are editor tools or samples bundled with packages.
37 of these come from in-source assets not available as UPM packages.
41 of these are from my own game’s code.
I use asmdef’s very liberally; I don’t even use the built-in assemblies (Assembly-CSharp.dll, etc.).
My project weighs about 264MB worth of in-source assets (i.e. excluding UPM packages but including Asset Store purchases), and is small enough in scope that it can reasonably be a solo project.
I’ve attached a list of all of my project’s script files, excluding third-party assets. (The specific log I’ve attached excludes .meta files, but they’re all there.)
The largest assembly in my project is called CorundumGames.Chromavaders.dll. Here are some facts about it:
It has a lot of dependencies and itself is a dependency for a lot of other assemblies.
It contains the vast majority of my game’s generated code.
Due to some of the code generator’s peculiar design decisions, this assembly is difficult to break apart.
Making a small change to this assembly results in a 35-second cycle, recompiling both the assembly itself and its dependents. I’ve attached the profiler’s output.
And this is all before I try to enter Play Mode.
This is starting to become asinine, and is already severely impacting my productivity. What can I do to get iteration times as brief as possible without immense changes to my workflow or project structure?
This isn’t a solution per se but rather an approach I have used when iterating with massive codebases: just turn off the auto-compile feature while you’re editing and playing back and forth.
When you’ve got the code ready for the next iteration, hit Assets->Refresh (generally ctrl- or cmd-R) and off you go for the 35-second compiler tax.
NOTE: to have the Auto Refresh setting respected, you actually have to close and reopen Unity, which is a mild facepalm in itself. There should be a popup notifying you this, because the setting appears to fail to work.
Short of redesigning your architecture, there’s nothing you can do other than maybe upgrading to the fastest CPU you can find.
For Unity 2020.2 they are working on incremental compilation so dependent assemblies will be recompiled only if there are changes to their dependencies public interfaces, at least.
It’s more about trimming your dependency chain. No assembly should depend on your “game” assembly, it should only consume other assemblies. If you have another assembly that needs to interact with things in your game assembly, you could always create a 3rd assembly just to hold the interface used for communication between the two. Some classes in your game assembly implement these interfaces, and register themselves with the “intermediate” assembly so they can be accessed by the other assembly. Delegates are also another tool for allowing another assembly to call back into your game assembly without depending on it.
The idea is to not have any assembly depend on assemblies which are being iterated on constantly. The high-iteration assemblies should just consume other assemblies.
@fherbst 's compilation visualizer has actually been a lot more useful than the EIP. It gives me a much more intuitive overview of where the time is being spent. Assembly compilation is in reality quite reasonable. Reloading, however, is abhorrent. Check this out. I made a single change to an assembly that has a lot of dependencies, but itself is not a dependency.
Five minutes for a domain reload every time I save my code? And that whole time, the Unity editor is frozen. I can’t even make changes to my game’s data.
My environment is still the same, except now I’m on Unity 2020.1.3f1 and Rider 2020.2.1.
That being said, for understanding how that reload time is spent EIP is very helpful and broken down nicely. From my initial observations it seems that some packages “misbehave” and do a ton of work on each reload; that includes Burst, ShaderGraph and a few others. Still trying to figure out how to best report bugs for these.
(btw, at some point in the future I hope to get to adding the EIP data into the visualizer - in the meantime, EIP can export to e.g. chrome tracer for a workaround visual view)
To the actual problem at hand: would it be possible for you to try in 2019.4? In my tests 2020.1 and 2020.2 have HUGE regressions in terms of assembly reload time, up to 10x compared to 2019.4 in some projects. Would be interesting if you see the same behaviour.
I don’t think it’s just UpdateAllMenus, otherwise there wouldn’t be an unexplained order of magnitude. Let’s suppose that it’s the latter; how can I figure out which function calls are guilty?
Yeah, it’s unlikely that a single function body eats away that much time without calling other functions, so it’s probably calling into unprofiled areas. Is it possible to enable deep profiling with EIP? That would be the only way to drill further.
There’s a button in the EIP UI to enable Deep Profiling - but at 200s of code execution you might need a loooooot of memory (like, at least 64 GB), but it’s worth a try.
Also I found that “User Code” button there sometimes reveals additional interesting data (I’m not sure what it’s supposed to do; the view is different afterwards but definitely not only user code).
Yes, please do, and post the case number here! You can also reference Case 1272396 (which is my report for slow compilation times but I don’t think the time there is spent in UpdateAllMenus).
Yep, just go to “Help > Report a Bug” and explain what QA needs to do to reproduce the slow times. Also helps to include some screenshots (I usually do that in a follow-up mail since the Bug Reporter UI is ridiculous)