Add config option to disable tier 0 JIT (dotnet/coreclr#22370)
authorKoundinya Veluri <kouvel@users.noreply.github.com>
Fri, 8 Feb 2019 01:51:29 +0000 (17:51 -0800)
committerGitHub <noreply@github.com>
Fri, 8 Feb 2019 01:51:29 +0000 (17:51 -0800)
Add config option to disable tier 0 JIT

Fixes https://github.com/dotnet/coreclr/issues/21856
- For methods that don't have pregenerated code, using tier 0 JIT can improve startup perf, and disabling tier 0 JIT can be useful to sacrifice some startup time to avoid issues of running tier 0 code for too long. In some cases, it may also be desirable to avoid tiering up much later.
- A fixed value for the call count indicates that tier 0 call counting is disabled. When disabled, the method starts at tier 1.
- Also modified call counting to start from a predetermined threshold and count down to zero, as it simplifies some things, allows for methods to have different thresholds, and likely is what we would want eventually anyway
- Took a small step towards eliminating knowledge of specific tier levels in code that should not care, though more is to be done there

Commit migrated from https://github.com/dotnet/coreclr/commit/19ed7168345d34336cbc5a334b3fca36046a1af1

src/coreclr/src/inc/clrconfigvalues.h
src/coreclr/src/vm/callcounter.cpp
src/coreclr/src/vm/callcounter.h
src/coreclr/src/vm/codeversion.cpp
src/coreclr/src/vm/codeversion.h
src/coreclr/src/vm/eeconfig.cpp
src/coreclr/src/vm/eeconfig.h
src/coreclr/src/vm/prestub.cpp
src/coreclr/src/vm/tieredcompilation.cpp
src/coreclr/src/vm/tieredcompilation.h

index 34d04da..ecf43f0 100644 (file)
@@ -654,6 +654,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TieredCompilation, W("TieredCompilation"), 1,
 RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_Tier1CallCountThreshold, W("TieredCompilation_Tier1CallCountThreshold"), 30, "Number of times a method must be called after which it is promoted to tier 1.")
 RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_Tier1CallCountingDelayMs, W("TieredCompilation_Tier1CallCountingDelayMs"), 100, "A perpetual delay in milliseconds that is applied to tier 1 call counting and jitting, while there is tier 0 activity.")
 RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_Tier1DelaySingleProcMultiplier, W("TieredCompilation_Tier1DelaySingleProcMultiplier"), 10, "Multiplier for TieredCompilation_Tier1CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_DisableTier0Jit, W("TieredCompilation_DisableTier0Jit"), 0, "For methods that don't have pregenerated code, disable jitting them at tier 0 and start with a higher tier instead. For methods that have pregenerated code, tiering occurs normally.")
 
 RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_Test_CallCounting, W("TieredCompilation_Test_CallCounting"), 1, "Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any tier1 promotion")
 RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TieredCompilation_Test_OptimizeTier0, W("TieredCompilation_Test_OptimizeTier0"), 0, "Use optimized codegen (normally used by tier1) in tier0")
index 641b611..1227f3a 100644 (file)
@@ -23,27 +23,69 @@ CallCounter::CallCounter()
     m_lock.Init(LOCK_TYPE_DEFAULT);
 }
 
