Skip to content

Instantly share code, notes, and snippets.

@qwe321qwe321qwe321
Last active February 28, 2024 05:26
Show Gist options
  • Save qwe321qwe321qwe321/2b97927a92790462173cdfc819d0fd3b to your computer and use it in GitHub Desktop.
Save qwe321qwe321qwe321/2b97927a92790462173cdfc819d0fd3b to your computer and use it in GitHub Desktop.
Unity Burst Compiler Direct Call comparison
using Unity.Burst;
using Unity.Burst.CompilerServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Profiling;
public class BurstTest : MonoBehaviour
{
public int count = 100000;
// Update is called once per frame
void Update()
{
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Job.Schedule()");
new MyBurstJob
{
Result = result,
count = count,
}.Schedule().Complete();
Profiler.EndSample();
}
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Job.Run()");
new MyBurstJob
{
Result = result,
count = count,
}.Run();
Profiler.EndSample();
}
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Job.Execute()");
new MyBurstJob
{
Result = result,
count = count,
}.Execute();
Profiler.EndSample();
}
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Direct Call");
unsafe
{
BurstLib.Burst(count, (uint*)result.GetUnsafePtr());
}
Profiler.EndSample();
}
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Direct Call Hint");
unsafe
{
BurstLib.BurstAssume(count, (uint*)result.GetUnsafePtr());
}
Profiler.EndSample();
}
using (NativeArray<uint> result =
new NativeArray<uint>(count, Allocator.TempJob, NativeArrayOptions.ClearMemory))
{
Profiler.BeginSample("Direct Call Performance");
unsafe
{
BurstLib.BurstPerformance(count, (uint*)result.GetUnsafePtr());
}
Profiler.EndSample();
}
{
uint[] result = new uint[count];
Profiler.BeginSample("Direct Call without for-loop");
for (int i = 0; i < count; i++)
{
result[i] = BurstLib.ComputeSomething(i, i, i);
}
Profiler.EndSample();
}
{
uint[] result = new uint[count];
Profiler.BeginSample("[No Burst] Direct Call without for-loop");
for (int i = 0; i < count; i++)
{
result[i] = NoBurstLib.ComputeSomething(i, i, i);
}
Profiler.EndSample();
}
}
[BurstCompile]
struct MyBurstJob : IJob
{
public NativeArray<uint> Result;
public int count;
[BurstCompile]
public void Execute()
{
for (int i = 0; i < count; i++)
{
Result[i] = NoBurstLib.ComputeSomething(i, i, i);
}
}
}
}
[BurstCompile]
public static class BurstLib
{
[BurstCompile]
public static unsafe void Burst(int count, uint* Result)
{
for (int i = 0; i < count; i++)
{
Result[i] = ComputeSomething(i,i, i);
}
}
[BurstCompile]
public static unsafe void BurstAssume([AssumeRange(1, int.MaxValue)] int count, uint* Result)
{
for (int i = 0; i < count; i++)
{
Result[i] = ComputeSomething(i,i, i);
}
}
[BurstCompile(OptimizeFor = OptimizeFor.Performance)]
public static unsafe void BurstPerformance([AssumeRange(1, int.MaxValue)] int count, uint* Result)
{
for (int i = 0; i < count; i++)
{
Result[i] = ComputeSomething(i,i, i);
}
}
[BurstCompile(OptimizeFor = OptimizeFor.Performance)]
public static uint ComputeSomething(int x, int y, float t)
{
float3 pos = math.float3(x, y, t) * math.float3(0.008f, 0.008f, 0.5f);
float f32 = noise.snoise(pos) * 0.4f + 0.5f;
uint un8 = (uint)(math.saturate(f32) * 255);
return un8 | un8 << 8 | un8 << 16 | 0xff000000;
}
}
public static class NoBurstLib
{
public static uint ComputeSomething(int x, int y, float t)
{
float3 pos = math.float3(x, y, t) * math.float3(0.008f, 0.008f, 0.5f);
float f32 = noise.snoise(pos) * 0.4f + 0.5f;
uint un8 = (uint)(math.saturate(f32) * 255);
return un8 | un8 << 8 | un8 << 16 | 0xff000000;
}
}
@qwe321qwe321qwe321
Copy link
Author

qwe321qwe321qwe321 commented Feb 28, 2024

Profiling result
(Leak Detection, Job Debugger, Safety Check are OFF.)
image

  • No difference from Jobs and Direct Calls.
  • For-loop inside the Burst scope helps.
  • Directly call Job.Execute() won't burst compile.
  • If the job is burst compiled, all functions it called through was burst compiled even without [BurstCompile] attribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment