Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

NativeHashMap

Discussion in '2018.1 Beta' started by Nozynski, Jan 30, 2018.

  1. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    Hi!
    I've seen some mentions of this collection, is it available already or will it come later? Cause I can use NativeArray but I can't seem to find NativeHashMap and I could use it for my job code (which btw works really great so far, I love IJobParallelFor).
     
  2. MartinGram

    MartinGram

    Unity Technologies

    Joined:
    Feb 24, 2017
    Posts:
    72
    The NativeHashMap will be available as we open up the beta part of ECS.

    We're still finalising various bits and pieces so that you will have a better experience when you get access.
     
  3. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    Great, thanks for the quick reply. I have one other kind of related problem I am trying to wrap my head around. I have a struct that has an array as a member. And I'd like to use it inside of the job code, but I get an error that the struct must be blittable. Do you know any smart way to make a struct with an array blittable? I know I won't have more than 100 elements in it, so I'd be happy with making it fixed 100 element array or something like this. The only way I've found so far is pretty ugly (making a struct with 100 element and overriding indexer operator to fake being an array).
     
  4. MartinGram

    MartinGram

    Unity Technologies

    Joined:
    Feb 24, 2017
    Posts:
    72
    I'll get back to you tomorrow with more.
     
  5. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    In case anyone needs something similar: here's my hundred element struct that pretends to be an array ;)
     

    Attached Files:

  6. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    325
    Out curiosity Martin, if we wanted to use a NativeArray of a struct, but the struct requires an array within it, would we need to wait for other Native container types coming with the ECS? The largest issue is that NativeArray<T> isn't blittable even if the 'T' type is blittable.

    Example:
    Code (CSharp):
    1. public struct TestingStruct {
    2.     public NativeArray<byte> Bytes; //Alternatively byte[] failed as well
    3. }
    4.  
    5. private struct JTest : IJob {
    6.         public NativeArray<TestingStruct> Data;
    7.         public void Execute() {}
    8. }
     
  7. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9

    You are basically asking what I've already asked in the same topic ;p
     
  8. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    325
    It was more in case it wasn't exactly what you needed. My reading has been greatly impaired via playing around with Job Systems keeping me up every night. Also to be fair Martin did say "tomorrow" about a week ago :)
     
  9. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Nested containers are currently not supported. Its not possible to validate safety for that.

    But more importantly, they are generally a terrible idea for performance and C# jobs are all about performance.
     
  10. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    You are right, I was talking about a different thing, I've just misunderstood your post.
     
  11. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    @MartingGram - any update about an array inside a struct?
     
  12. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,613
    TakuanDaikon likes this.
  13. Nozynski

    Nozynski

    Joined:
    Apr 24, 2017
    Posts:
    9
    I did not, thanks! I'll try it tomorrow and I'll see if it helps.
     
  14. MartinGram

    MartinGram

    Unity Technologies

    Joined:
    Feb 24, 2017
    Posts:
    72
    Hey. :-D

    It is true that I have been hiding a bit. Joachim did reply with a very good answer and rule of thumb.

    @Nozynski The suggestion you posted with encapsulating the elements inside a class and using indexers isn't really going to help you performance wise. What you are looking for are as @superpig mentions fixed buffers and moving into unsafe land.

    I would recommend a bit of patience for the new containers that are coming. There will also be a bunch of samples that can show case various access patterns with jobs and ECS.
     
    laurentlavigne likes this.
  15. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I would vote for new containers to be somewhat as elegant in design as Span<T> if possible. I realize it's very early, but really NativeArray needs to die in a fire at some point.
     
  16. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,613
    They do different things, though. Span<T> doesn't own its backing store.
     
    Peter77 likes this.
  17. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    What's confusing is how the underlying data is managed in relation to NativeArray itself. The allocation options make things even fuzzier. Does it really behave like a value type should? The strong implication is that it doesn't just by looking at the api.

    Span<T> on the other hand is very clear and works as you would expect.

    Naming is I think unfortunate but more of a minor issue. Is it a buffer or an array? doesn't look like either to me really. If it's really a value type then 'Native' just adds to the confusion.

    Slicing a minor thing also, but why a separate type for that?
     
  18. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Here is our goals we had for native array and native containers
    • Zero GC allocation (60 or 90 FPS games need the ability to never ever allocate GC memory)
    • Safety in the editor with the most amazing error messages
    • - Double dispose detection
    • - Leak detection
    • - Out of bounds checks
    • Race condition detectionAny race conditions are detected based on you declaring if you read or write to the NativeArrays. Both in terms of expressing dependencies but also reading from a nativeaarray after a job that writes to it has been scheduled. Essentially a combination of Runtime Checks + (Static analysis - upcoming not yet shipped) will provide 100% coverage of all race conditions.
    • Absolute best performance when deployed. All checks can be disabled and everything will work assuming you had no exceptions thrown by the safety system in the editor or in debug builds.
    • Control over memory allocators (Temp is cheaper than persistent memory as you would expect and avoids fragmentation)
    • Tight control over memory avoids any lock contention issues with the Garbage collector offering massive speedups

    These are the requirements and they are all met.

    As such it has to be a struct. Internally it contains a pointer to the data. Naturally one wants to have safety mechanism. This is where the editor job debugger / AtomicSafetyHandle comes in. All native containers can be copied around as if they are reference types. I agree it would be nice if it was a class but the above goals are more important than consistency with C#.
     
  19. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Span<T> is a value type
     
  20. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    To elaborate, what makes Span<T> much simpler to reason about is that like NativeArray it's an abstraction over memory, but it has a clear scope, it's a value type and acts like one. I don't have to think about the scope of the struct and the memory of the data it contains separately, nor reason about tmp vs non temp allocations or job vs non job scope. Or have to call dispose.
     
  21. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    Reading the Span<T> documentation and this blog post:
    • Span is an abstraction of memory (could be multiple partial blocks in mixed allocations).
      • NativeArray is a HANDLE to memory. Copying the struct copies the handle.
      • Calling Dispose releases the handle, and the memory pointed to is no longer valid.
      • This is more like C/C++ manual allocations than anything else, which is sometimes just what you need.
    • Span isn't necessarily contingous, or allocated as such (it can treat different allocations as one single mapping).
      • For performance reasons, NativeArray is a straitforward allocated block of memory meant to play nice with CPU Caches.
      • It's likely the other Native* structures will have all of their allocations nearby or in allocated in contiguous arenas.
    • Span doesn't seem threading safe, and is intended to operate on a single thread, and has no builtin protection against struct slicing. Span has a different implementation for readonly data.
      • NativeArray is read safe if marked as such in the job system.
      • NativeArray is write safe if marked as such on the job system.
    • Span will have "fast" and "slow" implementations on different platforms.
      • NativeArray<T> probably isn't going to change much on the Managed level between any platforms, outside of the C++ generated around it's usage by the burst compiler (different platforms may have different SIMD/specialized intrinsics).
    • Since Span is stack only, you cannot store it in a field and maintain the memory block, it also has no control over the lifecycle of the memory it represents.
      • NativeArray gives me all the control over the memory it represents.
      • I can even avoid the cost of setting the block allocation to zero if I'm just going to overwrite it immediately using the NativeArrayOptions enum.
      • There is a type that can do this proposed for .NET and intended to work with Span<T>. It's called Memory<T>, and it looks like it behaves more like NativeArray<T>, and less like Span<T>.
    TLDR;
    Span<T> is the wrong abstraction to be comparing to NativeArray<T> (which is optimized for it's intended purpose, being hyper-cache friendly and can be optimized/protected to work cleanly across threads via dependency checks), but Memory<T> is an API that solves a similar problem to NativeArray<T>, and lo-and-behold has similar behaviour (also a struct with pointers in it that can be manually disposed).

    One more thing:
    All of the above types are basically brand-new/in-preview (including the Native* from Unity), and Span<T>/Memory<T> in particular require C# 7.2 (even if we can get C# 7 with Unity soon-ish, there will always be some lag time, and NativeArray implementations can be controlled by Unity, platform implementations of Span<T> and Memory<T> may have issues that require someone else to fix since they're also new types themselves).
     
  22. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    I really like your answer recursive. Great summary.
     
    isaac-ashdown and recursive like this.