Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Removing s_Il2CppMethodInitialized from il2cpp output

Discussion in 'Scripting' started by troylightfox, May 14, 2024.

  1. troylightfox

    troylightfox

    Joined:
    Feb 1, 2023
    Posts:
    37
    So one of the worst and most pointless performance penalties in il2cpp are the static variable checks at the top of functions:

    Code (CSharp):
    1. IL2CPP_EXTERN_C IL2CPP_METHOD_ATTR AxisControl_tD6613A2445A3C2BFA22C77E16CA3201AF72354A7* FastTouchscreen_Initialize_ctrlTouchscreentouch2deltaright_m41BF07FF5552D28B90B9241BD75DAC08516CCC29 (FastTouchscreen_t283B7BBFB4762C6E85B0582C5547D08D666BFED7* __this, InternedString_t8D62A48CB7D85AAE9CFCCCFB0A77AC2844905735 ___0_kAxisLayout, InputControl_t74F06B623518F992BF8E38656A5E0857169E3E2E* ___1_parent, const RuntimeMethod* method)
    2. {
    3.     static bool s_Il2CppMethodInitialized;
    4.     if (!s_Il2CppMethodInitialized)
    5.     {
    6.         il2cpp_codegen_initialize_runtime_metadata((uintptr_t*)&AxisControl_tD6613A2445A3C2BFA22C77E16CA3201AF72354A7_il2cpp_TypeInfo_var);
    7.         il2cpp_codegen_initialize_runtime_metadata((uintptr_t*)&InputStateBlock_t0E05211ACF29A99C0FE7FC9EA7042196BFF1F3B5_il2cpp_TypeInfo_var);
    8.       il2cpp_codegen_initialize_runtime_metadata((uintptr_t*)&_stringLiteralA74F11BB6632DDE7D6577D711E3C10FB4B304972);
    9.         il2cpp_codegen_initialize_runtime_metadata((uintptr_t*)&_stringLiteralB1E5119D36EC43B340C0A0DDC99F1156546EA9DF);
    10.         s_Il2CppMethodInitialized = true;
    11.     }
    In our codebase, there are 59,350 such checks. Obviously this could be done once at start up, and the static check in every function removed.

    In Il2CPP.Api.Output.xml in the il2cpp folder, there's a list of il2cpp command line arguments that includes:
    EnableLazyStaticConstructors
    This seems to be off, as confirmed by the il2cpp output folder's analytics.json only containing one option: EnableInlining.

    Just to confirm - I tried using PlayerSettings.SetAdditionalIl2CppArgs(addlArgs); to *add* EnableLazyStaticConstructors, and it had no effect on the number. So it seems as though EnableLazyStaticConstructors is always on?

    This is on Unity 2022.3.19f1.

    Does anybody know how to move these static calls out so they're initialized on startup?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,357
    Look closer... they already are. :)

    Well, not at startup, but only once per function and after that it's only a bool check.

    Yes, it's still a bool check, but meh, prove it's a problem before restructuring someone else's emitted code!
     
  3. troylightfox

    troylightfox

    Joined:
    Feb 1, 2023
    Posts:
    37
    Kurt, respectfully, you really shouldn't even post if you're going to be this unhelpful - just keep it to yourself.

    I've been profiling the hottest parts of our game at the line level with Superluminal, and have already had to work around this problem several times(i.e. by moving from a generic to a non-generic).

    Between this, il2cpp_rgctx_method and the many, many memory barriers, Dictionary<> and GetHashCode() are dramatically slower than they have any right to be. This one in particular is the most pointless - if we had a "post il2cpp output but pre compilation" callback, I would just write a quick tool to move these out.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,357
    It would have been really nice if you had said that in the first place.

    It's rare that people on this forum even know what a profiler is. If you had perhaps pointed out that you had actually measured, I think I would have read your post differently.

    Re-reading your post now, I now see your actual meaning here:

    I originally read it that you were asserting the calls to this il2cpp_codegen_initialize_runtime_metadata() method were the hotspot, not the checking of that bool.
     
  5. troylightfox

    troylightfox

    Joined:
    Feb 1, 2023
    Posts:
    37
    @JoshPeterson do you know is EnableLazyStaticConstructors is stuck on, or if there's anyway to move all of these static method initializations out to start up so we don't pay for the static bool dereference & check on every invocation?
     
  6. Spy-Master

    Spy-Master

    Joined:
    Aug 4, 2022
    Posts:
    838
  7. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,682
    Spy-Master likes this.
  8. troylightfox

    troylightfox

    Joined:
    Feb 1, 2023
    Posts:
    37
    @xoofx @joncham @BillHolmes do any of you know if there's a plan to fix this? I understand the desire for complete mono compatibility, but some of the implementation choices in il2cpp make code i.e. using Dictionary dramatically slower than their mono equivalent.
     
  9. ScottHFerguson

    ScottHFerguson

    Unity Technologies

    Joined:
    Dec 13, 2019
    Posts:
    12
    There seem to be a few different questions/issues here and I’ll do my best to try to answer them.

    First of all the s_Il2CppMethodInitialized checks are unrelated to static constructors or static fields. They will be generated in any method that needs to access any metadata information, this include type handles, method information, or even constant strings. Yes, even constant strings are metadata - string data is stored in the global-metadata.dat file and at runtime we need to allocate System.String objects.

    These checks exist because .NET has a rich metadata system and any runtime that implements .NET will have to access metadata (regardless of reflection usage) to run (e.g. to allocate objects). JIT implementations have a benefit here because they can check at JIT time the needed metadata has been loaded and emit unchecked access to it.

    It is theoretically possible that we could load all of this at startup, but that would have a startup time and memory usage cost and would certainly load things that would never be used. If there are 59,350 methods with metadata load checks, each of those likely loads multiple items so you could easily be talking about allocating and populating a quarter million objects. That’s going to add up.


    Static constructors are another issue. It turns out that for some classes, it can be very important when, and in what order they run. We did end up eventually addressing https://issuetracker.unity3d.com/is...tialized-and-il2cpp-runtime-class-init-checks by adding support for an Unity.IL2CPP.CompilerSerices.Il2CppEagerStaticClassConstructionAttribute Any class with that attribute will have its static constructor run at startup and can elide the il2cpp_codegen_initialize_runtime_metadata checks.

    As for EnableLazyStaticConstructors, that is not a supported option (nor documented), it has no effect. There was an attempt in the past to run all static constructors at startup and it did not work out.

    On the topic of rgctx_data, this is how metadata is accessed in shared generic code. IL2CPP, like most runtimes, generates shared code for reference type generics since all reference types are pointer sized and have the same GC rules. But for any type or method metadata access we do need a level of indirection, hence rgctx_data. Which is essentially the same data that would have been loaded in the s_Il2CppMethodInitialized section, but accessed in an array by index. Not having this would greatly increase our size and build times.

    And write barriers are artifacts of the incremental GC. When the incremental GC is enabled we need to inform the GC when GC tracked fields are changed to keep the incremental collection up to date. Turning off the incremental GC would remove them, of course at the cost of higher GC collection spikes. Note these would also exist in Mono when the incremental GC is enabled.

    We have done some minor things to remove the need for some of these runtime checks, but currently we don’t have any plans to reduce them. And there is very little chance we will ever be able to completely remove them. Some of these issues are just part of supporting a language with a rich metadata system and a garbage collector.
     
  10. troylightfox

    troylightfox

    Joined:
    Feb 1, 2023
    Posts:
    37
    Thank you very much for the detailed info, @ScottHFerguson ! I suspect this thread will be referred to many times in the year ahead by folks like me trying to find information about il2cpp. Thanks for confirming that static constructors at startup was attempted and removed because it didn't work out.

    We'll give Il2CppEagerStaticClassConstructionAttribute a shot, as well as looking at the impact of disabling incremental GC.