realm / realm-dotnet

Realm is a mobile database: a replacement for SQLite & ORMs
https://realm.io
Apache License 2.0
1.24k stars 162 forks source link

[Bug]: Unity3D - Weaver Always Runs, regardless of Assembly Structure #2928

Open moritz-mg opened 2 years ago

moritz-mg commented 2 years ago

What happened?

We have our Data Models in a separate Assembly, that's where all our RealmObject inheritors live. Our Main Scripts Assembly references that assembly, so it only gets recompiled if the actual Models change.

However, unexpectedly, there is a 1 second Weaver operation on every compile, regardless of whether it involved the AoE.DataModels assembly. This seems to make up a considerable chunk of our iteration times.

image

If weaving manually via the Tools Menu, the tax is lower:

image

Expected behaviour: Weaver is either 0ms on a no-change compile; or skipped entirely, if the assembly that contains the RealmObjects does not get recompiled itself.

Repro steps

  1. Put your RealmObject inheritors into a separate Assembly (let's call it RealmObjects Assembly).
  2. Reference that Assembly in your Scripts Assembly (may need to create one from scratch)
  3. Compile everything, clear console.
  4. Change a File in the Scripts Assembly, which will trigger a Recompile
  5. Observe: Weaver runs, even though the RealmObjects Assembly does not change, does not get recompiled, and thus doesn't need its classes to be woven.

Version

10.12.0

What SDK flavour are you using?

MongoDB Realm (i.e. Sync, auth, functions)

What type of application is this?

Unity

Client OS and version

Win11, Unity 2022.1.0f1 but reproduced also on 2021.3.x LTS and before

Code snippets

No response

Stacktrace of the exception/crash you're getting

No response

Relevant log output

---------------------------------------
Triggered by Recompile (even though AoE.WorldMap is not being compiled as it hasn't changed)
---------------------------------------

[AoE.WorldMap] Weaving completed in 981 ms.
0 classes were woven:

UnityEngine.Debug:Log (object)
RealmWeaver.UnityWeaver/UnityLogger:Info (string)
RealmWeaver.UnityWeaver:WeaveAssemblyCore (string,System.Collections.Generic.IEnumerable`1<string>,string,string)
RealmWeaver.UnityWeaver/<>c:<Initialize>b__14_1 (string,UnityEditor.Compilation.CompilerMessage[])
UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface:TickCompilationPipeline (UnityEditor.Scripting.ScriptCompilation.EditorScriptCompilationOptions,UnityEditor.BuildTargetGroup,UnityEditor.BuildTarget,int,string[])

---------------------------------------
Manual Weave
---------------------------------------

Weaving completed. 0 assemblies needed weaving.
UnityEngine.Debug:Log (object)
RealmWeaver.UnityWeaver/UnityLogger:Info (string)
RealmWeaver.UnityWeaver/<WeaveAllAssembliesMenuItem>d__15:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int>:SetResult (int)
RealmWeaver.UnityWeaver/<WeaveAllAssemblies>d__19:MoveNext ()
UnityEngine.UnitySynchronizationContext:ExecuteTasks ()
moritz-mg commented 2 years ago

Disabling build time analytics cuts the duration of the Weaver operation by 75%, now averaging around 250ms as opposed to averaging slightly over 1000 ms. Still, the weaving should not happen at all.

nirinchev commented 2 years ago

Hey Moritz, I don't think we have an obvious way to detect where your models are - the weaver needs to run and inspect the assembly to detect there is no work to do there, but that inspection requires some work, especially after compilation. I'll try and profile it to see if we can optimize that and make it faster. We could also provide an option to specify filters for the assemblies the weaver processes - that way you can filter out assemblies where you know there are no models.

What would you say the impact of this issue is on your workflow when build time analytics are disabled? I'm trying to prioritize it against other tickets we have in flight.

moritz-mg commented 2 years ago

Maybe let us specify which Assembly all Models are in? I also sometimes get a message that no ReamObject inheritors were found in Assembly-CSharp (can't reliably reproduce, but seen it 4-5 times so far in this very project).

Then you perhaps only need to check if that assembly is being reloaded, and weave then.

I am reluctant to say the impact is "negligible" because it's a quarter second minimum in a process that should take <1 second max; in a realistic scenario it currently adds (apart from the sporadic message about there being zero inheritors) 250ms to a 3-5 second process due to some issues in Unity 2022.

In 2020.3 or so, this does cause a significant amount of delay (contributing said 250ms to a 1 second delay even in tiny RealmObject code bases); in 2021.3 about half as significant, and in 2022.3 about a quarter as significant, but this is Unity crawling to a halt in recent iterations, not MongoDB Realm Weaver code running faster.

That said - if you'd ask me whether I would want Realm to support No Domain Reload Edit Mode options or faster zero-change Weaving times on recompile, I would take the No Domain Reload support any time.