prejitResult.DetermineProfitability(methodInfo);
}
+ m_inlineStrategy->NotePrejitDecision(prejitResult);
+
// Handle the results of the inline analysis.
if (prejitResult.IsFailure())
{
{
if (FgStack::IsArgument(slot0))
{
+ compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST);
+
unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
{
if (FgStack::IsArgument(slot1))
{
+ compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST);
+
unsigned varNum = FgStack::SlotTypeToArgNum(slot1);
if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
{
m_Sibling->DumpXml(file, indent);
}
+ // Optionally suppress failing inline records
+ if ((JitConfig.JitInlineDumpXml() == 3) && !m_Success)
+ {
+ return;
+ }
+
const bool isRoot = m_Parent == nullptr;
const bool hasChild = m_Child != nullptr;
const char* inlineType = m_Success ? "Inline" : "FailedInline";
: m_Compiler(compiler)
, m_RootContext(nullptr)
, m_LastSuccessfulPolicy(nullptr)
+ , m_LastContext(nullptr)
+ , m_PrejitRootDecision(InlineDecision::UNDECIDED)
, m_CallCount(0)
, m_CandidateCount(0)
, m_AlwaysCandidateCount(0)
// If we're dumping "minimal" Xml, and we didn't do
// any inlines into this method, then there's nothing
// to emit here.
- if ((m_InlineCount == 0) && (JitConfig.JitInlineDumpXml() == 2))
+ if ((m_InlineCount == 0) && (JitConfig.JitInlineDumpXml() >= 2))
{
return;
}
fprintf(file, "%*s<SizeEstimate>%u</SizeEstimate>\n", indent + 2, "", m_CurrentSizeEstimate / 10);
fprintf(file, "%*s<TimeEstimate>%u</TimeEstimate>\n", indent + 2, "", m_CurrentTimeEstimate);
+ // For prejit roots also propagate out the assessment of the root method
+ if (isPrejitRoot)
+ {
+ fprintf(file, "%*s<PrejitDecision>%s</PrejitDecision>\n", indent + 2, "",
+ InlGetDecisionString(m_PrejitRootDecision));
+ fprintf(file, "%*s<PrejitObservation>%s</PrejitObservation>\n", indent + 2, "",
+ InlGetObservationString(m_PrejitRootObservation));
+ }
+
// Root context will be null if we're not optimizing the method.
//
// Note there are cases of this in mscorlib even in release builds,
// ------ Callee Information -------
INLINE_OBSERVATION(ARG_FEEDS_CONSTANT_TEST, bool, "argument feeds constant test", INFORMATION, CALLEE)
+INLINE_OBSERVATION(ARG_FEEDS_TEST, bool, "argument feeds test", INFORMATION, CALLEE)
INLINE_OBSERVATION(ARG_FEEDS_RANGE_CHECK, bool, "argument feeds range check", INFORMATION, CALLEE)
INLINE_OBSERVATION(BEGIN_OPCODE_SCAN, bool, "prepare to look at opcodes", INFORMATION, CALLEE)
INLINE_OBSERVATION(BELOW_ALWAYS_INLINE_SIZE, bool, "below ALWAYS_INLINE size", INFORMATION, CALLEE)
m_ImportCount++;
}
+ // Inform strategy about the inline decision for a prejit root
+ void NotePrejitDecision(const InlineResult& r)
+ {
+ m_PrejitRootDecision = r.GetPolicy()->GetDecision();
+ m_PrejitRootObservation = r.GetPolicy()->GetObservation();
+ }
+
// Dump csv header for inline stats to indicated file.
static void DumpCsvHeader(FILE* f);
static CritSecObject s_XmlWriterLock;
#endif // defined(DEBUG) || defined(INLINE_DATA)
- Compiler* m_Compiler;
- InlineContext* m_RootContext;
- InlinePolicy* m_LastSuccessfulPolicy;
- InlineContext* m_LastContext;
- unsigned m_CallCount;
- unsigned m_CandidateCount;
- unsigned m_AlwaysCandidateCount;
- unsigned m_ForceCandidateCount;
- unsigned m_DiscretionaryCandidateCount;
- unsigned m_UnprofitableCandidateCount;
- unsigned m_ImportCount;
- unsigned m_InlineCount;
- unsigned m_MaxInlineSize;
- unsigned m_MaxInlineDepth;
- int m_InitialTimeBudget;
- int m_InitialTimeEstimate;
- int m_CurrentTimeBudget;
- int m_CurrentTimeEstimate;
- int m_InitialSizeEstimate;
- int m_CurrentSizeEstimate;
- bool m_HasForceViaDiscretionary;
+ Compiler* m_Compiler;
+ InlineContext* m_RootContext;
+ InlinePolicy* m_LastSuccessfulPolicy;
+ InlineContext* m_LastContext;
+ InlineDecision m_PrejitRootDecision;
+ InlineObservation m_PrejitRootObservation;
+ unsigned m_CallCount;
+ unsigned m_CandidateCount;
+ unsigned m_AlwaysCandidateCount;
+ unsigned m_ForceCandidateCount;
+ unsigned m_DiscretionaryCandidateCount;
+ unsigned m_UnprofitableCandidateCount;
+ unsigned m_ImportCount;
+ unsigned m_InlineCount;
+ unsigned m_MaxInlineSize;
+ unsigned m_MaxInlineDepth;
+ int m_InitialTimeBudget;
+ int m_InitialTimeEstimate;
+ int m_CurrentTimeBudget;
+ int m_CurrentTimeEstimate;
+ int m_InitialSizeEstimate;
+ int m_CurrentSizeEstimate;
+ bool m_HasForceViaDiscretionary;
#if defined(DEBUG) || defined(INLINE_DATA)
long m_MethodXmlFilePosition;
break;
case InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER:
- // DefaultPolicy ignores this for prejit roots.
- if (!m_IsPrejitRoot)
- {
- m_LooksLikeWrapperMethod = value;
- }
+ m_LooksLikeWrapperMethod = value;
+ break;
+
+ case InlineObservation::CALLEE_ARG_FEEDS_TEST:
+ m_ArgFeedsTest++;
break;
case InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST:
- // DefaultPolicy ignores this for prejit roots.
- if (!m_IsPrejitRoot)
- {
- m_ArgFeedsConstantTest++;
- }
+ m_ArgFeedsConstantTest++;
break;
case InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK:
- // DefaultPolicy ignores this for prejit roots.
- if (!m_IsPrejitRoot)
- {
- m_ArgFeedsRangeCheck++;
- }
+ m_ArgFeedsRangeCheck++;
break;
case InlineObservation::CALLEE_HAS_SWITCH:
case InlineObservation::CALLEE_UNSUPPORTED_OPCODE:
- // DefaultPolicy ignores these for prejit roots.
- if (!m_IsPrejitRoot)
- {
- // Pass these on, they should cause inlining to fail.
- propagate = true;
- }
+ propagate = true;
break;
case InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST:
multiplier += 3.0;
JITDUMP("\nInline candidate has const arg that feeds a conditional. Multiplier increased to %g.", multiplier);
}
+ // For prejit roots we do not see the call sites. To be suitably optimisitic
+ // assume that call sites may pass constants.
+ else if (m_IsPrejitRoot && ((m_ArgFeedsConstantTest > 0) || (m_ArgFeedsTest > 0)))
+ {
+ multiplier += 3.0;
+ JITDUMP("\nPrejit root candidate has arg that feeds a conditional. Multiplier increased to %g.", multiplier);
+ }
switch (m_CallsiteFrequency)
{
{
switch (obs)
{
- case InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER:
- m_LooksLikeWrapperMethod = value;
- break;
-
- case InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST:
- assert(value);
- m_ArgFeedsConstantTest++;
- break;
-
- case InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK:
- assert(value);
- m_ArgFeedsRangeCheck++;
- break;
-
- case InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST:
- assert(value);
- m_ConstantArgFeedsConstantTest++;
- break;
-
case InlineObservation::CALLEE_IS_CLASS_CTOR:
m_IsClassCtor = value;
break;
, m_CallsiteFrequency(InlineCallsiteFrequency::UNUSED)
, m_InstructionCount(0)
, m_LoadStoreCount(0)
+ , m_ArgFeedsTest(0)
, m_ArgFeedsConstantTest(0)
, m_ArgFeedsRangeCheck(0)
, m_ConstantArgFeedsConstantTest(0)
InlineCallsiteFrequency m_CallsiteFrequency;
unsigned m_InstructionCount;
unsigned m_LoadStoreCount;
+ unsigned m_ArgFeedsTest;
unsigned m_ArgFeedsConstantTest;
unsigned m_ArgFeedsRangeCheck;
unsigned m_ConstantArgFeedsConstantTest;
#if defined(DEBUG) || defined(INLINE_DATA)
CONFIG_INTEGER(JitInlineDumpData, W("JitInlineDumpData"), 0)
-CONFIG_INTEGER(JitInlineDumpXml, W("JitInlineDumpXml"), 0) // 1 = full xml (all methods), 2 = minimal xml (only method
- // with inlines)
+CONFIG_INTEGER(JitInlineDumpXml, W("JitInlineDumpXml"), 0) // 1 = full xml (+ failures in DEBUG)
+ // 2 = only methods with inlines (+ failures in DEBUG)
+ // 3 = only methods with inlines, no failures
CONFIG_INTEGER(JitInlineLimit, W("JitInlineLimit"), -1)
CONFIG_INTEGER(JitInlinePolicyDiscretionary, W("JitInlinePolicyDiscretionary"), 0)
CONFIG_INTEGER(JitInlinePolicyFull, W("JitInlinePolicyFull"), 0)