Search Unity

Bursting into 2021 with Burst 1.5

April 14, 2021 in Engine & platform | 5 min. read
Screenshot of gameplay
Screenshot of gameplay
Share

Is this article helpful for you?

Thank you for your feedback!

Our High Performance C# (HPC#) compiler technology, Burst, has gone from strength to strength. In the latest version Burst 1.5, we’ve made some major improvements. In this post we’ll take you through the headline features, and show you how to make the most of Burst in your projects.

Arm Neon Hardware Intrinsics

In collaboration with our partners at Arm, we’ve added Arm Neon hardware intrinsics to Burst 1.5. These let you target the specific hardware instructions available on Arm platforms, including the amazing vector technology Neon in all its glory.

Arm Neon intrinsics were first introduced as an experimental feature in Burst 1.4, and we're happy to announce that in Burst 1.5 Neon intrinsics are now fully supported.

Burst currently supports all Armv8-A intrinsics. Armv8.1-RDMA, Armv8.2-DotProd and Armv8.2-Crypto intrinsics are an experimental feature in Burst 1.5, full support will be added in the next Burst version.

Arm Neon intrinsics make use of the v128 type, familiar from Intel intrinsics, and also the v64 type. These types comprise bags of 128 or 64 bits, respectively. It's up to you to make sure you are correctly treating vector element type and count; after all, in the CPU it is represented as a SIMD register.

A simple usage example:

Keep in mind that the IsNeonSupported value is being evaluated at compile time based on your target CPU, so it doesn't affect the runtime performance. If you want to provide multiple intrinsics implementations for Arm and Intel target CPUs, you'd want to have more of the IsXXXSupported blocks in your code.

An important thing to consider is that Neon intrinsics are supported only on Armv8-A hardware (64-bit). On Armv7-A (32-bit) IsNeonSupported will always be false. If you are still targeting older 32-bit Arm devices, you can still rely on Burst to optimize your managed code automatically, without using Neon intrinsics directly.

We’ll be following up on Arm intrinsics in a subsequent blog, sharing more details on Neon intrinsics.

Hardware intrinsics are targeted at advanced users who want to get the absolute maximum performance out of the compiler, and want to fine-tune their code trying to squeeze down a few more CPU cycles. If you accept this challenge, we are happy to hear your feedback!

Direct Call

A prominent new feature in Burst 1.5 is what we refer to as Direct Call. With Burst, we began focusing on jobs to accelerate tasks that run on Unity’s job system with our HPC# compiler. We then added function pointers, so you can manage and call into bits of Burst code from just about anywhere:

The code proceeds to run through Burst. Note that Direct Call methods only work this way (as shown above) when called from the main thread.

New optimization superpowers

In Burst 1.5, we’ve added ample new and interesting functionalities to give you some extra optimization superpowers.

Hint.Likely, Hint.Unlikely and Hint.Assume

One key request that has continued to come up focuses on the use of intrinsics to inform the compiler whether something is likely or unlikely to happen. In Burst 1.5, we’ve added two new intrinsics to Unity.Burst.CompilerServices – Likely and Unlikely:

These intrinsics enable you to tell the compiler whether some boolean condition (like the condition of an “if” branch) is either likely or unlikely to be hit. This allows the compiler to optimize the resulting code.

We’ve also added an Assume intrinsic:

This intrinsic informs the compiler of certain trends that will always occur. For instance, you can use Assume to tell the compiler that a pointer is never null, an index is never negative, a value is never NaN, and so forth. Be careful though – the compiler won’t check if your Assume is actually valid, so please ensure that your assumptions are actually true.

IsConstantExpression

We’ve also added an intrinsic to query whether an expression evaluates to a constant expression at compile time:

This query can be used as shown above, to ensure that some value is constant. Otherwise, it can be used in algorithms with faster paths, if, for example, something is definitely not NaN or null.

[SkipLocalsInit]

In C#, all local variables are zero initialized by default. Sometimes developers want to skip the cost of doing this zero initialization, so we added an attribute [SkipLocalsInit] to do just that. Simply apply this attribute to any function that you don’t want to have the zero initialization happen on. This mirrors .NET 5’s SkipLocalsInitAttribute functionality, but brings it to Burst sooner.

Miscellaneous improvements

Check out these smaller but equally awesome improvements in 1.5, in no particular order

  • Burst now supports ValueTuple structures (int, float) within Bursted code – so long as types don’t stray across entry-point boundaries. For example, you can’t store them in a job struct or return them from a function pointer.

  • We added Bmi1 and Bmi2 x86 intrinsics to Burst 1.5 – gating them on AVX2 support. Any CPU that has AVX2 support can now make use of these incredible bit manipulation instructions directly in their code.

  • In Unity 2020.2 or newer versions, you can now call new ProfilerMarker("MarkerName") from Bursted code.

  • We also re-enabled the Burst warning BC1370, exclusively in player builds. This warning tells you where throws appear in a function unguarded by [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] – which isn’t supported in player builds.

  • Finally, there is a whole slew of performance improvements surrounding the use of LLVM 11 as our default code generator, along with optimizations for stackalloc hoisting, dead loop removal, compile time improvements and much more.

One last dance for 2018.4

Burst 1.5 is the last version to support Unity 2018.4. Our next version will have a minimum requirement of Unity 2019.4.

Start using Burst

Burst is a core part of our technology stack that you can start using today. It is a stable and verified package, already employed in thousands of projects, and counting. While our DOTS technology stack leverages Burst to provide highly optimized code, Burst also serves as a stand-alone package outside of DOTS.

It supports all the major desktop, console and mobile platforms, and works with Unity 2018.4 or newer.

If you have any thoughts, questions, or would just like to let us know what you are doing with Burst, then please feel free to leave us a message on the Burst forum.

 

April 14, 2021 in Engine & platform | 5 min. read

Is this article helpful for you?

Thank you for your feedback!

Related Posts