From 8a89a0d0f7b03a9378f5d52774ba964b0524d81d Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 19 Jun 2020 11:51:36 -0700 Subject: [PATCH] JIT: allow some aggressive inlines to go over budget If we have a very small root method that calls a large method that is marked with AggressiveInlining, we may fail to inline because of a budget check. Allow such inlines to bypass the check. Closes #38106. --- src/coreclr/src/jit/inline.cpp | 12 +++++++++-- src/coreclr/src/jit/inlinepolicy.cpp | 31 +++++++++++++++++++++++----- src/coreclr/src/jit/inlinepolicy.h | 2 ++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/coreclr/src/jit/inline.cpp b/src/coreclr/src/jit/inline.cpp index d582c20b1448a1..16f32071a0cdcd 100644 --- a/src/coreclr/src/jit/inline.cpp +++ b/src/coreclr/src/jit/inline.cpp @@ -1151,8 +1151,16 @@ void InlineStrategy::NoteOutcome(InlineContext* context) bool InlineStrategy::BudgetCheck(unsigned ilSize) { - int timeDelta = EstimateInlineTime(ilSize); - return (timeDelta + m_CurrentTimeEstimate > m_CurrentTimeBudget); + const int timeDelta = EstimateInlineTime(ilSize); + const bool result = (timeDelta + m_CurrentTimeEstimate > m_CurrentTimeBudget); + + if (result) + { + JITDUMP("\nBudgetCheck: for IL Size %d, timeDelta %d + currentEstimate %d > currentBudget %d\n", ilSize, + timeDelta, m_CurrentTimeEstimate, m_CurrentTimeBudget); + } + + return result; } //------------------------------------------------------------------------ diff --git a/src/coreclr/src/jit/inlinepolicy.cpp b/src/coreclr/src/jit/inlinepolicy.cpp index 28ab5dadffa16c..22b0568ad16ac0 100644 --- a/src/coreclr/src/jit/inlinepolicy.cpp +++ b/src/coreclr/src/jit/inlinepolicy.cpp @@ -369,14 +369,33 @@ void DefaultPolicy::NoteBool(InlineObservation obs, bool value) // the candidate IL size during the inlining pass it // "reestablishes" candidacy rather than alters // candidacy ... so instead we bail out here. - + // if (!m_IsPrejitRoot) { InlineStrategy* strategy = m_RootCompiler->m_inlineStrategy; - bool overBudget = strategy->BudgetCheck(m_CodeSize); + const bool overBudget = strategy->BudgetCheck(m_CodeSize); + if (overBudget) { - SetFailure(InlineObservation::CALLSITE_OVER_BUDGET); + // If the candidate is a forceinline and the callsite is + // not too deep, allow the inline even if it goes over budget. + // + // For now, "not too deep" means a top-level inline. Note + // depth 0 is used for the root method, so inline candiate depth + // will be 1 or more. + // + assert(m_IsForceInlineKnown); + assert(m_CallsiteDepth > 0); + const bool allowOverBudget = m_IsForceInline && (m_CallsiteDepth == 1); + + if (allowOverBudget) + { + JITDUMP("Allowing over-budget top-level forceinline\n"); + } + else + { + SetFailure(InlineObservation::CALLSITE_OVER_BUDGET); + } } } @@ -531,9 +550,9 @@ void DefaultPolicy::NoteInt(InlineObservation obs, int value) case InlineObservation::CALLSITE_DEPTH: { - unsigned depth = static_cast(value); + m_CallsiteDepth = static_cast(value); - if (depth > m_RootCompiler->m_inlineStrategy->GetMaxInlineDepth()) + if (m_CallsiteDepth > m_RootCompiler->m_inlineStrategy->GetMaxInlineDepth()) { SetFailure(InlineObservation::CALLSITE_IS_TOO_DEEP); } @@ -1858,6 +1877,7 @@ void DiscretionaryPolicy::DumpSchema(FILE* file) const fprintf(file, ",CallerHasNewObj"); fprintf(file, ",CalleeDoesNotReturn"); fprintf(file, ",CalleeHasGCStruct"); + fprintf(file, ",CallsiteDepth"); } //------------------------------------------------------------------------ @@ -1940,6 +1960,7 @@ void DiscretionaryPolicy::DumpData(FILE* file) const fprintf(file, ",%u", m_CallerHasNewObj ? 1 : 0); fprintf(file, ",%u", m_IsNoReturn ? 1 : 0); fprintf(file, ",%u", m_CalleeHasGCStruct ? 1 : 0); + fprintf(file, ",%u", m_CallsiteDepth); } #endif // defined(DEBUG) || defined(INLINE_DATA) diff --git a/src/coreclr/src/jit/inlinepolicy.h b/src/coreclr/src/jit/inlinepolicy.h index e831b9a7183eca..70a71971933577 100644 --- a/src/coreclr/src/jit/inlinepolicy.h +++ b/src/coreclr/src/jit/inlinepolicy.h @@ -89,6 +89,7 @@ class DefaultPolicy : public LegalPolicy , m_Multiplier(0.0) , m_CodeSize(0) , m_CallsiteFrequency(InlineCallsiteFrequency::UNUSED) + , m_CallsiteDepth(0) , m_InstructionCount(0) , m_LoadStoreCount(0) , m_ArgFeedsTest(0) @@ -154,6 +155,7 @@ class DefaultPolicy : public LegalPolicy double m_Multiplier; unsigned m_CodeSize; InlineCallsiteFrequency m_CallsiteFrequency; + unsigned m_CallsiteDepth; unsigned m_InstructionCount; unsigned m_LoadStoreCount; unsigned m_ArgFeedsTest;