Does anyone use Assembly Definition files?

I posted a topic over in the Editor and General Support, but there hasn’t been any helpful response in a few days. ( Editor is extremely slow after adding Assembly Definitions ) I thought it might make more sense to ask something here.

The gist is, for every Assembly Definition file I add to my project, certain common actions in Unity run incrementally slower. Those actions include: Adding a new c# script, double-clicking a script to open in Visual Studio, moving a script from one directory to another, and other operations. Before I added any Assembly Definitions, doing these operations caused Unity to hang for 4-6 seconds, followed by a recompile. After adding 30-40 Assembly Definition files, that “hang” was up to about 17 seconds before it even started to compile.

Given this impact, it seems there should be very vocal complaints about asmdefs slowing down Unity, but I’m not really finding responses like that.

So what’s your experience? Is this typical? Or is it possible I’ve got something set up wrong that is causing this? I’ve read of people with a couple hundred asmdefs (many for test assemblies), and I expect that having that many asmdefs would result in 1+ minute delays performing various operations. Are you using assembly definitions? How many do you have in your project? And as anecdotal as this might be, how long does Unity lock up after adding a new c# script before it begins to compile? (You can get exact timing on that by looking at the Editor log, and looking for lines containing “Total AssetImport time:”)

1 Like

Why do you have 30-40 assembly definition files?

Now, I don’t know what exactly may be causing it since I don’t know the inner workings. But I wouldn’t be surprised that unity is having to recompile stuff, and that’s why it’s slowing down. For every assembly definition, that’s a new compiler action since it’s its own assembly. And those actions you describe like adding new C# scripts, moving scripts, and the sort. They usually require recompiling the assembly.

I know unity has released an incremental compiler, but I think it’s still considered beta and have read people having issues with it. But you can give it a try and see if it speeds things up.

But I go back to my question…

Why do you have 30-40 assembly definition files? Is that necessary?

I had in other project roughly 300 cs files, and around 30 ass def files.
Moving in and out is slow, but you don’t do that often.
However, I expected compilation to accelerate. That was not what I observed back then.
Only benefit from converting to asmd for me, was that I restructured the code, and removed circular references.

I know some people didn’t noticed compilation time improvement, while some had even slow down.
Other say they noticed improvement.
So this is all over the place, as far I am concerned. :wink:

One of affecting aspect, will be files locations in folders structure.
For example avoiding Resource folder with cs files.
But there is more to it.