+bool CallCounter::IsEligibleForTier0CallCounting(MethodDesc* pMethodDesc)
+{
+    WRAPPER_NO_CONTRACT;
+    _ASSERTE(pMethodDesc != NULL);
+    _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
+
+    return g_pConfig->TieredCompilation_CallCounting() && !pMethodDesc->RequestedAggressiveOptimization();
+}
+
+bool CallCounter::IsTier0CallCountingEnabled(MethodDesc* pMethodDesc)
+{
+    WRAPPER_NO_CONTRACT;
+    _ASSERTE(pMethodDesc != NULL);
+    _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
+    _ASSERTE(IsEligibleForTier0CallCounting(pMethodDesc));
+
+    SpinLockHolder holder(&m_lock);
+
+    const CallCounterEntry *entry = m_methodToCallCount.LookupPtr(pMethodDesc);
+    return entry == nullptr || entry->IsTier0CallCountingEnabled();
+}
+
+void CallCounter::DisableTier0CallCounting(MethodDesc* pMethodDesc)
+{
+    WRAPPER_NO_CONTRACT;
+    _ASSERTE(pMethodDesc != NULL);
+    _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
+    _ASSERTE(IsEligibleForTier0CallCounting(pMethodDesc));
+
+    SpinLockHolder holder(&m_lock);
+
+    CallCounterEntry *entry = const_cast<CallCounterEntry *>(m_methodToCallCount.LookupPtr(pMethodDesc));
+
+    // Disabling call counting will affect the tier of the MethodDesc's first native code version. Callers must ensure that this
+    // change is made deterministically and prior to or while jitting the first native code version such that the tier would not
+    // be changed after it is already jitted. At that point, the call count threshold would already be initialized and the entry
+    // would exist. To disable call counting at different points in time, it would be ok to do so if the method has not been
+    // called yet (if the entry does not yet exist in the hash table), if necessary that could be a different function like
+    // TryDisable...() that would fail to disable call counting if the method has already been called.
+    _ASSERTE(entry != nullptr);
+    entry->DisableTier0CallCounting();
+}
+
 // This is called by the prestub each time the method is invoked in a particular
 // AppDomain (the AppDomain for which AppDomain.GetCallCounter() == this). These
 // calls continue until we backpatch the prestub to avoid future calls. This allows
 // us to track the number of calls to each method and use it as a trigger for tiered
 // compilation.
