#Understanding Custom Data Structures Inside Jobs & Burst

1 messages · Page 1 of 1 (latest)

austere edge
#

Im trying to comprehend a bit more how to convert some tasks into more performant ones with jobs & burst but i'm having troubles understanding how a task that typically uses a custom class/struct for data handling would work with it.

To be more specific, in one simple example we have 2 classes, and 1 function (Im only using this as an example, not a real world application and just trying to understand more).

class MyCustomData
{
  List<OtherCustomData> MyData;
}```

```cs
class OtherCustomData
{
  Vector3 SomePosition;
  Float SomeValue;
}
void DoSomething()
{
  //Assuming its not empty for simplicity
  float testFloat = MyCustomDataInstance.MyData[0];
  For(int i = 1; i < MyValues.Count; i++) { testFloat *= MyCustomDataInstance.MyData[i] }
}```

How would you convert it?
azure bridge
#

First if all, if you want to go burst, you want all data types to be unmanaged:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/unmanaged-types

That is, you can't use classes to store your data, because they are managed types. So OtherCustomData should be a struct. You should also understand the exact difference between class and struct. Particularly – structs are value types:
https://www.c-sharpcorner.com/blogs/difference-between-struct-and-class-in-c-sharp

List<> is a class too, so you can't use List in burst (as well as other default C# collections like Dictionary, arrays[] and so on). But Unity got you covered, presenting unmanaged versions of them – NativeContainers:
https://docs.unity3d.com/2022.2/Documentation/Manual/JobSystemNativeContainer.html

So to put it simple – you just change MyData to be NativeList. But now it's you who is in charge of it's lifecycle, not garbage collector. you have to allocate and deallocate memory for it manually (or use Temp allocator which does it for you). read about Allocators.

now that you converted your data to be unmanaged, you have to burst compile your DoSomething() for it to take effect. for that, it has to be static, and you have to put [BurstCompile] on both method and it's type. There's a very good post from Elliot(❤):
https://forum.unity.com/threads/when-where-and-why-to-put-burstcompile-with-mild-under-the-hood-explanation.1344539/

He also presented a good way of checking if you actually burst compiled or not

hope it helps

#

Also, if you're like me and are curious where on Earth unmanaged restriction comes from, it is simply a design choice to allow Burst to optimize for very fast performance:
#1064581837055348857 message

austere edge
#

Ill spend time reading it in depth thank you. Ill come back if i got any more questions

austere edge
# azure bridge First if all, if you want to go burst, you want all data types to be unmanaged: ...

I spend a bit of time and i must say this didnt really help me clarify what i wanted to learn (due to lack of experience with burst ^^)

One clarification i should do is that:

class MyCustomData
{
  List<OtherCustomData> MyData;
}```

Is used inside yet another class, so after conversion the expected flow would look like:

```cs
class myClass : Monobehaviour
{
  NativeList<MyCustomData> CustomDataList; 
}```

```cs
struct MyCustomData
{
  NativeList<OtherCustomData> MyData;
}```

```cs
struct OtherCustomData
{
  float3 somevector;
  float somevalue;
}```
#

i saw some users suggesting me to use the nativehashmap to achieve this, but i cant find a single example of use case after a good amount of searching and the documentation is very confusing since it has 0 examples of api usage

azure bridge
austere edge
azure bridge
#

they have very similar APIs too

#

Unity has copypasted bunch of standard api from default collections to natives

austere edge
#

Ah okay i thought it would be more complex

#

Then this becomes more straight forward

azure bridge
# austere edge Ah okay i thought it would be more complex

all that's different is that you have to choose the Allocator.Something when initializing the container (whether NativeList or NativeHashMap or whatever native),
and once you don't need it anymore you should do myContainer.Dispose()
that's it

#

also keep in mind that NativeContainers are just pointers to actual UnsafeContainers

#

so they are value types

#

but they are pointers

#

that's why they act as "reference" types when passed around. because you actually just copy the pointer and it points to same data

austere edge
#

Man i havent worked with pointers since my C era of 4D pointer arrays (dont ask me why)

#

okay fun times then

#

Ill have to spend time to see how pointers work in c# cause no way they are similar to C - C++