ULONG * methodCodeSize,
CORJIT_FLAGS * compileFlags)
{
+ if (compIsForInlining())
+ {
+ // Notify root instance that an inline attempt is about to import IL
+ impInlineRoot()->m_inlineStrategy->NoteImport();
+ }
+
hashBv::Init(this);
VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal());
{
fprintf(fp, "\"%s\",", PhaseNames[i]);
}
+
+ InlineStrategy::DumpCsvHeader(fp);
+
fprintf(fp, "\"Total Cycles\",");
fprintf(fp, "\"CPS\"\n");
fclose(fp);
totCycles += m_info.m_cyclesByPhase[i];
fprintf(fp, "%I64u,", m_info.m_cyclesByPhase[i]);
}
+
+ comp->m_inlineStrategy->DumpCsvData(fp);
+
fprintf(fp, "%I64u,", m_info.m_totalCycles);
fprintf(fp, "%f\n", CycleTimer::CyclesPerSecond());
fclose(fp);
: m_Compiler(compiler)
, m_RootContext(nullptr)
, m_LastSuccessfulPolicy(nullptr)
+ , m_CallCount(0)
, m_CandidateCount(0)
- , m_InlineAttemptCount(0)
+ , m_AlwaysCandidateCount(0)
+ , m_ForceCandidateCount(0)
+ , m_DiscretionaryCandidateCount(0)
+ , m_UnprofitableCandidateCount(0)
+ , m_ImportCount(0)
, m_InlineCount(0)
, m_MaxInlineSize(DEFAULT_MAX_INLINE_SIZE)
, m_MaxInlineDepth(DEFAULT_MAX_INLINE_DEPTH)
}
//------------------------------------------------------------------------
-// NoteCandidate: do bookkeeping for an inline candidate
+// NoteAttempt: do bookkeeping for an inline attempt
+//
+// Arguments:
+// result -- InlineResult for successful inline candidate
+
+void InlineStrategy::NoteAttempt(InlineResult* result)
+{
+ assert(result->IsCandidate());
+ InlineObservation obs = result->GetObservation();
+
+ if (obs == InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE)
+ {
+ m_AlwaysCandidateCount++;
+ }
+ else if (obs == InlineObservation::CALLEE_IS_FORCE_INLINE)
+ {
+ m_ForceCandidateCount++;
+ }
+ else
+ {
+ m_DiscretionaryCandidateCount++;
+ }
+}
+
+//------------------------------------------------------------------------
+// DumpCsvHeader: dump header for csv inline stats
+//
+// Argument:
+// fp -- file for dump output
-void InlineStrategy::NoteCandidate()
+void InlineStrategy::DumpCsvHeader(FILE* fp)
{
- m_CandidateCount++;
+ fprintf(fp, "\"InlineCalls\",");
+ fprintf(fp, "\"InlineCandidates\",");
+ fprintf(fp, "\"InlineAlways\",");
+ fprintf(fp, "\"InlineForce\",");
+ fprintf(fp, "\"InlineDiscretionary\",");
+ fprintf(fp, "\"InlineUnprofitable\",");
+ fprintf(fp, "\"InlineEarlyFail\",");
+ fprintf(fp, "\"InlineImport\",");
+ fprintf(fp, "\"InlineLateFail\",");
+ fprintf(fp, "\"InlineSuccess\",");
+}
+
+//------------------------------------------------------------------------
+// DumpCsvData: dump data for csv inline stats
+//
+// Argument:
+// fp -- file for dump output
+
+void InlineStrategy::DumpCsvData(FILE* fp)
+{
+ fprintf(fp, "%u,", m_CallCount);
+ fprintf(fp, "%u,", m_CandidateCount);
+ fprintf(fp, "%u,", m_AlwaysCandidateCount);
+ fprintf(fp, "%u,", m_ForceCandidateCount);
+ fprintf(fp, "%u,", m_DiscretionaryCandidateCount);
+ fprintf(fp, "%u,", m_UnprofitableCandidateCount);
+
+ // Early failures are cases where candates are rejected between
+ // the time the jit invokes the inlinee compiler and the time it
+ // starts to import the inlinee IL.
+ //
+ // So they are "cheaper" that late failures.
+
+ unsigned profitableCandidateCount =
+ m_DiscretionaryCandidateCount - m_UnprofitableCandidateCount;
+
+ unsigned earlyFailCount = m_CandidateCount
+ - m_AlwaysCandidateCount
+ - m_ForceCandidateCount
+ - profitableCandidateCount;
+
+ fprintf(fp, "%u,", earlyFailCount);
+
+ unsigned lateFailCount = m_ImportCount - m_InlineCount;
+
+ fprintf(fp, "%u,", m_ImportCount);
+ fprintf(fp, "%u,", lateFailCount);
+ fprintf(fp, "%u,", m_InlineCount);
}
//------------------------------------------------------------------------
// context - context describing this inline
//
// Return Value:
-// Nominal estimate of jit time.
+// Nominal estimate of jit time.
int InlineStrategy::EstimateTime(InlineContext* context)
{
void InlineStrategy::NoteOutcome(InlineContext* context)
{
- // Might want to differentiate candidates from non-candidates here...
- // We don't really attempt to inline non-candidates.
- m_InlineAttemptCount++;
-
+ // Note we can't generally count up failures here -- we only
+ // create contexts for failures in debug modes, and even then
+ // we may not get them all.
if (context->IsSuccess())
{
m_InlineCount++;
// Determine if this inline is profitable
void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
{
- return m_Policy->DetermineProfitability(methodInfo);
+ m_Policy->DetermineProfitability(methodInfo);
}
// Ensure details of this inlining process are appropriately
return m_InitialSizeEstimate;
}
+ // Inform strategy that there's another call
+ void NoteCall()
+ {
+ m_CallCount++;
+ }
+
// Inform strategy that there's a new inline candidate.
- void NoteCandidate();
+ void NoteCandidate()
+ {
+ m_CandidateCount++;
+ }
+
+ // Inform strategy that a candidate was assessed and determined to
+ // be unprofitable.
+ void NoteUnprofitable()
+ {
+ m_UnprofitableCandidateCount++;
+ }
+
+ // Inform strategy that a candidate has passed screening
+ // and that the jit will attempt to inline.
+ void NoteAttempt(InlineResult* result);
+
+ // Inform strategy that jit is about to import the inlinee IL.
+ void NoteImport()
+ {
+ m_ImportCount++;
+ }
+
+ // Dump csv header for inline stats to indicated file.
+ static void DumpCsvHeader(FILE* f);
+
+ // Dump csv data for inline stats to indicated file.
+ void DumpCsvData(FILE* f);
// See if an inline of this size would fit within the current jit
// time budget.
InlineContext* m_RootContext;
InlinePolicy* m_LastSuccessfulPolicy;
InlineContext* m_LastContext;
+ unsigned m_CallCount;
unsigned m_CandidateCount;
- unsigned m_InlineAttemptCount;
+ unsigned m_AlwaysCandidateCount;
+ unsigned m_ForceCandidateCount;
+ unsigned m_DiscretionaryCandidateCount;
+ unsigned m_UnprofitableCandidateCount;
+ unsigned m_ImportCount;
unsigned m_InlineCount;
unsigned m_MaxInlineSize;
unsigned m_MaxInlineDepth;