-
Notifications
You must be signed in to change notification settings - Fork 2.7k
JIT: add some devirtualization info to the inline context #20395
JIT: add some devirtualization info to the inline context #20395
Conversation
Allows the jit to remember which calls were devirtualized and which of those were then optimized to use an unboxed entry point. This info is then dumped out as part of the inline tree. Also remove some of the clutter from the COMPlus_JitPrintInlinedMethods output stream -- we don't need to see both the in-stream results and the final results, and we don't really need to know about the budget. This information is still dumped for COMPlus_JitDump.
@sandreenko PTAL For this example using System;
interface IPrint
{
void Print();
}
struct X<T> : IPrint
{
public X(T t) { _t = t; }
public void Print() { Console.WriteLine(_t); }
T _t;
}
class Y
{
static int Main()
{
var s = new X<string>("hello, world!");
((IPrint)s).Print();
return 100;
}
} the inline tree now shows the call to
We can think about propagating these bits back to the runtime so they can eventually be surfaced in the ETL, but more work is needed (likely you'd also want the failure reasons). |
@AndyAyersMS Unrelated, but where can I find docs on the failed inline reasons (such as "noinline per IL/cached result")? |
@drieseng There aren't any docs per se -- the set of possible failure reasons is here (ignore the "information" cases). Many of the failure reasons are uncommon and obscure. "No inline per IL / cached result" indicates EITHER that the method was marked with Note "earlier" can mean the jit attempted to inline the method during crossgen OR realized the method could never be inlined when crossgenning the method. So if a method is not marked as noinline and isn't getting inlined it can sometimes be a challenge to figure out why it is not getting inlined. The noinline caching is done to help speed up jitting, so that the jit doesn't spend time trying to inline methods that ultimately can't or won't be inlined. And IIRC it has a significant positive impact on jit time. I have ambitions (#6095) of splitting up this particular failure category so that instead of "cached" noinline results we can surface the actual failure reason, but haven't gotten around to it. |
FWIW it might be an interesting project to write test cases for every possible inline failure so we have something we can refer to.... note some of them will have to be written in IL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with few comments.
failedContext->m_Sibling = parentContext->m_Child; | ||
parentContext->m_Child = failedContext; | ||
failedContext->m_Child = nullptr; | ||
failedContext->m_Offset = stmt->gtStmtILoffsx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you are here, could you please fix headers/signature for
InlineContext* InlineStrategy::NewSuccess(InlineInfo* inlineInfo)
and
InlineContext* InlineStrategy::NewFailure(GenTreeStmt* stmt, InlineResult* inlineResult)
,
they probably should be the same (and the headers are), but NewSuccess
doesn't have stmt - statement containing call being inlined
as argument.
Then maybe it will be obvious how to extract this two similar initialization lists into one method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update the comment, but are you suggesting common out some of the work these two methods do?
It may be clunky as they don't have access to the same data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can delete GenTreeStmt* stmt
arg from NewFailure
and do what NewSuccess
does:
GenTreeStmt* stmt = inlineInfo->iciStmt;
calleeContext->m_Offset = stmt->AsStmt()->gtStmtILoffsx;
<- looks like we do not need this cast here, it is already a statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently don't have access to the InlineInfo
for the failure cases.
I'll remove the cast too.
@sandreenko Made a few updates based on your feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
OSX failure is:
ubuntu arm failure is similar....
windows arm failure looks like an infrastructure problem:
None of these seem related. First two have been reported in #20392. |
Allows the jit to remember which calls were devirtualized and which of those were then optimized to use an unboxed entry point. This info is then dumped out as part of the inline tree. Also remove some of the clutter from the COMPlus_JitPrintInlinedMethods output stream -- we don't need to see both the in-stream results and the final results, and we don't really need to know about the budget. This information is still dumped for COMPlus_JitDump.
Allows the jit to remember which calls were devirtualized and which
of those were then optimized to use an unboxed entry point. This info
is then dumped out as part of the inline tree.
Also remove some of the clutter from the COMPlus_JitPrintInlinedMethods
output stream -- we don't need to see both the in-stream results and
the final results, and we don't really need to know about the budget.
This information is still dumped for COMPlus_JitDump.