Runtime: RuntimeHelpers.PrepareMethod with tiered compilation?

Created on 22 Jan 2019  路  7Comments  路  Source: dotnet/runtime

Hey,

Just a small question regarding the behavior of RuntimeHelpers.PrepareMethod in the presence of tiered compilation: Does it assume max optimizations or it generates only the thunk jump code?

area-TieredCompilation-coreclr question

Most helpful comment

Currently it prepares the tier 0 version of the code by either loading pregenerated code or by jitting it at tier 0. Tier 1 jitting usually happens in a background thread, so it would not occur in a constrained execution region. If the intention is to optimize the method as quickly as possible, it may be a better option to attribute the method with [MethodImpl(MethodImplOptions.AggressiveOptimization)], which currently would skip tier 0 for the method, then with PrepareMethod it would currently prepare the optimized version of the code. In the future though, the attribute may not immediately generate fully optimized code but it would try to optimize it as quickly as possible.

All 7 comments

cc @kouvel

Currently it prepares the tier 0 version of the code by either loading pregenerated code or by jitting it at tier 0. Tier 1 jitting usually happens in a background thread, so it would not occur in a constrained execution region. If the intention is to optimize the method as quickly as possible, it may be a better option to attribute the method with [MethodImpl(MethodImplOptions.AggressiveOptimization)], which currently would skip tier 0 for the method, then with PrepareMethod it would currently prepare the optimized version of the code. In the future though, the attribute may not immediately generate fully optimized code but it would try to optimize it as quickly as possible.

Hm.. [MethodImpl(MethodImplOptions.AggressiveOptimization)] + PrepareMethod doesn't work for me - COMPlus_JitDisasm still shows tier0 asm.

It seems to be working for me:

```c#
private static void Main(string[] args)
{
var bindingFlags = BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Static;
RuntimeHelpers.PrepareMethod(typeof(Program).GetMethod("Foo", bindingFlags).MethodHandle);
Foo();
}

[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void Foo()
{
    Foo2();
}

private static void Foo2()
{
}

```asm
; Assembly listing for method Program:Foo()
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; Tier-1 compilation
; optimized code
; rsp based frame
; partially interruptible
; Final local variable assignments
;
;# V00 OutArgs      [V00    ] (  1,  1   )  lclBlk ( 0) [rsp+0x00]   "OutgoingArgSpace"
;
; Lcl frame size = 0

G_M16031_IG01:

G_M16031_IG02:
       C3                   ret

; Total bytes of code 1, prolog size 0 for method Program:Foo()
; ============================================================

After commenting out the AggressiveOptimization attribute:

; Assembly listing for method Program:Foo()
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; Tier-0 compilation
; compiler->opts.MinOpts() is true
; rbp based frame
; partially interruptible
; Final local variable assignments
;
;  V00 OutArgs      [V00    ] (  1,  1   )  lclBlk (32) [rsp+0x00]   "OutgoingArgSpace"
;
; Lcl frame size = 32

G_M16030_IG01:
       55                   push     rbp
       4883EC20             sub      rsp, 32
       488D6C2420           lea      rbp, [rsp+20H]

G_M16030_IG02:
       E88956FFFF           call     Program:Foo2()
       90                   nop

G_M16030_IG03:
       488D6500             lea      rsp, [rbp]
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 22, prolog size 10 for method Program:Foo()
; ============================================================

@EgorBo, can you post a sample?

@kouvel hm.. can't reproduce it anymore.
In my code I had something like

typeof(Foo).GetMethods().ToList().ForEach(m => RuntimeHelpers.PrepareMethod(m.MethodHandle));

and still had tier0 output but now everything works fine... maybe I did something wrong. Sorry for bothering you.
_(I am creating an add-in for VS2019 to automate it: https://github.com/EgorBo/Disasmo)_

That add-in is pretty cool, I would use that a lot, thanks!

Although it's not an issue now, AggressiveOptimization is not guaranteed to always generate optimized code immediately, that may change in the future. There may not even be one version of best optimized code, for instance AggressiveOptimization may start with an instrumented version of code and cause the method to then transition to a version of code that is optimized based on profile data. @EgorBo I imagine such a change would break your scenario what you may want is one (unprofiled) version of optimized code, perhaps a stable way of getting that is to disable tiered compilation and get the disasm output out-of-proc with env var COMPlus_TieredCompilation=0. CC @noahfalk @AndyAyersMS

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bencz picture bencz  路  3Comments

omajid picture omajid  路  3Comments

chunseoklee picture chunseoklee  路  3Comments

noahfalk picture noahfalk  路  3Comments

jchannon picture jchannon  路  3Comments