-//
-// Returns TRUE if no future invocations are needed (we reached the count we cared about)
-// and FALSE otherwise. It is permissible to keep calling even when TRUE was previously
-// returned and multi-threaded race conditions will surely cause this to occur.
 void CallCounter::OnMethodCalled(
     MethodDesc* pMethodDesc,
     TieredCompilationManager *pTieredCompilationManager,
     BOOL* shouldStopCountingCallsRef,
-    BOOL* wasPromotedToTier1Ref)
+    BOOL* wasPromotedToNextTierRef)
 {
     STANDARD_VM_CONTRACT;
 
     _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
     _ASSERTE(pTieredCompilationManager != nullptr);
     _ASSERTE(shouldStopCountingCallsRef != nullptr);
-    _ASSERTE(wasPromotedToTier1Ref != nullptr);
+    _ASSERTE(wasPromotedToNextTierRef != nullptr);
+
+    // At the moment, call counting is only done for tier 0 code
+    _ASSERTE(IsEligibleForTier0CallCounting(pMethodDesc));
 
     // PERF: This as a simple to implement, but not so performant, call counter
     // Currently this is only called until we reach a fixed call count and then
@@ -58,9 +100,8 @@ void CallCounter::OnMethodCalled(
     // leaving the prestub unpatched, but may not be good overall as it increases
     // the size of the jitted code.
 
-
-    TieredCompilationManager* pCallCounterSink = NULL;
-    int callCount;
+    bool isFirstTier0Call = false;
+    int tier0CallCountLimit;
     {
         //Be careful if you convert to something fully lock/interlocked-free that
         //you correctly handle what happens when some N simultaneous calls don't
@@ -72,17 +113,30 @@ void CallCounter::OnMethodCalled(
         CallCounterEntry* pEntry = const_cast<CallCounterEntry*>(m_methodToCallCount.LookupPtr(pMethodDesc));
         if (pEntry == NULL)
         {
-            callCount = 1;
-            m_methodToCallCount.Add(CallCounterEntry(pMethodDesc, callCount));
+            isFirstTier0Call = true;
+            tier0CallCountLimit = (int)g_pConfig->TieredCompilation_Tier1CallCountThreshold() - 1;
+            _ASSERTE(tier0CallCountLimit >= 0);
+            m_methodToCallCount.Add(CallCounterEntry(pMethodDesc, tier0CallCountLimit));
+        }
+        else if (pEntry->IsTier0CallCountingEnabled())
+        {
+            pEntry->tier0CallCountLimit--;
+            tier0CallCountLimit = pEntry->tier0CallCountLimit;
         }
         else
         {
-            pEntry->callCount++;
-            callCount = pEntry->callCount;
+            *shouldStopCountingCallsRef = true;
+            *wasPromotedToNextTierRef = true;
+            return;
         }
     }
 
-    pTieredCompilationManager->OnMethodCalled(pMethodDesc, callCount, shouldStopCountingCallsRef, wasPromotedToTier1Ref);
+    pTieredCompilationManager->OnTier0MethodCalled(
+        pMethodDesc,
+        isFirstTier0Call,
+        tier0CallCountLimit,
+        shouldStopCountingCallsRef,
+        wasPromotedToNextTierRef);
 }
 
 #endif // FEATURE_TIERED_COMPILATION
index 4e9a5d3..5feeb56 100644 (file)
 struct CallCounterEntry
 {
     CallCounterEntry() {}
-    CallCounterEntry(const MethodDesc* m, const int c)
-        : pMethod(m), callCount(c) {}
+    CallCounterEntry(const MethodDesc* m, const int tier0CallCountLimit)
+        : pMethod(m), tier0CallCountLimit(tier0CallCountLimit) {}
 
     const MethodDesc* pMethod;
-    int callCount;
+    int tier0CallCountLimit;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+    bool IsTier0CallCountingEnabled() const
+    {
+        LIMITED_METHOD_CONTRACT;
+        return tier0CallCountLimit != INT_MAX;
+    }
+
+    void DisableTier0CallCounting()
+    {
+        LIMITED_METHOD_CONTRACT;
+        tier0CallCountLimit = INT_MAX;
+    }
+#endif
 };
 
 class CallCounterHashTraits : public DefaultSHashTraits<CallCounterEntry>
@@ -70,7 +84,26 @@ public:
     CallCounter();
 #endif
 
-    void OnMethodCalled(MethodDesc* pMethodDesc, TieredCompilationManager *pTieredCompilationManager, BOOL* shouldStopCountingCallsRef, BOOL* wasPromotedToTier1Ref);
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+    static bool IsEligibleForCallCounting(MethodDesc* pMethodDesc)
+    {
+        WRAPPER_NO_CONTRACT;
+        return IsEligibleForTier0CallCounting(pMethodDesc);
+    }
+
+    static bool IsEligibleForTier0CallCounting(MethodDesc* pMethodDesc);
+
+    bool IsCallCountingEnabled(MethodDesc* pMethodDesc)
+    {
+        WRAPPER_NO_CONTRACT;
+        return IsTier0CallCountingEnabled(pMethodDesc);
+    }
+
+    bool IsTier0CallCountingEnabled(MethodDesc* pMethodDesc);
+    void DisableTier0CallCounting(MethodDesc* pMethodDesc);
+#endif
+
+    void OnMethodCalled(MethodDesc* pMethodDesc, TieredCompilationManager *pTieredCompilationManager, BOOL* shouldStopCountingCallsRef, BOOL* wasPromotedToNextTierRef);
 
 private:
 
index 70072e1..e8ace28 100644 (file)
@@ -147,11 +147,23 @@ void NativeCodeVersionNode::SetActiveChildFlag(BOOL isActive)
 
 
 #ifdef FEATURE_TIERED_COMPILATION
+
 NativeCodeVersion::OptimizationTier NativeCodeVersionNode::GetOptimizationTier() const
 {
     LIMITED_METHOD_DAC_CONTRACT;
     return m_optTier;
 }
+
+#ifndef DACCESS_COMPILE
+void NativeCodeVersionNode::SetOptimizationTier(NativeCodeVersion::OptimizationTier tier)
+{
+    LIMITED_METHOD_CONTRACT;
+    _ASSERTE(tier >= m_optTier);
+
+    m_optTier = tier;
+}
+#endif
+
 #endif // FEATURE_TIERED_COMPILATION
 
 NativeCodeVersion::NativeCodeVersion() :
@@ -327,6 +339,7 @@ MethodDescVersioningState* NativeCodeVersion::GetMethodDescVersioningState()
 #endif
 
 #ifdef FEATURE_TIERED_COMPILATION
+
 NativeCodeVersion::OptimizationTier NativeCodeVersion::GetOptimizationTier() const
 {
     LIMITED_METHOD_DAC_CONTRACT;
@@ -339,6 +352,23 @@ NativeCodeVersion::OptimizationTier NativeCodeVersion::GetOptimizationTier() con
         return TieredCompilationManager::GetInitialOptimizationTier(GetMethodDesc());
     }
 }
+
+#ifndef DACCESS_COMPILE
+void NativeCodeVersion::SetOptimizationTier(OptimizationTier tier)
+{
+    WRAPPER_NO_CONTRACT;
+    if (m_storageKind == StorageKind::Explicit)
+    {
+        AsNode()->SetOptimizationTier(tier);
+    }
+    else
+    {
+        // State changes should have been made previously such that the initial tier is the new tier
+        _ASSERTE(TieredCompilationManager::GetInitialOptimizationTier(GetMethodDesc()) == tier);
+    }
+}
+#endif
+
 #endif
 
 PTR_NativeCodeVersionNode NativeCodeVersion::AsNode() const
index 6554fc5..821c938 100644 (file)
@@ -71,6 +71,9 @@ public:
     };
 #ifdef FEATURE_TIERED_COMPILATION
     OptimizationTier GetOptimizationTier() const;
