Hello !
I found something strange.
I have a small static function that is called a lot by a burst compiled job. The function is not in the job struct but is burst compiled with the [BurstCompile] attribute.
However I noticed that removing the attribute doesn't break anything and it actually improves the job's performance by about 40% !
I have no idea what is going on 😦
Should I avoid calling other burst compiled functions from burst compiled code ? Or could it be because the function is very small ?
#Function called from a job is faster when not burst compiled
1 messages · Page 1 of 1 (latest)
This is the function :
[BurstCompile]
public static bool _IsBigBlockSolid(int x, int y, int z, in int4 dynamicMask, in NativeArray<int> bigBlockIDs, in NativeList<int4> DPOBigBlocks)
{
int id = data.Data.bigBlockIDs[x + (z << WorldManager.horizontalBits) + (y << (2 * WorldManager.horizontalBits))];
return (id & removeDynamicIDMask) != 0 || (id != 0 && DynamicPhysicsObject._IsBigBlockSolid(DPOBigBlocks[(id >> (typeBits + staticIDBits)) - 1], in dynamicMask));
}
And this is DynamicPhysicsObject._IsBigBlockSolid (another small burst compiled static function in another class)
[BurstCompile]
public static bool _IsBigBlockSolid(in int4 objects, in int4 mask)
{
return math.any((objects & mask) != 0);
}
If I simply remove the attributes without changing anything else it is much faster 🥲
Do not put [BurstCompile] on all of your methods
You should mark with attribute only the points of entry for execution - system methods (onupdate) and job struct itself.
Compiler will resolve everything additional and make required bursted methods for itself.
Hmm ok but what if this function is also called from regular C# code ? If the function is not burst compiled it might be slower 😢
Or will it use the compiled version made for the job ?
calling from regular code will never call bursted version (ok someone is probably doing some magic with it)
so when you call it from non-bursted context it will be a non-bursted variant
to call bursted method all stack should be bursted from the point of entry so consider it bursted onupdate and bursted job - anything except it will be regular unbursted call
Yes but I'm not using full ECS 🥲
I'm only using Burst and jobs when performance is needed. So sometimes the same function is called from a regular Unity script AND from a job for example.
But OK, I'll try to do that, I can make more functions if needed 🙂
Thank you for your help !
Unity Forum
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...
calling from regular code will never call bursted version
it's been a while since I tried it, but I believe a static function will be burst compiled just fine (see Rukhanka's link)
iirc the problem with doing this with a small function called from non-bursted code is the switch from managed to native that happens as a result (hence the perf issues)
After trying a few more things, I realised I forgot to burst compile the job 🥲 Sorry about that !
When the job is burst compiled there is no difference if the function is burst compiled or not.
So indeed it seems to be the switch between non-bursted to bursted that was causing this problem 🙂
Small correction, it makes no difference if the function is marked with [BurstCompile] or not- it'll be burst compiled no matter what if the job calling it is burst compiled :-P
Right that's indeed what I see in my benchmark results 🙂
But if the job is not burst compiled then there is a difference 🙂
the reason is burst compiled function introduces native interop and when called many times for something that is extremely cheap in mono - you will spend much more time on simply invoking the function.
Mostly you can consider that cost of calling bursted function is equal to reflection based call of function (MethodInfo.Invoke).
When whole job is bursted - the cost of interop is only once per job, not per function call, since Burst will inline your functions into one giant function for whole job.