Search Unity

Question “NativeBool” - Worth it?

Discussion in 'Entity Component System' started by PublicEnumE, May 5, 2021.

  1. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    I’m wondering how all you smart people might approach this:

    One of our projects has a ParallelFor job, which takes a giant array of integers, splits it up into ranges, and then sums each of those ranges across multiple threads.

    If that’s not clear, here’s a better illustration:

    Source array: [5, 1, 7, 10, 3, 12, 8, 0, 4,…]

    Thread #1: 5 + 1 + 7
    Thread #2: 10 + 3 + 12
    Thread #3: 8 + 0 + 4

    …and so on.

    After this ParallelFor job completes, a follow-up also runs. It does some extra work…IF any of the sums from any of those threads is > 10.

    So - my first job needs a way to communicate with the second job.

    So far, I’ve been using a NativeQueue.ParallelWriter for this. If any of the threads finds a sum greater than 10, it adds some information to the queue. That works great. The second job can just check the length of the queue, and if it’s > 0, that means at least one of the sums was above the threshold.

    However…For fun, I’ve wondered about this. A NativeQueue is kind of overkill here. All I really need to know is if *any* of the threads found a sum greater than 10. The result I’m looking for is binary. The second job doesn’t care how many threads were > 10 - only if any of them were.

    Ive wondered if there’s a more memory efficient way to do this - for example, would be silly to write a custom, NativeBool collection type, which only allocated a single bool for each thread?

    Would that even be necessary? Could you just have all threads write to the same, single bool in ram, and then have the second job check to see if any threads have set that bool to true?

    Goes without saying - this is over optimizing. A NativeQueue works fine here. But please humor me - just for the sake on improving my memory skills. Would the single bool approach even be safe, as long as each thread could only ever set it to true?

    Thank you for any advice.
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    Yes. This is actually safe, and you don't even need to use atomic instructions. If each thread only has the option to write a single fixed value or leave the value as is, and its execution is not dependent on the existing value (WriteOnly), then it doesn't matter which thread wins the race, the result will be correct.

    You have to be very cautious to follow all the rules to pull this off, but it does come in handy. Unity uses this trick internally for updating change versions when writing to a ComponentDataFromEntity using [NativeDisableParallelForRestriction]. And they do this kind of parallel random access writing in LocalToParentSystem.
     
  3. Kmsxkuse

    Kmsxkuse

    Joined:
    Feb 15, 2019
    Posts:
    306
    Yea, I've done something similar.

    A single NativeReference to a Bool variable designated WriteOnly (I dont remember if the [WriteOnly] tag does anything, seeing how it doesnt exist for the Entities.ForEach lambdas).

    If any of the IJobParallelFor indices triggers a conditional, it sets that NativeReference to True.

    Since it never needs to read what that NativeReference was originally, it's thread safe.

    Then pass that to a second job to do whatever you need with it.
     
  4. BrendonSmuts

    BrendonSmuts

    Joined:
    Jun 12, 2017
    Posts:
    86
    One thing to remember however, if you have multiple jobs writing to this same bool, is cache invalidation. Every time you write to this value every other thread will have to re-fetch this value from the cache before it can perform its own writes, even if the thread does not care what the existing value is. Depending on your access pattern it would probably be best to keep track of a bool local to that thread context and write it back to the shared location only once at the end.