+#ifndef DACCESS_COMPILE
+    void SetOptimizationTier(OptimizationTier tier);
+#endif
 #endif // FEATURE_TIERED_COMPILATION
     bool operator==(const NativeCodeVersion & rhs) const;
     bool operator!=(const NativeCodeVersion & rhs) const;
@@ -237,7 +240,10 @@ public:
 #endif
 #ifdef FEATURE_TIERED_COMPILATION
     NativeCodeVersion::OptimizationTier GetOptimizationTier() const;
+#ifndef DACCESS_COMPILE
+    void SetOptimizationTier(NativeCodeVersion::OptimizationTier tier);
 #endif
+#endif // FEATURE_TIERED_COMPILATION
 
 private:
     //union - could save a little memory?
index d964243..a3a636d 100644 (file)
@@ -355,6 +355,7 @@ HRESULT EEConfig::Init()
 
 #if defined(FEATURE_TIERED_COMPILATION)
     fTieredCompilation = false;
+    fTieredCompilation_DisableTier0Jit = false;
     fTieredCompilation_CallCounting = false;
     fTieredCompilation_OptimizeTier0 = false;
     tieredCompilation_tier1CallCountThreshold = 1;
@@ -1221,6 +1222,10 @@ HRESULT EEConfig::sync()
 
 #if defined(FEATURE_TIERED_COMPILATION)
     fTieredCompilation = Configuration::GetKnobBooleanValue(W("System.Runtime.TieredCompilation"), CLRConfig::EXTERNAL_TieredCompilation) != 0;
+    fTieredCompilation_DisableTier0Jit =
+        Configuration::GetKnobBooleanValue(
+            W("System.Runtime.TieredCompilation.DisableTier0Jit"),
+            CLRConfig::UNSUPPORTED_TieredCompilation_DisableTier0Jit) != 0;
 
     fTieredCompilation_CallCounting = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Test_CallCounting) != 0;
     fTieredCompilation_OptimizeTier0 = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Test_OptimizeTier0) != 0;
@@ -1231,6 +1236,10 @@ HRESULT EEConfig::sync()
     {
         tieredCompilation_tier1CallCountThreshold = 1;
     }
