Skip to content

Force RyuJIT to optimize the code even if heuristics says it is too big. #6210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
redknightlois opened this issue Jun 24, 2016 · 16 comments
Closed
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI enhancement Product code improvement that does NOT require public API changes/additions
Milestone

Comments

@redknightlois
Copy link

From what I am seeing, when methods are too big the JIT optimization method will not happen (no inlining, no dead code removal, no dead code optimization).

There are cases where we dont care how much time it will take to optimize it (it will save the cost of optimizing billion times over the lifetime of the method). There should be a way to signal the JIT that heuristic should not apply (if it exist I will be thrilled to know how to do that).

The idea would be following the pattern of [MethodImpl(MethodImplOptions.AggressiveInlining)] and [MethodImpl(MethodImplOptions.NoOptimization)] to have another flag called [MethodImpl(MethodImplOptions.ForceOptimization)] that would disable the method size heuristic.

@CarolEidt I would code the support myself if that is what is required to see this happen ASAP.

@mikedn
Copy link
Contributor

mikedn commented Jun 24, 2016

when methods are too big the JIT optimization

How big is "too big"? What exactly is big about the method (code, number of variables)? Give some practical examples. Even non JIT compilers sometimes tone down optimizations for large functions otherwise the compilation time would be prohibitively slow in some cases.

@redknightlois
Copy link
Author

Forgot to add the code. I am at the phone right now, but look at the LZ4_compress_generic code from the link at issue of the dead code elimination you just responded.

@briansull
Copy link
Contributor

briansull commented Jun 24, 2016

The following defines control when the JIT decides to stop optimizing and drop to MIN_OPTS mode:

    // optimize maximally and/or favor speed over size?

#define DEFAULT_MIN_OPTS_CODE_SIZE 60000
#define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
#define DEFAULT_MIN_OPTS_BB_COUNT 2000
#define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
#define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000

The CodeSize value is total IL bytes and INSTR_COUNT is the total number of IL instructions
And where LV means Local Variable or Jit temps, BB means BasicBlocks.

These values are quite large and are typically only ever reached by some kind of machien generated code.

Additionally if you can use crossgen to precompile your code and we do not drop to MIN_OPTS for such cases.

@briansull
Copy link
Contributor

briansull commented Jun 24, 2016

Looking at the source code for LZ4_compress_generic code it seems unlikely that you would hit any of these limits with that code.

the actual code can be found at: https://github.com/Corvalius/ravendb/blob/lz4-131/src/Sparrow/Compression/LZ4.cs

@briansull briansull changed the title Force RyuJIT to optimize the code even if heuristics sais it is too big. Force RyuJIT to optimize the code even if heuristics says it is too big. Jun 24, 2016
@redknightlois
Copy link
Author

@briansull then there is something else preventing even aggressive inlining. I will probably have to dig further to understand the reason. I will keep you posted of anything I can gather. If you can point me into any doc that explain how to dump the jit states would be great.

@CarolEidt
Copy link
Contributor

You can set COMPlus_JitDump to the method name, and then search the dump output for "OPTIONS: opts.MinOpts() ==". It will tell you what it set it to, and there should be some indication just above it as to why.

@AndyAyersMS
Copy link
Member

Also, there are a number of reasons why methods with AggressiveInlining might not get inlined. If you can drop a checked clrjit.dll into your dotnet install, you can set COMPlus_JitPrintInlinedMethods to get a log of inlining decisions with failure reasons (this is less voluminous than a full jit dump).

@CarolEidt
Copy link
Contributor

Oh, yes - thanks @AndyAyersMS - I forgot to mention that you need a checked (or debug) jit to get the dump.

@CarolEidt
Copy link
Contributor

I'm not terribly crazy about removing all the limits. However, I am guessing that you might be running into this in a method that has lots of checks against generic parameter types. IMO, that should be a well-supported practice for generic programming, and it would be nice not to penalize such code (at least in the struct case, which as @mikedn pointed out is the one that has optimization potential in the current generics implementation). To that end, another option (that has occurred to me, though I confess I haven't gotten any farther than thinking about it) would be for the JIT to attempt to identify such patterns BEFORE applying the heuristics for minopts or inlining - I just don't know how costly such a heuristic might be that early in the JIT (i.e. when we're just looking at bytecode).

@mikedn
Copy link
Contributor

mikedn commented Jun 24, 2016

Also, there are a number of reasons why methods with AggressiveInlining might not get inlined.

For example LZ4_getPositionOnHash isn't inlined due to "No inlining for THROW within a non-void conditional". And that happens because the code lacks an "else".

@mikedn
Copy link
Contributor

mikedn commented Jun 24, 2016

And that happens because the code lacks an "else".

Actually adding the else doesn't solve the issue, the throw needs to be removed and then it inlines just fine (assuming that structs are used for directives).

@AndyAyersMS
Copy link
Member

Yep, there's a jit limitation about inlining conditional throws in methods that return values. Not sure how hard this limitation would be to remove.

For now you can work around it by removing the throw, calling a helper method to do the throw, or returning the result via an out param and changing the method return type to void. Calling a helper is probably the way to go.

@omariom
Copy link
Contributor

omariom commented Jun 24, 2016

I encountered "No inlining for THROW within a non-void conditional" once.
It prevents inlining short methods. But when throw is wrapped in another inlined method everything is fine. So the limitation doesn't look fundamental.

@redknightlois
Copy link
Author

Confirming the throw and class are preventing optimization here. At least in this case the problem isnt the heuristic, though I believe that if the limits exist, we should be able to have the ability to disable them.

@AndyAyersMS
Copy link
Member

@redknightlois if this is still relevant let us know. The inlining block you hit was removed in dotnet/coreclr#8038.

@redknightlois
Copy link
Author

Haven't hit this for a long time. This issue is indeed obsolete by now.

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 30, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI enhancement Product code improvement that does NOT require public API changes/additions
Projects
None yet
Development

No branches or pull requests

7 participants