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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug Burst erros? (v128 in structs, += operator)

Discussion in 'Burst' started by markus-seidl, Jan 8, 2023.

  1. markus-seidl

    markus-seidl

    Joined:
    Nov 29, 2021
    Posts:
    4
    Hi!

    I'm using Burst 1.8.2 in 2022.2.2f1 and encountered the following issues. I thought on reporting them, so maybe these can be fixed (or determined that I'm wrong :) ).

    1) (updated)
    Burst has a problem when using a struct with a specific placed (?) boolean in a struct that is used in the Job. See 2nd post for the difference in the struct used.

    This is the error.
    Code (CSharp):
    1. System.IndexOutOfRangeException: Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.
    (The {0} and others are in the original message and not added by me.

    This is how the class (from the 2nd post) is used:
    Code (CSharp):
    1.    
    2. private struct BurstJob_NextFloat : IJob {
    3.     public Pcg64 Rnd;
    4.     public int Rounds;
    5.  
    6.     public NativeArray<double> Stats_0;
    7.  
    8.     public void Execute() {
    9.         var ss_0 = new StreamStats();
    10.         for (var i = 0; i < Rounds; i++) {
    11.             var val = Rnd.NextFloat();
    12.  
    13.             ss_0.Add(val);
    14.         }
    15.  
    16.         ss_0.CopyToBurstArray(ref Stats_0); // copy gathered stats into the NativeArray. This produces the access error
    17.     }
    18. }
    19.  
    *BUT* this only happens with some code, this is as far as I could narrow it down so far.

    2)
    Sometimes the "+=" operator crashes Burst - sometimes. This method does:

    Code (CSharp):
    1.         /// <summary>
    2.         /// Add two 128-bit numbers with overflow between two ulong, but still inside the 128bit range (does not overflow to 256 bits).
    3.         /// </summary>
    4.         public static v128 Add128(v128 a, v128 b) {
    5.             var ret = new v128 {
    6.                 ULong0 = a.ULong0 + b.ULong0,
    7.                 ULong1 = a.ULong1 + b.ULong1
    8.             };
    9.  
    10.             if (ret.ULong0 < a.ULong0 /* || ret.ULong0 < b.ULong0 */) { // overflow check
    11.                 ret.ULong1 += 1; // += doesn't work in burst (1.8.2)
    12.             }
    13.  
    14.             return ret;
    15.         }
    with the error:

    Burst error BC1303: Cannot take a reference or pointer to intrinsic vector field `ULong1`


    While using the "+=" operator for example in a constructor on a ctor does work flawlessly.
     
    Last edited: Jan 8, 2023
  2. markus-seidl

    markus-seidl

    Joined:
    Nov 29, 2021
    Posts:
    4
    Update to 1) I could narrow it down to an additional boolean in the struct:
    I think this is related to the use or definition of "_hasBeenInitialized" in the following struct.
    This works with burst:

    Code (CSharp):
    1.     public partial struct Pcg64 : IRandom64 {
    2.         private const ulong PCG_DEFAULT_MULTIPLIER_128_H = 2_549_297_995_355_413_924ul;
    3.         private const ulong PCG_DEFAULT_MULTIPLIER_128_L = 4_865_540_595_714_422_341ul;
    4.         private const ulong PCG_DEFAULT_INCREMENT_128_H = 6_364_136_223_846_793_005ul;
    5.         private const ulong PCG_DEFAULT_INCREMENT_128_L = 1_442_695_040_888_963_407ul;
    6.  
    7.         private  v128 _multiplier;
    8.  
    9.         private  v128 _increment;
    10.      
    11.         private v128 _state;
    12.  
    13.         // private bool _hasBeenInitialized;
    14.  
    15.         public Pcg64(v128 multiplier, v128 increment, ulong seed) {
    16.             seed = Helpers.StandardSeed(seed);
    17.             _multiplier = multiplier;
    18.             _increment = increment;
    19.  
    20.             _state = new v128(0ul, 0ul);
    21.             _increment.ULong0 = (_increment.ULong0 << 1) | 1; // make sure the lowest bit is set
    22.  
    23.             // _hasBeenInitialized = true;
    24.  
    25.             // PCGs preferred initialization routine "magic".
    26.             Next();
    27.             _state.ULong0 += seed; // TODO carry?
    28.             Next();
    29.         }
    30.  
    31.         public Pcg64(ulong seed) : this(
    32.             new v128(PCG_DEFAULT_MULTIPLIER_128_L, PCG_DEFAULT_MULTIPLIER_128_H),
    33.             new v128(PCG_DEFAULT_INCREMENT_128_L, PCG_DEFAULT_INCREMENT_128_H), seed) { }
    34.  
    35.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    36.         public ulong Next() {
    37.             // Helpers.CheckState(_hasBeenInitialized); // Use a constructor to create this RNG
    38.  
    39.             var res = BitMath.mul128(_state, _multiplier);
    40.  
    41.             _state = BitMath.Add128(res, _increment);
    42.  
    43.             var value = _state.ULong1 ^ _state.ULong0;
    44.             var rot = (int)(_state.ULong1 >> 59);
    45.             return math.rol(value, rot);
    46.         }
    47.     }
    this does produce the execution error in the Job System:

    Code (CSharp):
    1.     public partial struct Pcg64 : IRandom64 {
    2.         private const ulong PCG_DEFAULT_MULTIPLIER_128_H = 2_549_297_995_355_413_924ul;
    3.         private const ulong PCG_DEFAULT_MULTIPLIER_128_L = 4_865_540_595_714_422_341ul;
    4.         private const ulong PCG_DEFAULT_INCREMENT_128_H = 6_364_136_223_846_793_005ul;
    5.         private const ulong PCG_DEFAULT_INCREMENT_128_L = 1_442_695_040_888_963_407ul;
    6.  
    7.         private  v128 _multiplier;
    8.  
    9.         private  v128 _increment;
    10.      
    11.         private v128 _state;
    12.  
    13.         private bool _hasBeenInitialized;
    14.  
    15.         public Pcg64(v128 multiplier, v128 increment, ulong seed) {
    16.             seed = Helpers.StandardSeed(seed);
    17.             _multiplier = multiplier;
    18.             _increment = increment;
    19.  
    20.             _state = new v128(0ul, 0ul);
    21.             _increment.ULong0 = (_increment.ULong0 << 1) | 1; // make sure the lowest bit is set
    22.  
    23.             _hasBeenInitialized = true;
    24.  
    25.             // PCGs preferred initialization routine "magic".
    26.             Next();
    27.             _state.ULong0 += seed; // TODO carry?
    28.             Next();
    29.         }
    30.  
    31.         public Pcg64(ulong seed) : this(
    32.             new v128(PCG_DEFAULT_MULTIPLIER_128_L, PCG_DEFAULT_MULTIPLIER_128_H),
    33.             new v128(PCG_DEFAULT_INCREMENT_128_L, PCG_DEFAULT_INCREMENT_128_H), seed) { }
    34.  
    35.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    36.         public ulong Next() {
    37.             Helpers.CheckState(_hasBeenInitialized); // Use a constructor to create this RNG
    38.  
    39.             var res = BitMath.mul128(_state, _multiplier);
    40.  
    41.             _state = BitMath.Add128(res, _increment);
    42.  
    43.             var value = _state.ULong1 ^ _state.ULong0;
    44.             var rot = (int)(_state.ULong1 >> 59);
    45.             return math.rol(value, rot);
    46.         }
    47.     }
     
    Last edited: Jan 8, 2023
  3. markus-seidl

    markus-seidl

    Joined:
    Nov 29, 2021
    Posts:
    4
    I've submitted a minimal example showing the IndexOutOfBoundsException via
    IN-28319 .
     
    tim_jones likes this.
  4. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    282
    Thank you @markus-seidl. I've also put (2) into our backlog - supporting `+=` on `v128` fields.
     
    markus-seidl likes this.
  5. Wolpen

    Wolpen

    Unity Technologies

    Joined:
    Oct 11, 2022
    Posts:
    9
    Hey @markus-seidl.
    I've looked at 1), and a fix will be in a future release.

    In the meantime, you can work around the problem by specifying your struct layout to be sequential with a pack value of 1. i.e. add the following attribute to your Pcg64 struct:
    Code (CSharp):
    1. [StructLayout(LayoutKind.Sequential, Pack = 1)]