People are very often confused about where they should put [BurstCompile], and what gets bursted when they put it where, so I figured I’d write something up explaining everything in one place.
The first two things to know, from which all else flows, but seems a bit surprising at first:
- Burst can only ever burst static methods, period, end of story. If you want this to happen outside of the special cases outlined below, just put [BurstCompile] on a static method and on its declaring type.* When you call this method, it will call the bursted version automatically, assuming burst compilation didn’t fail.
- Unless you try really hard, all C# called from bursted code is bursted.
If #1 above is true, what’s the deal with IJobWhatever’s Execute method (which is not static for any value of IJobWhatever), and ISystem’s OnUpdate & friends (which are also not static), you ask?
Answer: Different magic for each.
In the case of jobs, each job interface is annotated with an attribute like [JobProducerType(typeof(SomeOtherSpecialSecretType))]
For example, you can see here: UnityCsReference/Runtime/Jobs/Managed/IJob.cs at 2022.2 · Unity-Technologies/UnityCsReference · GitHub
that the definition of the IJob interface is tagged with [JobProducerType(typeof(IJobExtensions.JobStruct<>))]
If you put [BurstCompile] on a type that implements an interface, Burst knows to look for this attribute on the interface, go find that other type (in this case IJobExtensions.JobStruct
), make sure it’s generic (it is), specialize it with the type of your specific job struct (making it IJobExtensions.JobStruct<YourPersonalJob>
), and then compile the static Execute method on that other type. The static Execute method on that other type will call your personal Execute with some arguments and in some context, and your personal Execute will be bursted as part of that larger static function (see point 2 at the top of this post).
This is also why you sometimes see code that isn’t yours in the outer loop of the burst inspector.
In the case of ISystem OnWhatever callbacks, we run an ILPostProcessor that specially generates static functions that take a void* for the this argument plus the ref SystemState, and we cast the void* back to the particular system type and then call the non-static OnUpdate on that. Burst then bursts our static wrappers, and we make sure to call the static wrappers when we update systems.
Corollaries of this:
-
Non-Execute methods of job structs that have [BurstCompile] on the job struct are NOT bursted when called from non-bursted code (unless they’re static and you put [BurstCompile] on them specifically as well as on the job struct). But, as mentioned, all C# called from bursted code is bursted.
-
The ISystem magic makes it seem like you can burst non-static functions because of those special cases, but you can’t in general.
Happy bursting!
- The reason you need to put [BurstCompile] on the declaring type as well as the static method is to reduce the time Burst needs to take scanning for what to burst. If we didn’t require it on the type, it would have to go to every method of every type checking for attributes, whereas this way it can just check the type itself and move on if the type doesn’t have the attribute. [Edit 5/19/2023: This used to apply to ISystem’s as well, but a touch of extra magic was added there so you only need it on the OnWhatever functions, not on the type itself. The extra magic is basically, we’re processing all the ISystems for codegen anyway, so it’s no extra bother for us to check the OnWhatever functions for [BurstCompile], and slap [BurstCompile] on the type for you while we’re at it.]
[edit shortly after]
If you are ever worried about whether some particular code is being run bursted or unbursted, you can use the following pattern:
[BurstDiscard]
void SetFalseIfUnBursted(ref bool val)
{
val = false;
}
bool IsBursted()
{
bool ret = true;
SetFalseIfUnBursted(ref ret);
return ret;
}
It is perhaps obviously inadvisable to ever change behavior based on the value of this function, because then when you turn off burst your behavior will change and you will immediately go insane.