#Function called from a job is faster when not burst compiled

1 messages · Page 1 of 1 (latest)

charred heron
#

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 ?

#

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 🥲

halcyon schooner
#

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.

charred heron
#

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 ?

halcyon schooner
#

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

charred heron
#

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 !

sour compass
pine lotus
charred heron
#

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 🙂

ebon thunder
charred heron
#

Right that's indeed what I see in my benchmark results 🙂

#

But if the job is not burst compiled then there is a difference 🙂

hoary finch
# charred heron 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.