+    else if (tieredCompilation_tier1CallCountThreshold > INT_MAX) // CallCounter uses 'int'
+    {
+        tieredCompilation_tier1CallCountThreshold = INT_MAX;
+    }
 
     tieredCompilation_tier1CallCountingDelayMs =
         CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Tier1CallCountingDelayMs);
index cf46336..20dde06 100644 (file)
@@ -282,6 +282,7 @@ public:
     // Tiered Compilation config
 #if defined(FEATURE_TIERED_COMPILATION)
     bool          TieredCompilation(void)           const {LIMITED_METHOD_CONTRACT;  return fTieredCompilation; }
+    bool          TieredCompilation_DisableTier0Jit() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_DisableTier0Jit; }
     bool          TieredCompilation_CallCounting()  const {LIMITED_METHOD_CONTRACT;  return fTieredCompilation_CallCounting; }
     bool          TieredCompilation_OptimizeTier0() const {LIMITED_METHOD_CONTRACT; return fTieredCompilation_OptimizeTier0; }
     DWORD         TieredCompilation_Tier1CallCountThreshold() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_tier1CallCountThreshold; }
@@ -1023,6 +1024,7 @@ private: //----------------------------------------------------------------
 
 #if defined(FEATURE_TIERED_COMPILATION)
     bool fTieredCompilation;
+    bool fTieredCompilation_DisableTier0Jit;
     bool fTieredCompilation_CallCounting;
     bool fTieredCompilation_OptimizeTier0;
     DWORD tieredCompilation_tier1CallCountThreshold;
index ba84927..0f3d96d 100644 (file)
@@ -372,6 +372,17 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig)
 
     if (pCode == NULL)
     {
+#ifdef FEATURE_TIERED_COMPILATION
+        if (g_pConfig->TieredCompilation_DisableTier0Jit() &&
+            IsEligibleForTieredCompilation() &&
+            pConfig->GetCodeVersion().GetOptimizationTier() == NativeCodeVersion::OptimizationTier0 &&
+            CallCounter::IsEligibleForTier0CallCounting(this))
+        {
+            GetCallCounter()->DisableTier0CallCounting(this);
+            pConfig->GetCodeVersion().SetOptimizationTier(NativeCodeVersion::OptimizationTier1);
+        }
+#endif
+
         LOG((LF_CLASSLOADER, LL_INFO1000000,
             "    In PrepareILBasedCode, calling JitCompileCode\n"));
         pCode = JitCompileCode(pConfig);
@@ -1810,13 +1821,12 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT)
 #ifdef FEATURE_TIERED_COMPILATION
     BOOL fNeedsCallCounting = FALSE;
     TieredCompilationManager* pTieredCompilationManager = nullptr;
-    if (IsEligibleForTieredCompilation() && TieredCompilationManager::RequiresCallCounting(this))
+    if (IsEligibleForTieredCompilation() && CallCounter::IsEligibleForCallCounting(this))
     {
         pTieredCompilationManager = GetAppDomain()->GetTieredCompilationManager();
-        CallCounter * pCallCounter = GetCallCounter();
-        BOOL fWasPromotedToTier1 = FALSE;
-        pCallCounter->OnMethodCalled(this, pTieredCompilationManager, &fCanBackpatchPrestub, &fWasPromotedToTier1);
-        fNeedsCallCounting = !fWasPromotedToTier1;
+        BOOL fWasPromotedToNextTier = FALSE;
+        GetCallCounter()->OnMethodCalled(this, pTieredCompilationManager, &fCanBackpatchPrestub, &fWasPromotedToNextTier);
+        fNeedsCallCounting = !fWasPromotedToNextTier;
     }
 #endif
 
