Skip to content

Commit

Permalink
Add JIT debugging helpers, and other debugging output improvements (#…
Browse files Browse the repository at this point in the history
…100123)

1. Add `DOTNET_JitHoistLimit` to specify the maximum number of
hoisted expressions to allow before stopping.
2. Add `DOTNET_JitStressModeNamesAllow` to allow specifying a set of
STRESS mode names to allow. Use this in conjunction with a `DOTNET_JitStress`
setting to allow JitStress to work as usual (with the usual weightings)
but only for a specified set of stress modes. This is basically the
opposite of `DOTNET_JitStressModeNamesNot`. One use is the enable JitStress,
get a JitDump, see all the JitStress mode names that were enabled, then
set `DOTNET_JitStressModeNamesAllow` to that set
(e.g., `STRESS_RANDOM_INLINE STRESS_GENERIC_VARN STRESS_UNWIND`). Remove them
one by one (or "binary search") to find the minimal set that causes a bug, to
reduce noise in the dump and additional complexity in the IR and generated code.
3. Fix a few JitDump cases missing `dspPtr` to create diffable dumps.
4. Add `DOTNET_JitInlineLimit` support to `RandomPolicy`
5. Add `DOTNET_JitNoCSE2` support to `CSE_HeuristicRandom`
6. Remove an extra newline from `eePrintObjectDescription`
  • Loading branch information
BruceForstall committed Mar 22, 2024
1 parent d59b32e commit f7334c4
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 20 deletions.
14 changes: 11 additions & 3 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2082,9 +2082,9 @@ void Compiler::compDoComponentUnitTestsOnce()
// compGetJitDefaultFill:
//
// Return Value:
// An unsigned char value used to initizalize memory allocated by the JIT.
// The default value is taken from DOTNET_JitDefaultFill, if is not set
// the value will be 0xdd. When JitStress is active a random value based
// An unsigned char value used to initialize memory allocated by the JIT.
// The default value is taken from DOTNET_JitDefaultFill. If it is not set
// the value will be 0xdd. When JitStress is active a random value based
// on the method hash is used.
//
// Notes:
Expand Down Expand Up @@ -3597,6 +3597,14 @@ bool Compiler::compStressCompileHelper(compStressArea stressArea, unsigned weigh
return false;
}

// Does user allow using this STRESS_MODE through the command line?
const WCHAR* strStressModeNamesAllow = JitConfig.JitStressModeNamesAllow();
if ((strStressModeNamesAllow != nullptr) &&
(u16_strstr(strStressModeNamesAllow, s_compStressModeNamesW[stressArea]) == nullptr))
{
return false;
}

// Does user explicitly set this STRESS_MODE through the command line?
const WCHAR* strStressModeNames = JitConfig.JitStressModeNames();
if (strStressModeNames != nullptr)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/eeinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,5 +614,5 @@ void Compiler::eePrintObjectDescription(const char* prefix, CORINFO_OBJECT_HANDL
}
}

printf("%s '%s'\n", prefix, str);
printf("%s '%s'", prefix, str);
}
5 changes: 3 additions & 2 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (origCall->IsVirtual() && (origCall->gtCallType != CT_INDIRECT) && (exactContextHnd != nullptr) &&
(origCall->gtHandleHistogramProfileCandidateInfo == nullptr))
{
JITDUMP("\nSaving context %p for call [%06u]\n", exactContextHnd, dspTreeID(origCall));
JITDUMP("\nSaving context %p for call [%06u]\n", dspPtr(exactContextHnd), dspTreeID(origCall));
origCall->gtCallMoreFlags |= GTF_CALL_M_HAS_LATE_DEVIRT_INFO;
LateDevirtualizationInfo* const info = new (this, CMK_Inlining) LateDevirtualizationInfo;
info->exactContextHnd = exactContextHnd;
Expand Down Expand Up @@ -8449,8 +8449,9 @@ void Compiler::impCheckCanInline(GenTreeCall* call,
return;
}
#endif

JITDUMP("\nCheckCanInline: fetching method info for inline candidate %s -- context %p\n",
compiler->eeGetMethodName(ftn), pParam->exactContextHnd);
compiler->eeGetMethodName(ftn), compiler->dspPtr(pParam->exactContextHnd));

