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.

[MethodImpl(MethodImplOptions.AggressiveInlining)]

Discussion in 'Entity Component System' started by Quatum1000, Oct 13, 2018.

  1. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    886
    Hi,
    I made a test with AggressiveInlining. Would it not possible use these option with the standard c# or incremental compiler? The example script time results are the same. For the burst compiler exists a lot in-lining code stuff.

    Code (CSharp):
    1. using System.Diagnostics;
    2. using System.Runtime.CompilerServices;
    3. using UnityEngine;
    4.  
    5. public class AgressiveInliningTest : MonoBehaviour
    6. {
    7.    const int _max = 10000000;
    8.    
    9.    void Start() {
    10.        // ... Compile the methods.
    11.        Method1();
    12.        Method2();
    13.        double sum = 0;
    14.  
    15.        var s1 = Stopwatch.StartNew();
    16.        for (int i = 0; i < _max; i++) {
    17.            sum += Method1();
    18.            sum += Method1();
    19.            sum += Method1();
    20.            sum += Method1();
    21.            sum += Method1();
    22.            sum += Method1();
    23.        }
    24.        s1.Stop();
    25.        var s2 = Stopwatch.StartNew();
    26.        for (int i = 0; i < _max; i++) {
    27.            sum += Method2();
    28.            sum += Method2();
    29.            sum += Method2();
    30.            sum += Method2();
    31.            sum += Method2();
    32.            sum += Method2();
    33.        }
    34.        s2.Stop();
    35.  
    36.        UnityEngine.Debug.Log((s2.ElapsedTicks / 10000f) + " Sum: " + sum);
    37.        UnityEngine.Debug.Log((s1.ElapsedTicks / 10000f) + " Sum: " + sum);
    38.    }
    39.  
    40.    [MethodImpl(MethodImplOptions.NoInlining)]
    41.    double Method1() {
    42.        // ... No inlining.
    43.        return "one".Length + "two".Length + "three".Length +
    44.             "four".Length + "five".Length + "six".Length +
    45.             "seven".Length + "eight".Length + "nine".Length +
    46.             "ten".Length;
    47.    }
    48.  
    49.    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    50.    double Method2() {
    51.        // ... Aggressive inlining.
    52.        return "one".Length + "two".Length + "three".Length +
    53.             "four".Length + "five".Length + "six".Length +
    54.             "seven".Length + "eight".Length + "nine".Length +
    55.             "ten".Length;
    56.    }
    57. }
     
    Last edited: Oct 13, 2018
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,553
    I think [MethodImpl(MethodImplOptions.AggressiveInlining)] force the inlining with the purpose that Burst compiler can pattern match the method and replace it with something else that fits the architecture. Burst only know how to replace things in Unity.Mathematics

    In this case Burst does not know how to completely replace your custom `Method2()` code nor String.Length inside it and the method will be at best just inlined into the caller, removing just the method call cost.

    Or it might be that [MethodImpl(MethodImplOptions.AggressiveInlining)] has no effect at all in C# in the first place, but Burst lib searches for this attribute tag to find things to replace + match just the method's full name.
     
  3. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    8,792
    Additional info on inlining which is still may or may not relevant.
     
    Last edited: Oct 14, 2018
  4. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    886
    Thanks for the answers.
    Seems to be not implemented from what the guy says in the video?!

    Inlining is mainly used in case of libraries and not of hot code. This guy performs a misleading information by rhetoric, to get out of this problematic. Libraries are puzzled of single functions to get at last the main function call. On none existent Inlining, you have a massive overhead. Anyway..

    Inlining was an issue in 2017
    https://bugzilla.xamarin.com/show_bug.cgi?id=59608
    and got fixed: https://github.com/mono/mono/pull/5654
    But perhaps the mono version in unity is out dated.
     
    Last edited: Oct 14, 2018
  5. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    502
    And enabling additional optimizations as the context is fully known.

    The video is from a pre-mono runtime update, so it might be supported by the jit compiler now. I'm pretty confident IL2CPP already uses the attribute.
     
  6. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    502
    I made some tests. TLDR: AggressiveInlining seems to be implemented in Mono standalone and IL2CPP. Not active in editor.

    The methods you presented don't allow for any optimizations other than removing the call overhead. I added two math functions that allow for some optimizations when inlined (eg constant parameter).
    Code (CSharp):
    1. float Method1(float one, float two, float three)
    2. {
    3.     return (one * (two / 3f) + math.pow(three, two)) / math.pow(three, two);
    4. }
    Results
    Editor: No differences at all
    Mono: AggressiveInlining on 'your' methods: 33% SLOWER. AggressiveInlining on math functions: 10% faster.
    IL2CPP: With 'your' methods inlining doesn't make any difference. The math functions have a decent performance boost of 14%
    Burst: No difference at all. Manual inlining has nearly the same performance which let's me think it is using the default heuristics of the C++ compile and comes to the conclusion to inline it despite NoInlining. AggressiveInline might still have an effect when the function is to large to get inlined automatically.

    It seems the attribute is actually supported by Mono and IL2CPP in Standalone but the AggressiveInlining on 'your' methods shows the danger of it. When inlining to much code program may actually get slower probably due to CPU getting less effiecient due to some internal optimizations not getting activated (eg branch prediction).
     
  7. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    324
    It is a suggestion to compiler. Doesn't guarantee an inline.
     
    cgrow67 likes this.
  8. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    886
    In my case on standard C# application on this example the results are correct from this website. https://www.dotnetperls.com/aggressiveinlining

    Another example v = Vector3:Lerp(a,b,(float)t) when using my own optimized lib results in a about 80% speed up in Unity through the JIT AggressiveInlining in IL2CPP.

    Code (CSharp):
    1. // ---> INLINE JIT 2018 disassembly debug.symbols (X_ref_ASM=B00048)
    2.  
    3.        v = Vector3.Lerp(v1, v2, (float)startPercent);
    4.  
    5.        ///// <summary>
    6.        ///// Double LerpVector3
    7.        ///// </summary>
    8.        ///// <param name="a"></param>
    9.        ///// <param name="b"></param>
    10.        ///// <param name="t"></param>
    11.        ///// <returns></returns>
    12.        //[MethodImpl(MethodImplOptions.AggressiveInlining)]
    13.        //public static Vector3 LerpVector3(Vector3 a, Vector3 b, double t) {
    14.        //   t = Clamp01(t);
    15.        //   Vector3 delta = (b - a);
    16.        //   double x = a.x + delta.x * t;
    17.        //   double y = a.y + delta.y * t;
    18.        //   double z = a.z + delta.z * t;
    19.        //   return new Vector3((float)x, (float)y, (float)z);
    20.        //}
    21.  
    22.        // ---snipp---snipp
    23.        if (startPercent > 1.0) startPercent = 1.0;
    24.        if (startPercent < 0.0) startPercent = 0.0;
    25.        ax = v1.x;
    26.        ay = v1.y;
    27.        az = v1.z;
    28.        bx = v2.x;
    29.        by = v2.y;
    30.        bz = v2.z;
    31.        v.x = (float)(ax + (bx - ax) * startPercent);
    32.        v.y = (float)(ay + (by - ay) * startPercent);
    33.        v.z = (float)(az + (bz - az) * startPercent);
    34.       // ---snipp---snipp
    35.  
     
    Last edited: Oct 15, 2018
    Slight0 likes this.
  9. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    502
    That does sound a little bit to good. Running Microsoft .net? I guess they recoginze that the inlined method actually has a constant result. Maybe replace the string literals with static fields which the compiler has to assume might change.