@@ -1834,7 +1844,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT)
 #ifdef FEATURE_TIERED_COMPILATION
         if (pTieredCompilationManager != nullptr && fNeedsCallCounting && fCanBackpatchPrestub && pCode != NULL)
         {
-            pTieredCompilationManager->OnMethodCallCountingStoppedWithoutTier1Promotion(this);
+            pTieredCompilationManager->OnMethodCallCountingStoppedWithoutTierPromotion(this);
         }
 #endif
 
index f5745a1..dd40d8c 100644 (file)
@@ -65,7 +65,6 @@ TieredCompilationManager::TieredCompilationManager() :
     m_lock(CrstTieredCompilation),
     m_isAppDomainShuttingDown(FALSE),
     m_countOptimizationThreadsRunning(0),
-    m_callCountOptimizationThreshhold(1),
     m_optimizationQuantumMs(50),
     m_methodsPendingCountingForTier1(nullptr),
     m_tieringDelayTimerHandle(nullptr),
@@ -88,7 +87,6 @@ void TieredCompilationManager::Init(ADID appDomainId)
 
     CrstHolder holder(&m_lock);
     m_domainId = appDomainId;
-    m_callCountOptimizationThreshhold = g_pConfig->TieredCompilation_Tier1CallCountThreshold();
 }
 
 #endif // FEATURE_TIERED_COMPILATION && !DACCESS_COMPILE
@@ -98,71 +96,81 @@ NativeCodeVersion::OptimizationTier TieredCompilationManager::GetInitialOptimiza
     WRAPPER_NO_CONTRACT;
     _ASSERTE(pMethodDesc != NULL);
 
-#ifdef FEATURE_TIERED_COMPILATION
+#if defined(FEATURE_TIERED_COMPILATION) && !defined(DACCESS_COMPILE)
+    if (!pMethodDesc->IsEligibleForTieredCompilation())
+    {
+        // The optimization tier is not used
+        return NativeCodeVersion::OptimizationTier0;
+    }
+
     if (pMethodDesc->RequestedAggressiveOptimization())
     {
         // Methods flagged with MethodImplOptions.AggressiveOptimization begin at tier 1, as a workaround to cold methods with
         // hot loops performing poorly (https://github.com/dotnet/coreclr/issues/19751)
         return NativeCodeVersion::OptimizationTier1;
     }
-#endif // FEATURE_TIERED_COMPILATION
+
+    if (!g_pConfig->TieredCompilation_CallCounting())
+    {
+        // Call counting is disabled altogether through config, the intention is to remain at the initial tier
+        return NativeCodeVersion::OptimizationTier0;
+    }
+
+    if (!pMethodDesc->GetCallCounter()->IsTier0CallCountingEnabled(pMethodDesc))
+    {
+        // Tier 0 call counting may have been disabled based on information about precompiled code or for other reasons, the
+        // intention is to begin at tier 1
+        return NativeCodeVersion::OptimizationTier1;
+    }
+#endif
 
     return NativeCodeVersion::OptimizationTier0;
 }
 
 #if defined(FEATURE_TIERED_COMPILATION) && !defined(DACCESS_COMPILE)
 
-bool TieredCompilationManager::RequiresCallCounting(MethodDesc* pMethodDesc)
-{
-    WRAPPER_NO_CONTRACT;
-    _ASSERTE(pMethodDesc != NULL);
-    _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
-
-    return
-        g_pConfig->TieredCompilation_CallCounting() &&
-        GetInitialOptimizationTier(pMethodDesc) == NativeCodeVersion::OptimizationTier0;
-}
-
 // Called each time code in this AppDomain has been run. This is our sole entrypoint to begin
 // tiered compilation for now. Returns TRUE if no more notifications are necessary, but
 // more notifications may come anyways.
 //