if (pParam->exactContextHnd == METHOD_BEING_COMPILED_CONTEXT())
{
Expand Down
16 changes: 15 additions & 1 deletion src/coreclr/jit/inlinepolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,7 @@ void RandomPolicy::NoteInt(InlineObservation obs, int value)
// methodInfo -- method info for the callee
//
// Notes:
// The random policy makes random decisions about profitablity.
// The random policy makes random decisions about profitability.
// Generally we aspire to inline differently, not necessarily to
// inline more.

Expand All @@ -1131,6 +1131,20 @@ void RandomPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
assert(InlDecisionIsCandidate(m_Decision));
assert(m_Observation == InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE);

#if defined(DEBUG)

// Punt if we're inlining and we've reached the acceptance limit.
int limit = JitConfig.JitInlineLimit();
unsigned current = m_RootCompiler->m_inlineStrategy->GetInlineCount();

if (!m_IsPrejitRoot && (limit >= 0) && (current >= static_cast<unsigned>(limit)))
{
SetFailure(InlineObservation::CALLSITE_OVER_INLINE_LIMIT);
return;
}

#endif // defined(DEBUG)

// Budget check.
const bool overBudget = this->BudgetCheck();
if (overBudget)
Expand Down
40 changes: 28 additions & 12 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ CONFIG_INTEGER(JitReportFastTailCallDecisions, W("JitReportFastTailCallDecisions
CONFIG_INTEGER(JitPInvokeCheckEnabled, W("JITPInvokeCheckEnabled"), 0)
CONFIG_INTEGER(JitPInvokeEnabled, W("JITPInvokeEnabled"), 1)

CONFIG_INTEGER(JitHoistLimit, W("JitHoistLimit"), -1) // Specifies the maximum number of hoist candidates to hoist

// Controls verbosity for JitPrintInlinedMethods. Ignored for JitDump where
// it's always set.
CONFIG_INTEGER(JitPrintInlinedMethodsVerbose, W("JitPrintInlinedMethodsVerboseLevel"), 0)
Expand All @@ -162,9 +164,7 @@ CONFIG_INTEGER(JitSsaStress, W("JitSsaStress"), 0) // Perturb order of processin
CONFIG_INTEGER(JitStackChecks, W("JitStackChecks"), 0)
CONFIG_INTEGER(JitStress, W("JitStress"), 0) // Internal Jit stress mode: 0 = no stress, 2 = all stress, other = vary
// stress based on a hash of the method and this value
CONFIG_INTEGER(JitStressBBProf, W("JitStressBBProf"), 0) // Internal Jit stress mode
CONFIG_INTEGER(JitStressModeNamesOnly, W("JitStressModeNamesOnly"), 0) // Internal Jit stress: if nonzero, only enable
// stress modes listed in JitStressModeNames
CONFIG_INTEGER(JitStressBBProf, W("JitStressBBProf"), 0) // Internal Jit stress mode
CONFIG_INTEGER(JitStressProcedureSplitting, W("JitStressProcedureSplitting"), 0) // Always split after the first basic
// block.
CONFIG_INTEGER(JitStressRegs, W("JitStressRegs"), 0)
Expand Down Expand Up @@ -242,20 +242,33 @@ CONFIG_INTEGER(JitDumpFgBlockOrder, W("JitDumpFgBlockOrder"), 0) // 0 == bbNext
CONFIG_INTEGER(JitDumpFgMemorySsa, W("JitDumpFgMemorySsa"), 0) // non-zero: show memory phis + SSA/VNs

CONFIG_STRING(JitRange, W("JitRange"))
CONFIG_STRING(JitStressModeNames, W("JitStressModeNames")) // Internal Jit stress mode: stress using the given set of
// stress mode names, e.g. STRESS_REGS, STRESS_TAILCALL
CONFIG_STRING(JitStressModeNamesNot, W("JitStressModeNamesNot")) // Internal Jit stress mode: do NOT stress using the
// given set of stress mode names, e.g. STRESS_REGS,
// STRESS_TAILCALL
CONFIG_STRING(JitStressRange, W("JitStressRange")) // Internal Jit stress mode

// Internal Jit stress mode: stress using the given set of stress mode names, e.g. STRESS_REGS, STRESS_TAILCALL.
// Unless JitStressModeNamesOnly is non-zero, other stress modes from a JitStress setting may also be invoked.
CONFIG_STRING(JitStressModeNames, W("JitStressModeNames"))

// Internal Jit stress: if nonzero, only enable stress modes listed in JitStressModeNames.
CONFIG_INTEGER(JitStressModeNamesOnly, W("JitStressModeNamesOnly"), 0)

// Internal Jit stress mode: only allow stress using the given set of stress mode names, e.g. STRESS_REGS,
// STRESS_TAILCALL. Note that JitStress must be enabled first, and then only the mentioned stress modes are allowed
// to be used, at the same percentage weighting as with JitStress -- the stress modes mentioned are NOT
// unconditionally true for a call to `compStressCompile`. This is basically the opposite of JitStressModeNamesNot.
CONFIG_STRING(JitStressModeNamesAllow, W("JitStressModeNamesAllow"))

// Internal Jit stress mode: do NOT stress using the given set of stress mode names, e.g. STRESS_REGS, STRESS_TAILCALL
CONFIG_STRING(JitStressModeNamesNot, W("JitStressModeNamesNot"))

CONFIG_STRING(JitStressRange, W("JitStressRange")) // Internal Jit stress mode
CONFIG_METHODSET(JitEmitUnitTests, W("JitEmitUnitTests")) // Generate emitter unit tests in the specified functions
CONFIG_STRING(JitEmitUnitTestsSections, W("JitEmitUnitTestsSections")) // Generate this set of unit tests

///
/// JIT Hardware Intrinsics
///
CONFIG_INTEGER(EnableIncompleteISAClass, W("EnableIncompleteISAClass"), 0) // Enable testing not-yet-implemented
#endif // defined(DEBUG)

#endif // defined(DEBUG)

CONFIG_METHODSET(JitDisasm, W("JitDisasm")) // Print codegen for given methods
CONFIG_INTEGER(JitDisasmTesting, W("JitDisasmTesting"), 0) // Display BEGIN METHOD/END METHOD anchors for disasm testing
Expand Down Expand Up @@ -389,6 +402,7 @@ CONFIG_INTEGER(JitRLCSEGreedy, W("JitRLCSEGreedy"), 0)
CONFIG_INTEGER(JitRLCSEVerbose, W("JitRLCSEVerbose"), 0)

#if defined(DEBUG)

// Allow fine-grained controls of CSEs done in a particular method
//
// Specify method that will respond to the CSEMask.
Expand Down Expand Up @@ -440,7 +454,7 @@ CONFIG_STRING(JitRLCSEAlpha, W("JitRLCSEAlpha"))
// If nonzero, dump candidate feature values
CONFIG_INTEGER(JitRLCSECandidateFeatures, W("JitRLCSECandidateFeatures"), 0)

#endif
#endif // DEBUG

///
/// JIT
Expand Down Expand Up @@ -483,6 +497,7 @@ CONFIG_INTEGER(JitNoRngChks, W("JitNoRngChks"), 0) // If 1, don't generate range
#endif // defined(FEATURE_ENABLE_NO_RANGE_CHECKS)

#if defined(OPT_CONFIG)

CONFIG_INTEGER(JitDoAssertionProp, W("JitDoAssertionProp"), 1) // Perform assertion propagation optimization
CONFIG_INTEGER(JitDoCopyProp, W("JitDoCopyProp"), 1) // Perform copy propagation on variables that appear redundant
CONFIG_INTEGER(JitDoOptimizeIVs, W("JitDoOptimizeIVs"), 1) // Perform optimization of induction variables
Expand All @@ -509,7 +524,8 @@ CONFIG_INTEGER(JitDoValueNumber, W("JitDoValueNumber"), 1) // Perform value numb
CONFIG_METHODSET(JitOptRepeat, W("JitOptRepeat")) // Runs optimizer multiple times on the method
CONFIG_INTEGER(JitOptRepeatCount, W("JitOptRepeatCount"), 2) // Number of times to repeat opts when repeating
CONFIG_INTEGER(JitDoIfConversion, W("JitDoIfConversion"), 1) // Perform If conversion
#endif // defined(OPT_CONFIG)

#endif // defined(OPT_CONFIG)

// Max # of MapSelect's considered for a particular top-level invocation.
CONFIG_INTEGER(JitVNMapSelBudget, W("JitVNMapSelBudget"), DEFAULT_MAP_SELECT_BUDGET)
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/jit/optcse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2190,6 +2190,13 @@ void CSE_HeuristicRandom::ConsiderCandidates()
JITDUMPEXEC(m_pCompiler->gtDispTree(candidate.Expr()));
JITDUMP("\n");

#ifdef DEBUG
if (m_pCompiler->optConfigDisableCSE2())
{
continue;
}
#endif

if (dsc->defExcSetPromise == ValueNumStore::NoVN)
{
JITDUMP("Abandoned " FMT_CSE " because we had defs with different Exc sets\n", candidate.CseIndex());
Expand Down Expand Up @@ -5407,7 +5414,7 @@ bool Compiler::optConfigDisableCSE2()
{
if (verbose)
{
printf(" Disabled by jitNoCSE2 > totalCSEcount\n");
printf(" Disabled by jitNoCSE2 %d > totalCSEcount %d\n", jitNoCSE2, totalCSEcount);
}
return true;
}
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5187,6 +5187,21 @@ void Compiler::optHoistCandidate(GenTree* tree,
return;
}

#if defined(DEBUG)

// Punt if we've reached the hoisting limit.
int limit = JitConfig.JitHoistLimit();
unsigned current = m_totalHoistedExpressions; // this doesn't include the current candidate yet

if ((limit >= 0) && (current >= static_cast<unsigned>(limit)))
{
JITDUMP(" ... not hoisting in " FMT_LP ", hoist count %u >= JitHoistLimit %u\n", loop->GetIndex(), current,
static_cast<unsigned>(limit));
return;
}

#endif // defined(DEBUG)

// Expression can be hoisted
optPerformHoistExpr(tree, treeBb, loop);

Expand Down

0 comments on commit f7334c4

Please sign in to comment.