Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

When QuickJit is enabled, disable it for methods that contain loops by default #24252

Merged
merged 5 commits into from
May 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Documentation/project-docs/clr-configuration-knobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Name | Description | Type

## Environment/Registry Configuration Knobs

This table was machine-generated using `clr-configuration-knobs.csx` script from repository commit [d064ffb](https://github.com/dotnet/coreclr/commit/d064ffb6b05c4f7fa44c7ee389e9694e64a76c08) on 15/04/2019. It might be out of date. To generate latest documentation run `{dotnet-script} clr-configuration-knobs.csx` from this file directory.
This table was machine-generated using `clr-configuration-knobs.csx` script from repository commit [0ae3d02](https://github.com/dotnet/coreclr/commit/0ae3d020f82c3f8650b7e5eeaf9f1030f7e7e785) on 4/25/2019. It might be out of date. To generate latest documentation run `dotnet-script clr-configuration-knobs.csx` from this file directory.

When using these configurations from environment variables, the variables need to have the `COMPlus_` prefix in their names. e.g. To set DumpJittedMethods to 1, add the environment variable `COMPlus_DumpJittedMethods=1`.

Expand Down Expand Up @@ -802,12 +802,12 @@ Name | Description | Type | Class | Default Value | Flags

Name | Description | Type | Class | Default Value | Flags
-----|-------------|------|-------|---------------|-------
`TC_QuickJit` | For methods that would be jitted, enable using quick JIT when appropriate. | `DWORD` | `UNSUPPORTED` | `0` |
`TC_StartupTier_CallCounting` | Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers | `DWORD` | `INTERNAL` | `1` |
`TC_StartupTier_CallCountingDelayMs` | A perpetual delay in milliseconds that is applied call counting in the startup tier and jitting at higher tiers, while there is startup-like activity. | `DWORD` | `UNSUPPORTED` | `100` |
`TC_StartupTier_CallCountThreshold` | Number of times a method must be called in the startup tier after which it is promoted to the next tier. | `DWORD` | `UNSUPPORTED` | `30` |
`TC_StartupTier_DelaySingleProcMultiplier` | Multiplier for TC_StartupTier_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor. | `DWORD` | `UNSUPPORTED` | `10` |
`TC_StartupTier_OptimizeCode` | Use optimized codegen (normally used by the optimized tier) in the startup tier | `DWORD` | `INTERNAL` | `0` |
`TC_CallCounting` | Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers | `DWORD` | `INTERNAL` | `1` |
`TC_CallCountingDelayMs` | A perpetual delay in milliseconds that is applied call counting in tier 0 and jitting at higher tiers, while there is startup-like activity. | `DWORD` | `INTERNAL` | `100` |
`TC_CallCountThreshold` | Number of times a method must be called in tier 0 after which it is promoted to the next tier. | `DWORD` | `INTERNAL` | `30` |
`TC_DelaySingleProcMultiplier` | Multiplier for TC_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor. | `DWORD` | `INTERNAL` | `10` |
`TC_QuickJit` | For methods that would be jitted, enable using quick JIT when appropriate. | `DWORD` | `EXTERNAL` | `0` |
`TC_QuickJitForLoops` | When quick JIT is enabled, quick JIT may also be used for methods that contain loops. | `DWORD` | `UNSUPPORTED` | `0` |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be EXTERNAL?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same for TC_QuickJit?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think TC_QuickJit should be "external" to indicate that it is supported. For TC_QuickJitForLoops, "unsupported" is probably appropriate. It doesn't affect whether the options can be configured with any means.

`TieredCompilation` | Enables tiered compilation | `DWORD` | `EXTERNAL` | `1` |

#### TypeLoader Configuration Knobs
Expand Down
13 changes: 6 additions & 7 deletions src/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -645,13 +645,12 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_GainExponent,
///
#ifdef FEATURE_TIERED_COMPILATION
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TieredCompilation, W("TieredCompilation"), 1, "Enables tiered compilation")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_QuickJit, W("TC_QuickJit"), 0, "For methods that would be jitted, enable using quick JIT when appropriate.")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_StartupTier_CallCountThreshold, W("TC_StartupTier_CallCountThreshold"), 30, "Number of times a method must be called in the startup tier after which it is promoted to the next tier.")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_StartupTier_CallCountingDelayMs, W("TC_StartupTier_CallCountingDelayMs"), 100, "A perpetual delay in milliseconds that is applied call counting in the startup tier and jitting at higher tiers, while there is startup-like activity.")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_StartupTier_DelaySingleProcMultiplier, W("TC_StartupTier_DelaySingleProcMultiplier"), 10, "Multiplier for TC_StartupTier_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.")

RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_StartupTier_CallCounting, W("TC_StartupTier_CallCounting"), 1, "Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_StartupTier_OptimizeCode, W("TC_StartupTier_OptimizeCode"), 0, "Use optimized codegen (normally used by the optimized tier) in the startup tier")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_QuickJit, W("TC_QuickJit"), 0, "For methods that would be jitted, enable using quick JIT when appropriate.")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_QuickJitForLoops, W("TC_QuickJitForLoops"), 0, "When quick JIT is enabled, quick JIT may also be used for methods that contain loops.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountThreshold, W("TC_CallCountThreshold"), 30, "Number of times a method must be called in tier 0 after which it is promoted to the next tier.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountingDelayMs, W("TC_CallCountingDelayMs"), 100, "A perpetual delay in milliseconds that is applied call counting in tier 0 and jitting at higher tiers, while there is startup-like activity.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DelaySingleProcMultiplier, W("TC_DelaySingleProcMultiplier"), 10, "Multiplier for TC_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCounting, W("TC_CallCounting"), 1, "Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers")
#endif

///
Expand Down
3 changes: 2 additions & 1 deletion src/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ enum CorInfoFlag
CORINFO_FLG_INTRINSIC = 0x00400000, // This method MAY have an intrinsic ID
CORINFO_FLG_CONSTRUCTOR = 0x00800000, // This method is an instance or type initializer
CORINFO_FLG_AGGRESSIVE_OPT = 0x01000000, // The method may contain hot code and should be aggressively optimized if possible
// CORINFO_FLG_UNUSED = 0x02000000,
CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS = 0x02000000, // Indicates that tier 0 JIT should not be used for a method that contains a loop
CORINFO_FLG_NOSECURITYWRAP = 0x04000000, // The method requires no security checks
CORINFO_FLG_DONT_INLINE = 0x10000000, // The method should not be inlined
CORINFO_FLG_DONT_INLINE_CALLER = 0x20000000, // The method should not be inlined, nor should its callers. It cannot be tail called.
Expand Down Expand Up @@ -864,6 +864,7 @@ enum CorInfoMethodRuntimeFlags
CORINFO_FLG_BAD_INLINEE = 0x00000001, // The method is not suitable for inlining
CORINFO_FLG_VERIFIABLE = 0x00000002, // The method has verifiable code
CORINFO_FLG_UNVERIFIABLE = 0x00000004, // The method has unverifiable code
CORINFO_FLG_SWITCHED_TO_TIER1 = 0x00000008, // The JIT decided to switch to tier 1 for this method, when a different tier was requested
};


Expand Down
8 changes: 8 additions & 0 deletions src/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5814,6 +5814,8 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
info.compTotalHotCodeSize = 0;
info.compTotalColdCodeSize = 0;

fgHasBackwardJump = false;

#ifdef DEBUG
compCurBB = nullptr;
lvaTable = nullptr;
Expand Down Expand Up @@ -5946,6 +5948,12 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
goto _Next;
}

if (fgHasBackwardJump && (info.compFlags & CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS) != 0 && fgCanSwitchToTier1())
{
// Method likely has a loop, switch to the OptimizedTier to avoid spending too much time running slower code
fgSwitchToTier1();
}

compSetOptimizationLevel();

#if COUNT_BASIC_BLOCKS
Expand Down
7 changes: 7 additions & 0 deletions src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5289,6 +5289,13 @@ class Compiler
void fgInitBBLookup();
BasicBlock* fgLookupBB(unsigned addr);

bool fgHasBackwardJump;

bool fgCanSwitchToTier1();
void fgSwitchToTier1();

bool fgMayExplicitTailCall();

void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);

void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
Expand Down
97 changes: 97 additions & 0 deletions src/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4252,6 +4252,94 @@ class FgStack
unsigned depth;
};

//------------------------------------------------------------------------
// fgCanSwitchToTier1: Determines if conditions are met to allow switching the opt level to tier 1
//
// Return Value:
// True if the opt level may be switched to tier 1, false otherwise
//
// Assumptions:
// - compInitOptions() has been called
// - compSetOptimizationLevel() has not been called
//
// Notes:
// This method is to be called at some point before compSetOptimizationLevel() to determine if the opt level may be
// changed based on information gathered in early phases.

bool Compiler::fgCanSwitchToTier1()
{
bool result = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT) &&
!opts.compDbgCode && !compIsForInlining();
if (result)
{
// Ensure that it would be safe to change the opt level
assert(opts.compFlags == CLFLG_MINOPT);
assert(!opts.IsMinOptsSet());
}

return result;
}

//------------------------------------------------------------------------
// fgSwitchToTier1: Switch the opt level to tier 1
//
// Assumptions:
// - fgCanSwitchToTier1() is true
// - compSetOptimizationLevel() has not been called
//
// Notes:
// This method is to be called at some point before compSetOptimizationLevel() to switch the opt level to tier 1
// based on information gathered in early phases.