-// currentCallCount is pre-incremented, that is to say the value is 1 on first call for a given
-//      method.
-void TieredCompilationManager::OnMethodCalled(
+// currentCallCountLimit is pre-decremented, that is to say the value is <= 0 when the
+//      threshold for promoting to tier 1 is reached.
+void TieredCompilationManager::OnTier0MethodCalled(
     MethodDesc* pMethodDesc,
-    DWORD currentCallCount,
+    bool isFirstCall,
+    int currentCallCountLimit,
     BOOL* shouldStopCountingCallsRef,
-    BOOL* wasPromotedToTier1Ref)
+    BOOL* wasPromotedToNextTierRef)
 {
     WRAPPER_NO_CONTRACT;
     _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
     _ASSERTE(shouldStopCountingCallsRef != nullptr);
-    _ASSERTE(wasPromotedToTier1Ref != nullptr);
+    _ASSERTE(wasPromotedToNextTierRef != nullptr);
 
     *shouldStopCountingCallsRef =
         // Stop call counting when the delay is in effect
         IsTieringDelayActive() ||
         // Initiate the delay on tier 0 activity (when a new eligible method is called the first time)
-        (currentCallCount == 1 && g_pConfig->TieredCompilation_Tier1CallCountingDelayMs() != 0) ||
+        (isFirstCall && g_pConfig->TieredCompilation_Tier1CallCountingDelayMs() != 0) ||
         // Stop call counting when ready for tier 1 promotion
-        currentCallCount >= m_callCountOptimizationThreshhold;
+        currentCallCountLimit <= 0;
 
-    *wasPromotedToTier1Ref = currentCallCount >= m_callCountOptimizationThreshhold;
+    *wasPromotedToNextTierRef = currentCallCountLimit <= 0;
 
-    if (currentCallCount == m_callCountOptimizationThreshhold)
+    if (currentCallCountLimit == 0)
     {
         AsyncPromoteMethodToTier1(pMethodDesc);
     }
 }
 
-void TieredCompilationManager::OnMethodCallCountingStoppedWithoutTier1Promotion(MethodDesc* pMethodDesc)
+void TieredCompilationManager::OnMethodCallCountingStoppedWithoutTierPromotion(MethodDesc* pMethodDesc)
 {
     WRAPPER_NO_CONTRACT;
     _ASSERTE(pMethodDesc != nullptr);
     _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
 
-    if (g_pConfig->TieredCompilation_Tier1CallCountingDelayMs() == 0)
+    if (g_pConfig->TieredCompilation_Tier1CallCountingDelayMs() == 0 ||
+        !pMethodDesc->GetCallCounter()->IsCallCountingEnabled(pMethodDesc))
     {
         return;
     }
index 072f8e1..2c021b8 100644 (file)
@@ -34,9 +34,8 @@ public:
 #ifdef FEATURE_TIERED_COMPILATION
 
 public:
-    static bool RequiresCallCounting(MethodDesc* pMethodDesc);
-    void OnMethodCalled(MethodDesc* pMethodDesc, DWORD currentCallCount, BOOL* shouldStopCountingCallsRef, BOOL* wasPromotedToTier1Ref);
-    void OnMethodCallCountingStoppedWithoutTier1Promotion(MethodDesc* pMethodDesc);
+    void OnTier0MethodCalled(MethodDesc* pMethodDesc, bool isFirstCall, int currentCallCountLimit, BOOL* shouldStopCountingCallsRef, BOOL* wasPromotedToNextTierRef);
+    void OnMethodCallCountingStoppedWithoutTierPromotion(MethodDesc* pMethodDesc);
     void AsyncPromoteMethodToTier1(MethodDesc* pMethodDesc);
     void Shutdown();
     static CORJIT_FLAGS GetJitFlags(NativeCodeVersion nativeCodeVersion);
@@ -69,7 +68,6 @@ private:
     ADID m_domainId;
     BOOL m_isAppDomainShuttingDown;
     DWORD m_countOptimizationThreadsRunning;
-    DWORD m_callCountOptimizationThreshhold;
     DWORD m_optimizationQuantumMs;
     SArray<MethodDesc*>* m_methodsPendingCountingForTier1;
     HANDLE m_tieringDelayTimerHandle;