There are actually three reasons I wanted to separate my project into (at least) 30-40 assembly definitions. Hopefully all of these seems reasonable:

  • I wanted to leverage the new Incremental Compiler to reduce compile time for my project overall. ( Unity Incremental C# Compiler - deprecated ) Without any assembly definition files, Unity has to recompile everything any time a change is made to any file. The incremental compiler is supposed to be smarter, such that it will only recompile code that it detects is dependent on the code change I’ve made. This is supposed to reduce compile time. For example, if I change some unit test code, that should ideally only recompile the unit tests in that one assembly, as nothing else depends on that unit test assembly. It seems the best gains from the incremental compiler require a certain amount of diligence in isolating code into separate assemblies in order to increase the chance that a single code change affects as few other assemblies as possible.
  • Separation of concerns. As I worked on refactoring my code into separate assemblies, this required me to clean up some “smelly” code, such as where one controller finds another controller in the scene in order to perform some action on it. This kind of code has a tendency to get messy. In separating code into different assemblies, it forced me to implement better patterns that decouple the different areas of my application. I’m much happier with the outcome of that refactoring, and I appreciate that separate assemblies forces me to write code more cleanly.
  • Unit Testing - Edit Mode tests are required to be added to an assembly definition. Play mode tests don’t need to be added to their own assembly, but in order to leverage the incremental compiler, it seems preferable to have one test assembly per non-test assembly. I could create a single, massive test assembly with every test in it, which is dependent on every non-test assembly, but I guess that just “feels” less correct.

It’s worth mentioning that the slowness I’m experience doesn’t appear to be compilation time. Adding a new c# script causes two things to occur in series:

  • After adding the script, unity “hangs” for a number of seconds. By “hangs” I mean that the UI is unresponsive, while Unity apparently perform some kind of Asset Import. While tailing the editor log during this time, this phase ends with a log statement containing something like this: “----- Total AssetImport time: 20.854323s, AssetImport time: 15.353629s, Asset hashing: 0.000173s [0.6 KB, 3.150748 mb/s]”
  • After that entry gets written to the log, compilation begins. Compilation actually runs just fine, with no apparently slowness.

So it’s really just that first part that’s affected by the assembly definitions. My big question is, what is Unity doing during that AssetImport pass, and why is it taking an increasing amount of time per assembly definition? Has it always been this way, or is it a regression? It’s worth mentioning that this AssetImport slowness occurs whether or not the project is using the Incremental Compiler.

So, the short answer is that it’s not “necessary” to have any assembly definitions file (except perhaps a single one to put every Edit Mode test into). But there are reasons that having many assembly definitions seems like it should be an appropriate way to structure my project. It just so happens that there’s one massive downside to using this approach. I’ve love to know if that’s a resolvable bug, or a way of life.

3 Likes

Unfortunately, after I moved everything into assembly definitions and had a nicely segregated project (devoid of circular references) I found that compile time wasn’t really affected very much. Or, Unity does other stuff after compiling that still eats up a lot of time. The post I linked above on the incremental compiler does point this out somewhat, and suggests that their impressive charts don’t necessarily show a reasonable before-and-after for how long compilation feels in the editor. I’m not sure quite how much the incremental compiler improved the compiler performance of my project overall, but my understanding is that it’s still a work in progress.

1 Like

I have long suspected that the editor marks things dirty which shouldn’t be, causing all sorts of assets to be processed unnecessarily. At least that’s the only explanation I can see for some of the strange slowdowns in rebuild time. They’re not always consistent either, which makes it such a pain to submit bug reports.

My little unproved theory is (not sure if same case for you), since i mostly work on beta version of Unity, it may have some additional checks enabled, which may slow down certain actions.

Edit:
I was running ECS with official samples files on one test project.
Unity / Visual studio was spending roughly one min to do something with files, every time I did rebuild my little script. Until I created new project. So there are some unnecessary check going on for sure.

Assembly definition files are a colossal pain in the arse and I’ll never use them unless forced. I’m using the incremental compiler and expect Unity to handle my mess, which it does very well. Another happy customer.

If middleware, Unity packages and stuff I don’t need to look at use it - then that is fine and I am happy.

Yes, 47 so far, about half of those from packages or third party code, the other half my own. I no longer have any code in any of the default assemblies or Plugins.

Tracking EditorApplication.isCompiling tells me that adding a new script to an unreferenced leaf assembly takes 3-4 seconds, but including editor hangs due to various other things that go on it’s closer to 8-9 seconds of dead time (for example HDRP being torn down/recreated appears to eat a few seconds). “Total Asset Import” time when adding a new script is 0s. Might be something weird going on there because Cache Server/2018.3b.

I think most actual compilation speedups can be gained by just turning on the Incremental Compiler. I’m a fan of asmdefs for encouraging separation of concerns, discouraging sloppy use of globals, etc. though.

From my experience and a lot of time spent profiling the editor, compilation/new code/“enter play” hangs are most often caused by packages/assets doing lots of work when Unity does its teardown/setup for a domain reload. A few to look out for in the profiler off the top of my head: Cinemacine, Odin, HDRP.

3 Likes

Thanks very much for your experience. It didn’t occur to me to profile the editor to see what it’s up to while the delay is occurring. I’ll investigate that.

Well, I’m not sure what to make of this, but this is what a Deep Profile of the editor looks like when I add a new C# script, without any assembly definition files. I was hoping to find some 3rd Party code in here, but this looks completely built in:

AssetPostprocessingInternal.PostprocessAllAssets is taking 3 seconds. It’s also generating a lot of garbage (71.5 MB) but maybe that’s typical of Editor functionality. Again, this doesn’t give me much to pursue in terms of why that method is taking 3 seconds.

Hi, I’m using many 3rd party assets and they cause slowing down compiling my own code.

I would like to put my code in my own assembly to speed it up but the problem is that I also have to put the 3rd party assets into its own assemblies as well to make it work.

But the problem is that many 3rd party asset has too many “Editor” folders. Right now I have a total of 116 Editor folders and I’ll need to create Assembly Def file for each of them.

To make it less painful, one of the following solutions will work but I need Unity to help.

  1. Don’t create Assembly Def file for the 3rd party asset and it will put them into the default CSharp-Assembly. And make CSharp-Assembly selectable from the list of the Assembly Def file so that we can make our own assembly sit on top of it.

  2. Create Editor assembly automatically for the custom Assembly Definition file under them, just like how the default CSharp-Assembly-Editor.dll is created.

Unity, can you please help? or, there is some easier way to deal with this?

Thanks.

1 Like

I just came to the same conclusion after finding out that compilation of assembly definitions ignore the magic Editor folders. If you want your builds to succeed, you will have to create asmdef files in ALL your Editor folders. Since I like to contain things that belong together, together, this is very well put “a huge pain in the arse”.

I saw that Lee Vermeulen found a workaround.
https://www.3delement.com/?p=586

Why is something like this not build into Unity?

Thanks, I’ll take a look at the workaround. But too many things at Unity are not well thought of, always missing something simple and stupid.

Unity! Please make the Magic Editor folder work for AsmDef! There are too many Assets that has too many Editor folders and it’s impossible to turn it into AsmDef friendly.

If you want to take the lazy route, make the asset developer to require AsmDef in the assets from now on.

2 Likes

The reason your seeing the slowness isn’t due to increased compilation time. It’s due to the time needed to unload and reload all of the assembly files that have been generated. Long story short: Having a handful of asmdefs can help speed up compilation - say 1 for long-term library code and 1 for actively developing project code. However, if you have dozens of the things then you will loose all of the speed benefits.

As others have mentioned by now, the fact that they ignore editor folders is a huge pita and is quite deliberate as Unity specifically stated they wanted to eventually do away with such ‘magic’ folders. Haven’t yet gotten around to it but I’m going to try a build automation tool that will rename the file extension of all asmdefs in the project just before a build. And changes them back just after. Manually testing this has show that it does work so I see no issues with large-scale automation (aside from slower build times perhaps).

This came up in another thread, but it’s worth mentioning that some versions of Visual Studio Tools for Unity is/are/were doing some very inefficient things with respect to assembly definitions. So if you use ASMDEFs and haven’t updated Visual Studio in a while (VS Tools for Unity is pinned to individual VS releases), you might see some performance improvements if you update.

2019.2 will have reference files which allow you to have all subfolders for an asmdef reference a separate assembly.

When the feature of asmdef files was released, I did a quick experiment: making 2 of our plugins Master Audio and Core GameKit use asmdef files, which includes editor folders for each. It still compiled, but changing a file in either plugin’s folder actually caused compilation to go slower - which was quite surprising as the claim was that the feature was meant to speed up compilation. Also, the custom defines functionality doesn’t even work consistently. Asmdef files is totally useless feature to me. Those are the 2 things that would have value. Neither works. Maybe not tested enough? I don’t know why anyone would use them as is.

Not sure if this is known anyway I use a script created by Karl Jones from Unity that shows what asmdef part(s) are recompiled in de console. This can be usefull at times to see what is beeing rebuild if you change a C# file.
link about the discussion is here:

File location (also in link above is here )

Also works in 2019.3a5+

1 Like

I compared the compile time and assembly reloading time. Having separate AsmDefs improves compile time just a little, a fraction of seconds, but having many separate dll increased assembly reloading time, sometimes making even worse than not having AsmDef at all. Therefore, using AsmDef doesn’t help and it is pretty much useless.

The situation is even worse now. Some Asset developers are starts using AsmDef and some don’t. In order to cross-reference, I must create AsmDef for them. This is becoming a joke now.

What I want to do is to put all asset that doesn’t change often into a single AsmDef (plus Editor assembly) and my code into the other assembly. This is the best solution. Why is just a hard concept to understand? You already have Magic Folder working for Assembly-CSharp, why not make it work for AsmDef? It’s freaking ridiculous how Unity thinks and works.
Please do something about it.