void Compiler::fgSwitchToTier1()
{
assert(fgCanSwitchToTier1());

// Switch to tier 1 and re-init options
assert(opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0));
opts.jitFlags->Clear(JitFlags::JIT_FLAG_TIER0);
opts.jitFlags->Set(JitFlags::JIT_FLAG_TIER1);
compInitOptions(opts.jitFlags);

// Notify the VM of the change
info.compCompHnd->setMethodAttribs(info.compMethodHnd, CORINFO_FLG_SWITCHED_TO_TIER1);
}

//------------------------------------------------------------------------
// fgMayExplicitTailCall: Estimates conservatively for an explicit tail call, if the importer may actually use a tail
// call.
//
// Return Value:
// - False if a tail call will not be generated
// - True if a tail call *may* be generated
//
// Assumptions:
// - compInitOptions() has been called
// - info.compIsVarArgs has been initialized
// - An explicit tail call has been seen
// - compSetOptimizationLevel() has not been called

bool Compiler::fgMayExplicitTailCall()
{
assert(!compIsForInlining());

if (info.compFlags & CORINFO_FLG_SYNCH)
{
// Caller is synchronized
return false;
}

#if !FEATURE_FIXED_OUT_ARGS
if (info.compIsVarArgs)
{
// Caller is varargs
return false;
}
#endif // FEATURE_FIXED_OUT_ARGS

return true;
}

//------------------------------------------------------------------------
// fgFindJumpTargets: walk the IL stream, determining jump target offsets
//
Expand Down Expand Up @@ -5137,6 +5225,7 @@ void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock)
if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0)
{
block->bbFlags |= BBF_BACKWARD_JUMP;
fgHasBackwardJump = true;
}
}
}
Expand Down Expand Up @@ -5516,6 +5605,14 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F
#endif // !FEATURE_CORECLR && _TARGET_AMD64_
}

if (fgCanSwitchToTier1() && fgMayExplicitTailCall())
{
// Method has an explicit tail call that may run like a loop or may not be generated as a tail
// call in tier 0, switch to tier 1 to avoid spending too much time running slower code and to
// avoid stack overflow from recursion
fgSwitchToTier1();
}

#if !defined(FEATURE_CORECLR) && defined(_TARGET_AMD64_)
if (isCallPopAndRet)
{
Expand Down
4 changes: 2 additions & 2 deletions src/vm/callcounter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ bool CallCounter::IsEligibleForTier0CallCounting(MethodDesc* pMethodDesc)
_ASSERTE(pMethodDesc != NULL);
_ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());

return g_pConfig->TieredCompilation_StartupTier_CallCounting() && !pMethodDesc->RequestedAggressiveOptimization();
return g_pConfig->TieredCompilation_CallCounting() && !pMethodDesc->RequestedAggressiveOptimization();
}

bool CallCounter::IsTier0CallCountingEnabled(MethodDesc* pMethodDesc)
Expand Down Expand Up @@ -131,7 +131,7 @@ void CallCounter::OnMethodCalled(
if (pEntry == NULL)
{
isFirstTier0Call = true;
tier0CallCountLimit = (int)g_pConfig->TieredCompilation_StartupTier_CallCountThreshold() - 1;
tier0CallCountLimit = (int)g_pConfig->TieredCompilation_CallCountThreshold() - 1;
_ASSERTE(tier0CallCountLimit >= 0);
m_methodToCallCount.Add(CallCounterEntry(pMethodDesc, tier0CallCountLimit));
}
Expand Down
42 changes: 21 additions & 21 deletions src/vm/eeconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,10 @@ HRESULT EEConfig::Init()
#if defined(FEATURE_TIERED_COMPILATION)
fTieredCompilation = false;
fTieredCompilation_QuickJit = false;
fTieredCompilation_StartupTier_CallCounting = false;
fTieredCompilation_StartupTier_OptimizeCode = false;
tieredCompilation_StartupTier_CallCountThreshold = 1;
tieredCompilation_StartupTier_CallCountingDelayMs = 0;
fTieredCompilation_QuickJitForLoops = false;
fTieredCompilation_CallCounting = false;
tieredCompilation_CallCountThreshold = 1;
tieredCompilation_CallCountingDelayMs = 0;
#endif

#ifndef CROSSGEN_COMPILE
Expand Down Expand Up @@ -1203,29 +1203,30 @@ HRESULT EEConfig::sync()
dwSleepOnExit = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_SleepOnExit);

#if defined(FEATURE_TIERED_COMPILATION)
fTieredCompilation = Configuration::GetKnobBooleanValue(W("System.Runtime.TieredCompilation"), CLRConfig::EXTERNAL_TieredCompilation) != 0;
fTieredCompilation = Configuration::GetKnobBooleanValue(W("System.Runtime.TieredCompilation"), CLRConfig::EXTERNAL_TieredCompilation);

