Unity Native Collections / quaternion / mathematics in-Editor performance issues

Hi, I am having issues with reduced in-Editor performance of native collections and quaternion from the mathematics package.

I’ve started trying to optimise some code using Burst, so I put my data into native collections. I’ve done performance testing and found native collections to be much slower in-Editor when compared with managed alternatives, which is why I have mostly avoided them. For example, I have found NativeArray to take 5x as long to loop over vs. managed arrays, which is mitigated by using pointers with NativeArray - so now I use pointers for in-Editor performance. In builds, the NativeArray is on-par with managed arrays, and is even faster when using Burst.

This slowness in-Editor also applies to other native collections I have tested. Perhaps it is related to collection safety checks, which I believe to be force-enabled in-Editor, and disabled in builds.

This is all great for builds, but I do most testing in-Editor so that I can work on things and make changes, and this performance overhead can be quite substantial, and makes it difficult to understand the performance of my game. I know builds should be profiled, but if I have to profile a build every time just because the performance characteristics of these packages are completely different in builds, then this introduces a lot more wait time. I have not noticed such a large discrepancy between Editor and Build performance in other areas of my code.

I have now found that using mathematics.quaternion.LookRotation takes about 3x as long as UnityEngine.Quaternion.LookRotation in-Editor, whereas in a build, mathematics.quaternion is a bit faster even without Burst. Deep Profiling shows the bulk of the cost of mathematics.quaternion.LookRotation in-Editor to be from the constructor.

In my case I am making an open world game, and am currently optimising my enemy system, which has many spawned enemies.

I’m wondering if you have any recommendations here, if you have noticed this, and how you are working with it; and if Unity can make any improvements to the Editor performance of these packages.

EDIT: I am using mathematics 1.2.6 and collections 1.4.0. I see that I can update the collections package so I will look into that.

Always profile builds and make decisions around that.

You seem to be unaware that in the editor Native Collections and Jobs have safety features enabled by default in the editor. You can (temporarily) disable these either from a menu item or settings, depending on the package/editor versions. These can greatly affect performance.

Burst too has settings, for instance you can force it to always prefer performance (unless overridden by an attribute) at the expense of slower compilation.

I make decisions around the builds as stated, but that doesn’t resolve the degraded Editor performance.

I mentioned the safety checks. I believe some checks can be disabled for Burst methods - I was under the impression that as this is under the Burst menu, that it would not apply in general to Native Collections, or to the mathematics.quaternion struct. Burst performance is good in any case - it is the usage outside of Burst that is problematic.

I am posting to update my findings. I am using Collections 1.4.0 even though an update to 2.4.2 is available. I attempted to update the package, and was reminded of why I am still on 1.4.0. 2.4.2 provides the following error message:

error CS0006: Metadata file ‘Library/PackageCache/com.unity.ext.nunit@2.0.3/net35/unity-custom/nunit.framework.dll’ could not be found

I believe this is related to my usage of nunit in my test assemblies, so I am unable to update the Collections package to re-evaluate performance. I previously copied my project folder to attempt a library rebuild which did not resolve the issue.

I am still evaluating the situation on the whole.

You can compile static functions with Burst. It’s pretty great for optimizing editor scripts. Some examples:

Yeah I’ve been making a lot of Burst methods. They are a bit more limited than jobs in terms of the arguments they accept, but are sometimes more convenient.

I think my strategy is to use these native collections and mathematics types with Burst wherever possible, and if there is expensive code outside of that which is difficult to Burst, to instead use the standard types e.g. managed arrays and Quaternion.

I try to keep my editor performance somewhat decent for ease of testing and these things add up at larger scales.

EDIT: I just wanted to add that although I had made a lot of Burst methods, I found them more convenient to use when converted to IJobFor. The arguments are less restricted for Burst compatibility, the job gets its own profiler marker, and it seems the job can then be scheduled more efficiently than a plain Burst method through dependency chaining, which is helping performance in my hot paths.

IJobFor is also nice because I can schedule single-threaded or parallel depending on my test data.