Search Unity

[SOLVED] IJobParallelfor + BurstCompiler: Can't copy value type from static field (see error msg))

Discussion in 'Burst' started by meanmonkey, May 7, 2019.

  1. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    The fix was no big deal, as I just passed the value via job arguments, but anyway I felt I should post it. I'm not sure if this error is intentional.

    The ParallelForJob was completely empty at testing, despite this line (originally I did this with a custom struct, but for the sake of simplicity I demo this with an int):

    Code (CSharp):
    1. TestJob testJob = new TestJob();
    2. JobHandle testJobHandle = testJob.Schedule(1000, 1);
    3. testJobHandle.Complete();
    4.  
    5. ---
    6.  
    7. [BurstCompile]
    8. private struct TestJob : IJobParallelFor
    9. {
    10. public void Execute(int i)
    11. {
    12. int intZero = MyStaticClass.intZero;
    13. }
    14. }
    15.  
    16. ---
    17.  
    18. public static class MyStaticClass
    19. {
    20. public readonly static int intZero = 0;
    21. }
    Error output (no more details, disabling burstcompiling removed the error):

    System.InvalidOperationException: Jobs can only create Temp memory
    This Exception was thrown from a job compiled with Burst, which has limited exception support. Turn off burst (Jobs -> Enable Burst Compiler) to inspect full exceptions & stacktraces.

    It just seems odd to me, as I can use static mehtods too, but I'm not allowed to copy static values ?

    EDIT:
    Unity 2019.1.1.f.1
    Burst 1.0.0
    Jobs preview11-0.0.7
     
    Last edited: May 7, 2019
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    You can’t use static fields in Burst, except readonly/const fields.
     
  3. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    He is actually reading from a static readonly field though
     
    HQF and eizenhorn like this.
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Oops my bad, missed bottom part :)
     
  5. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Anyway. It works fine in my case. Without any problems. (2019.1.1f1 Burst 1.0.1 Entites preview.31)
    upload_2019-5-7_19-34-9.png

    And in our game also all works fine.
     
    Last edited: May 7, 2019
    meanmonkey likes this.
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Are you sure it's in this job and not in other job where you allocate native containers not with Allocator.Temp?

    Cos in this case you'll see your error
    upload_2019-5-7_19-43-35.png
    upload_2019-5-7_19-43-43.png
     
    meanmonkey likes this.
  7. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    Thanks for the feedback!

    That's weird.I'm on 2019.1.1f1 and all packages are up to date regarding to the package manager. But are you sure burst is 1.0.1 ? mine is 1.0.0, and there are no updates available.

    Also yes, I'm sure it's not from another job, I tested it extensively.
     
  8. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
  9. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Then retest :) I shown you, when error comes. Or show full your code here.
     
  11. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    I do have preview packages active all the time. no update for burst to 1.0.1 :-(

    It's no big issue for me at all as I could fix it by passing the values via job arguments. I just wanted to report an eventual bug. maybe it's gone with 1.0.1, I will see when the update is available for me...
     
  12. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    It works as before :) on 1.0.0 all the same
     
    Last edited: May 8, 2019
    meanmonkey likes this.
  13. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    ok thanks for testing then...I did test it several times with the testjob on/off always the same result. I have no idea how this is possible...must be some very special circumstance not obvious to me. I guess I will test it in an empty project
     
    Last edited: May 7, 2019
  14. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    @eizenhorn the secret is unveiled.... :D

    The reason for the error is a NativeArray (readonly & static, created in static constructor) in the same static class I copy the readonly struct/int/whatever from.

    I wasn't aware that static constructors are called each time a static class member is accessed, if I understand the following correctly: https://stackoverflow.com/questions/1437352/when-is-a-static-constructor-called-in-c

    Learned something :D

    Code (CSharp):
    1. TestJob testJob = new TestJob();
    2. JobHandle testJobHandle = testJob.Schedule(1000, 1);
    3. testJobHandle.Complete();
    4.  
    5. ---
    6.  
    7. [BurstCompile]
    8. private struct TestJob : IJobParallelFor
    9. {
    10. public void Execute(int i)
    11. {
    12. int intZero = MyStaticClass.intZero;
    13. }
    14. }
    15.  
    16. ---
    17.  
    18. public static class MyStaticClass
    19. {
    20. public readonly static int intZero = 0;
    21. public readonly static NativeArray<int> myNativeArray;
    22.  
    23. static MyStaticClass
    24. {
    25. myNativeArray = new NativeArray<int>(100, Allocator.Persistent);
    26. }
    27.  
    28. }
     
    Last edited: May 8, 2019
  15. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    As I told before :) Because error clearly says about native container allocation.

    Nope, it's not true. Static constructor called once, and guaranteed it'll be before first access.

    I think the problem (not actually problem, just by design) is how Burst works with static readonly values. I think in creates instances and copy to jobs when compile, and not acces to it by some static references. But it's only my things. I think @mike_acton or @Joachim_Ante or @xoofx explain it better :)
     
    meanmonkey likes this.
  16. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    OK thanks for clarifying! :) I was curious about the static constructor call, as it would have been a huge overhead.
     
  17. xoofx

    xoofx

    Unity Technologies

    Joined:
    Nov 5, 2016
    Posts:
    417
    So a static readonly field with a simple constant like the one described above:

    Code (CSharp):
    1. static readonly int MyConstant = 1;
    will be compiled directly to some readonly data in the generated code (and can be converted to a constant if they are used as constant data - e.g not using an dynamic index indirection)

    But if the static readonly contains code that we can't evaluate as a constant (any control flows will stop for example the static readonly data to be evaluated as a constant up-front), the static constructor will be called at the beginning of the job, everytime you enter the job, but relying only on the expectation that the resulting static readonly expression will still boil down to a constant when the compiler will optimize the job.

    In the case of allocating a NativeArray for a readonly static field, this is actually something that we should not support today correctly, as in practice, the NativeArray is allocated on every job schedule in that case. So it's a bug and we will have to emit an error in that case. But we will also try to improve support for this scenario so that dynamic static readonly code will be only called once when entering a function multiple time.
     
    eterlan, meanmonkey and FROS7 like this.
  18. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    I don't think this is right. the static constructor (and static field initializers) should be called exactly once per app domain, if you use the class. if you are calling it multiple times it's a bug

    e.g. in the following code
    Code (CSharp):
    1. class Foo {
    2. public static int value;
    3. }
    4. class Bar {
    5. public static readonly int value = ++Foo.value;
    6. }
    ,
    Bar.value
    should be always 1, no matter how many jobs referencing Bar you have
     
  19. xoofx

    xoofx

    Unity Technologies

    Joined:
    Nov 5, 2016
    Posts:
    417
    I was not referring to the behavior of a regular .NET CLR where it is indeed done once but not at domain load but when you access the class or a member of the class.

    In burst, as I explained previously, the behavior is different in the sense that static constructors are backed into const/read-only memory at compilation time and if it is not possible (e.g because there is a control flow), the static constructor is called on every method call, while we didn't expect them to have side effects (but we are actually not detecting external function calls - which is the case of NativeArray typically)
     
    Egad_McDad, meanmonkey and eizenhorn like this.
  20. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I hit a really strange case of this today. Or rather strange in the side effects it causes. I setup a static constructor to call NavMesh.GetSettingsByIndex. So it got called by burst and shortly thereafter Unity locked up. Looked at the logs and saw a ton of calls from all over into unity api's, most not even our code, were complaining about not being on the main thread. ECS internal code like where it schedules jobs wasn't running on the main thread. Like the thread context just got completely screwed.
     
  21. eterlan

    eterlan

    Joined:
    Sep 29, 2018
    Posts:
    177
    A irreverent noob question, I was wondering what's this static class use for, for something like storing user data? can you give me some insight about it? Thanks.:D
     
  22. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    You can't access objects from within jobs if you want to use burst compiler. But it's allowed to directly access static readonly values and static methods, too.
     
    KAV2008 and eterlan like this.
  23. xoofx

    xoofx

    Unity Technologies

    Joined:
    Nov 5, 2016
    Posts:
    417
    We have fixed this issue in burst so that the next version will forbid to call such methods. It's unfortunate that we forgot in the first place to disallow internal/dll calls inside static constructors in HPC#/burst (while you can perfectly do that in regular C#)
     
  24. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    For some global shared immutable data which filled from config on initialization
     
    meanmonkey and eterlan like this.