fTieredCompilation_QuickJit =
Configuration::GetKnobBooleanValue(
W("System.Runtime.TieredCompilation.QuickJit"),
CLRConfig::UNSUPPORTED_TC_QuickJit) != 0;
CLRConfig::EXTERNAL_TC_QuickJit);
fTieredCompilation_QuickJitForLoops =
Configuration::GetKnobBooleanValue(
W("System.Runtime.TieredCompilation.QuickJitForLoops"),
CLRConfig::UNSUPPORTED_TC_QuickJitForLoops);

fTieredCompilation_StartupTier_CallCounting = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_StartupTier_CallCounting) != 0;
fTieredCompilation_StartupTier_OptimizeCode = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_StartupTier_OptimizeCode) != 0;
fTieredCompilation_CallCounting = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCounting) != 0;

tieredCompilation_StartupTier_CallCountThreshold =
CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TC_StartupTier_CallCountThreshold);
if (tieredCompilation_StartupTier_CallCountThreshold < 1)
tieredCompilation_CallCountThreshold = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCountThreshold);
if (tieredCompilation_CallCountThreshold < 1)
{
tieredCompilation_StartupTier_CallCountThreshold = 1;
tieredCompilation_CallCountThreshold = 1;
}
else if (tieredCompilation_StartupTier_CallCountThreshold > INT_MAX) // CallCounter uses 'int'
else if (tieredCompilation_CallCountThreshold > INT_MAX) // CallCounter uses 'int'
{
tieredCompilation_StartupTier_CallCountThreshold = INT_MAX;
tieredCompilation_CallCountThreshold = INT_MAX;
}

tieredCompilation_StartupTier_CallCountingDelayMs =
CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TC_StartupTier_CallCountingDelayMs);
tieredCompilation_CallCountingDelayMs = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCountingDelayMs);

#ifndef FEATURE_PAL
bool hadSingleProcessorAtStartup = CPUGroupInfo::HadSingleProcessorAtStartup();
Expand All @@ -1235,14 +1236,13 @@ HRESULT EEConfig::sync()

if (hadSingleProcessorAtStartup)
{
DWORD delayMultiplier =
CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TC_StartupTier_DelaySingleProcMultiplier);
DWORD delayMultiplier = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_DelaySingleProcMultiplier);
if (delayMultiplier > 1)
{
DWORD newDelay = tieredCompilation_StartupTier_CallCountingDelayMs * delayMultiplier;
if (newDelay / delayMultiplier == tieredCompilation_StartupTier_CallCountingDelayMs)
DWORD newDelay = tieredCompilation_CallCountingDelayMs * delayMultiplier;
if (newDelay / delayMultiplier == tieredCompilation_CallCountingDelayMs)
{
tieredCompilation_StartupTier_CallCountingDelayMs = newDelay;
tieredCompilation_CallCountingDelayMs = newDelay;
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/vm/eeconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,10 @@ class EEConfig
#if defined(FEATURE_TIERED_COMPILATION)
bool TieredCompilation(void) const { LIMITED_METHOD_CONTRACT; return fTieredCompilation; }
bool TieredCompilation_QuickJit() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_QuickJit; }
bool TieredCompilation_StartupTier_CallCounting() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_StartupTier_CallCounting; }
bool TieredCompilation_StartupTier_OptimizeCode() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_StartupTier_OptimizeCode; }
DWORD TieredCompilation_StartupTier_CallCountThreshold() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_StartupTier_CallCountThreshold; }
DWORD TieredCompilation_StartupTier_CallCountingDelayMs() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_StartupTier_CallCountingDelayMs; }
bool TieredCompilation_QuickJitForLoops() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_QuickJitForLoops; }
bool TieredCompilation_CallCounting() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_CallCounting; }
DWORD TieredCompilation_CallCountThreshold() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_CallCountThreshold; }
DWORD TieredCompilation_CallCountingDelayMs() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_CallCountingDelayMs; }
#endif

#ifndef CROSSGEN_COMPILE
Expand Down Expand Up @@ -1014,10 +1014,10 @@ class EEConfig
#if defined(FEATURE_TIERED_COMPILATION)
bool fTieredCompilation;
bool fTieredCompilation_QuickJit;
bool fTieredCompilation_StartupTier_CallCounting;
bool fTieredCompilation_StartupTier_OptimizeCode;
DWORD tieredCompilation_StartupTier_CallCountThreshold;
DWORD tieredCompilation_StartupTier_CallCountingDelayMs;
bool fTieredCompilation_QuickJitForLoops;
bool fTieredCompilation_CallCounting;
DWORD tieredCompilation_CallCountThreshold;
DWORD tieredCompilation_CallCountingDelayMs;
#endif

#ifndef CROSSGEN_COMPILE
Expand Down
Loading