Skip to content

Instantly share code, notes, and snippets.

@nothke
Last active October 19, 2020 07:42
Show Gist options
  • Select an option

  • Save nothke/dd86f3781e76e48d2c400414c9ccc7c2 to your computer and use it in GitHub Desktop.

Select an option

Save nothke/dd86f3781e76e48d2c400414c9ccc7c2 to your computer and use it in GitHub Desktop.
// A very basic and silly example of some class that contains a slow operation we'd like to compile with Burst.
// This only shows how to CONVERT a -theoretically- already existing piece of code, and still reap the benefits of the Burst compiler.
// If you started with knowing it will be Burst compiled from the beginning you might design everything differently.
// This is an example of how we might do a thing in classic C# OOP
public class ClassicExample
{
public int multiplier = 2;
const int CONST = 42;
public int[] array;
public void Build()
{
array = new int[100000];
// Do something for each element
// Lets say that this loop is very expensive and we'd like to Burst compile it.
for (int i = 0; i < array.Length; i++)
{
Calculate(i);
}
// We might then use a value, maybe even outside the class
Debug.Log(array[123]);
}
// An example outside of loop that operates on the elements of the loop,
// In classic C# OOP we will probably directly reference members instead of passing them
void Calculate(int index)
{
array[index] = multiplier * index + CONST; // some random calculation
}
}
using Unity.Collections;
using Unity.Burst;
using Unity.Jobs;
// This is how we could convert above to DOTS aka HPC# aka Jobs + Burst Compiler
public class BurstExample
{
public int multiplier = 2;
const int CONST = 42;
// The C# managed arrays cannot be used in burst compiled jobs, hence it needs to be NativeArray
// Note that you also can't use class references as NativeArray members,
// only basic types or structs with basic types are allowed
public NativeArray<int> array;
public void Build()
{
// I'm building a persistent array here, but you might use some other allocator.
array = new NativeArray<int>(100000, Allocator.Persistent);
// Create and run a job immediately on the main thread.
// Otherwise, use .Schedule() and .Complete() to run on a separate thread and wait for completion
new CalculateJob()
{
// Pass external values to job
// Note that you can't use static values, you need to "pass values in" explicitely (except consts)
array = array,
multiplier = multiplier
}.Run();
// Using the value works just like in the classic example
Debug.Log(array[123]);
}
private void OnDestroy()
{
// Also we need to dispose the array manually!
array.Dispose();
}
// Will be burst compiled, running very fast!
[BurstCompile]
public struct CalculateJob : IJob
{
public int multiplier;
public NativeArray<int> array;
public void Execute()
{
// That original loop is now here! But using values passed in through Build() method
for (int i = 0; i < array.Length; i++)
{
Calculate(ref array, multiplier, i);
}
}
}
// Need to convert this method to static, so you make sure it doesn't use memebers outside of the job
// It will be burst compiled as it is referenced inside the CalculateJob
// Since this is such a small function, you might want to use [MethodImpl(MethodImplOptions.AggressiveInlining)],
// to let the compiler know it's a small function (but always profile if performance is very important)
static void Calculate(ref NativeArray<int> array, in int multiplier, int index)
{
// But note that you can still use consts inside burst compiled jobs, without passing them in!
array[index] = multiplier * index + CONST;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment