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

Interface delegate caching, smart or stupid?

Discussion in 'Scripting' started by kkkkkkkkkkk0, Nov 23, 2021.

  1. kkkkkkkkkkk0

    kkkkkkkkkkk0

    Joined:
    Nov 23, 2021
    Posts:
    7
    Consider following snippet:
    Code (CSharp):
    1.  
    2.     class Test : MonoBehaviour
    3.     {
    4.         interface IInterface
    5.         {
    6.             string SayMyName();
    7.             Coroutine StartSomeFunc(int inputVar);
    8.         }
    9.  
    10.         class Impl : IInterface
    11.         {
    12.  
    13.             public string SayMyName()
    14.             {
    15.                 return "Bob";
    16.             }
    17.            
    18.             IEnumerator SomeFunc(int inputVar)
    19.             {
    20.                 var i = 0;
    21.                 while (i < 999999999)
    22.                 {
    23.                     Debug.Log(i++);
    24.                 }
    25.                 yield return null;
    26.             }
    27.  
    28.             public Coroutine StartSomeFunc(int inputVar)
    29.             {
    30.                 return StartCoroutine(SomeFunc(inputVar));
    31.             }
    32.  
    33.         }
    34.  
    35.         void Exec()
    36.         {
    37.             IInterface implA0 = new Impl();
    38.             IInterface implB0 = new Impl();
    39.            
    40.             // This is standard
    41.             string out10 = implA0.SayMyName();
    42.             Coroutine out11 = implA0.StartSomeFunc(5);
    43.            
    44.             // Is this better?
    45.             Func<string> func1 = implB0.SayMyName;
    46.             Func<int, Coroutine> func2 = implB0.StartSomeFunc;
    47.             string out20 = func1.Invoke();
    48.             Coroutine out21 = func2.Invoke(55);
    49.  
    50.         }
    51.     }
    Considering that I'll cache func1 and func2 is this more performant than direct interface access? I need to access these functions in interfaces a lot, but I've heard that interfaces are slow relative to direct functions and number one technique of fighting delay of reflection is to cache the function inside a delegate. So, does this work well?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,954
    What does the profiler tell you? And for what platform? Remember it will be completely different between an IL target and Javascript target and a native C (IL2CPP) target.

    DO NOT OPTIMIZE CODE JUST BECAUSE... If you don't have a problem, DO NOT OPTIMIZE!

    If you DO have a problem, always start by using the profiler:

    Window -> Analysis -> Profiler

    Failure to use the profiler means you're just guessing, making a mess of your code for no good reason.

    https://forum.unity.com/threads/is-...ng-square-roots-in-2021.1111063/#post-7148770

    Notes on optimizing UnityEngine.UI setups:

    https://forum.unity.com/threads/how...form-data-into-an-array.1134520/#post-7289413
     
  3. kkkkkkkkkkk0

    kkkkkkkkkkk0

    Joined:
    Nov 23, 2021
    Posts:
    7
    I didn't create anything yet because full implementation would be too complicated to make it out whether it is more performant. Identifying tiny part of a function within larger system would be more of a problem than using someone's experience to say "yes" or "no".

    All of them. I can't (and think barely anybody does) write specific C# code for every operating system, one code compiles to all. Target platform is irrelevant.

    Would you tell me the same if I had ran reflections to everywhere? "DO NOT OPTIMIZE JUST BECAUSE". Interfaces are also known to be slow (although faster than Reflection), and I already know that there will be many invocations, any 5 or 10 or 20 FPS that I can gain is already worth it.

    My main question was whether saving interface methods into delegates makes C# compiler think things through more and makes it somehow more optimal under the hood, which I cannot access.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,954
    Yes. If you did that, one of two things would happen:

    1. it would be adequately performant, you ship your game

    2. it is NOT adequately performant and changes have to be made.

    But what changes??

    Until that happens, there's no way to fantasize in advance what might or might not be performant.

    I know you want it to be that way but it's not. It's not a thing.
     
  5. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I think Kurt is very right: you should profile these things. In this case, you don't even need something very complex to get an idea; it's like 10 lines of code. Also, it's usually very easy to refactor code to add cache delegates if needed. Like, come on, this is not the same as reflection; there's nothing obviously slow here. The real bottle necks are often a surprise, so it's better to make your code easy to change, instead of trying to make the perfect code.

    That said, in my experience, delegates and interface calls are mostly equally fast. Supposedly, delegates in IL2CPP have been improved performance wise in 2021.2, but I haven't tested it. Even then, I don't think it's worth the extra memory for delegates, and the cognitive load they would bring.

    The only exception I know would be if the interface is accessed through covariance/contravariance; that can be pretty slow in IL2CPP. In my current project, some covariant calls were about five times as slow as delegates. I should say that applying that trick translated to about 3% of overall gains in my case, and I was using it quite a bit in that one case. So, again, you should test these things in your projects.
     
    kkkkkkkkkkk0 likes this.