Search Unity

BindStreamProperty is slow

Discussion in 'Animation' started by taro_b19, Jan 31, 2021.

  1. taro_b19

    taro_b19

    Joined:
    Dec 12, 2014
    Posts:
    2
    BindStreamProperty processing is very slow compared to BindStreamTransform.
    AnimationJob's Bind is a bottleneck due to high load.
    Is there any way to solve this problem?


    Sample: count=100

    Code (CSharp):
    1. public class TestComponent : MonoBehaviour
    2. {
    3.     public float a;
    4. }
    Code (CSharp):
    1. Profiler.BeginSample("BindStreamProperty");
    2. for (int i = 0; i < count; i++)
    3. {
    4.     animator.BindStreamProperty(transforms[i], typeof(TestComponent), "a");
    5. }
    6.  
    7. Profiler.EndSample();
    8. Profiler.BeginSample("BindStreamTransform");
    9. for (int i = 0; i < count; i++)
    10. {
    11.     animator.BindStreamTransform(transforms[i]);
    12. }
    13.  
    14. Profiler.EndSample();
    Result:
    Profiler.png

    BindStreamProperty is x6~8 loaded and stopping the main thread.
    UnityEditor 2020.2.2
     
  2. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    @taro_b19 Find any good ways around this?

    I suspect BindStreamProperty is doing some code generation to make writing to that property as a graph output in the future super fast. The transform version is most likely heaps faster because the API to write to a transform already exists and is knowable at compile time. There's no way to know that transform xyz has a TestComponent with a writable field/property of "a" and that type "a" even is at compile time and I doubt it's going to use pure C# reflection to access and set it's value (that would be super slow). If it's not using reflection it will need to somehow generate some code to access that field/property that at runtime as some kind of expression tree or maybe some unsafe c++ voodoo shenanigans but I'm guessing it needs to do some reflection or metadata analysis of TestComponent first to make sure "a" exists and to know what it's type is etc so it can make writes to it safely.

    Would love nothing more than to be corrected and find a way to speed this up though.
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    I'm pretty sure runtime code generation isn't allowed on platforms like iOS so I don't think that could be how it's done.

    My guess would be some sort of unsafe pointer hackery. On bind find out where the target field is relative to the object's position in memory then write there directly while animating. That's just a wild guess though, I've never done anything like that so I have no real idea how feasible it would be.
     
  4. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    I reckon it's an unsafe pointer too.

    However, code generation is allowed on iOS now, Apple changed their TOS not too long ago now but it was prohibited for a very long time. Also the newer runtimes in Unity even support compiling expression trees although with some limitations and on IL2CPP expression trees are slower than just using reflection (why I have no clue but it is), see image below (not my image, it's from this Unity Answers post I came across recently):

     
  5. taro_b19

    taro_b19

    Joined:
    Dec 12, 2014
    Posts:
    2
    @Cameron860 I haven't found a good way...

    This is a heavy load even on iOS devices, but it seems that there is no problem with execution speed if BindStreamProperty is completed.

    Currently, I have stopped using it in the game and changed to Unity Editor only to update every frame.

    Because the main thread stops for too long,
    I don't think it is possible to create a complicated Animation Job as it is.