diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-10-01 00:47:24 +0300 |
---|---|---|
committer | Scott Mosier <smosier@microsoft.com> | 2015-10-01 00:47:24 +0300 |
commit | ad0323ab91a7b1469b42ca5457ddd631b94294fe (patch) | |
tree | 88fae57e1ec3aae90288463dc07e58f7aebc1de8 /src/Native/Runtime/GcStressControl.cpp | |
parent | 6763d16387778f126ec510c0421783952602f8f7 (diff) |
Initial population of CoreRT Runtime files.
Diffstat (limited to 'src/Native/Runtime/GcStressControl.cpp')
-rw-r--r-- | src/Native/Runtime/GcStressControl.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/Native/Runtime/GcStressControl.cpp b/src/Native/Runtime/GcStressControl.cpp new file mode 100644 index 000000000..73c710cb0 --- /dev/null +++ b/src/Native/Runtime/GcStressControl.cpp @@ -0,0 +1,184 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +#include "common.h" + +#if defined(FEATURE_GC_STRESS) & !defined(DACCESS_COMPILE) + + +#include "commontypes.h" +#include "daccess.h" +#include "commonmacros.h" +#include "palredhawkcommon.h" +#include "palredhawk.h" +#include "assert.h" +#include "static_check.h" +#include "holder.h" +#include "crst.h" +#include "rhconfig.h" +#include "gcrhinterface.h" +#include "slist.h" +#include "varint.h" +#include "regdisplay.h" +#include "forward_declarations.h" +#include "stackframeiterator.h" +#include "thread.h" +#include "event.h" +#include "rwlock.h" +#include "threadstore.h" +#include "shash.h" +#include "shash.inl" +#include "gcstresscontrol.h" + + +class GcStressControl +{ +public: + static bool ShouldHijack(UIntNative CallsiteIP, HijackType ht) + { + if (s_initState != isInited) + Initialize(); + + // don't hijack for GC stress if we're in a "no GC stress" region + Thread * pCurrentThread = ThreadStore::GetCurrentThread(); + if (pCurrentThread->IsSuppressGcStressSet()) + return false; + + if (g_pRhConfig->GetGcStressThrottleMode() == 0) + { + return true; + } + if (g_pRhConfig->GetGcStressThrottleMode() & gcstm_TriggerRandom) + { + if (GcStressTriggerRandom(CallsiteIP, ht, pCurrentThread)) + return true; + } + if (g_pRhConfig->GetGcStressThrottleMode() & gcstm_TriggerOnFirstHit) + { + if (GcStressTriggerFirstHit(CallsiteIP, ht)) + return true; + } + return false; + } + +private: + enum InitState { isNotInited, isIniting, isInited }; + + static void Initialize() + { + volatile InitState is = (InitState) PalInterlockedCompareExchange((volatile Int32*)(&s_initState), isIniting, isNotInited); + if (is == isNotInited) + { + s_lock.InitNoThrow(CrstGcStressControl); + + if (g_pRhConfig->GetGcStressSeed()) + s_lGcStressRNGSeed = g_pRhConfig->GetGcStressSeed(); + else + s_lGcStressRNGSeed = PalGetTickCount(); + + if (g_pRhConfig->GetGcStressFreqDenom()) + s_lGcStressFreqDenom = g_pRhConfig->GetGcStressFreqDenom(); + else + s_lGcStressFreqDenom = 10000; + + s_initState = isInited; + } + else + { + while (s_initState != isInited) + ; + } + } + + // returns true if no entry was found for CallsiteIP, false otherwise + static bool GcStressTrackAtIP(UIntNative CallsiteIP, HijackType ht, bool bForceGC) + { + // do this under a lock, as the underlying SHash might be "grown" by + // operations on other threads + + CrstHolder lh(&s_lock); + + const CallsiteCountEntry * pEntry = s_callsites.LookupPtr(CallsiteIP); + size_t hits; + + if (pEntry == NULL) + { + hits = 1; + CallsiteCountEntry e = {CallsiteIP, 1, 1, ht}; + s_callsites.AddOrReplace(e); + } + else + { + hits = ++(const_cast<CallsiteCountEntry*>(pEntry)->countHit); + if (bForceGC) + { + ++(const_cast<CallsiteCountEntry*>(pEntry)->countForced); + } + } + + return pEntry == NULL; + } + + static bool GcStressTriggerFirstHit(UIntNative CallsiteIP, HijackType ht) + { + return GcStressTrackAtIP(CallsiteIP, ht, false); + } + + static UInt32 GcStressRNG(UInt32 uMaxValue, Thread *pCurrentThread) + { + if (!pCurrentThread->IsRandInited()) + { + pCurrentThread->SetRandomSeed(s_lGcStressRNGSeed); + } + + return pCurrentThread->NextRand() % uMaxValue; + } + + static bool GcStressTriggerRandom(UIntNative CallsiteIP, HijackType ht, Thread *pCurrentThread) + { + bool bRes = false; + if (ht == htLoop) + { + bRes = GcStressRNG(s_lGcStressFreqDenom , pCurrentThread) < g_pRhConfig->GetGcStressFreqLoop(); + } + else if (ht == htCallsite) + { + bRes = GcStressRNG(s_lGcStressFreqDenom , pCurrentThread) < g_pRhConfig->GetGcStressFreqCallsite(); + } + if (bRes) + { + // if we're about to trigger a GC, track this in s_callsites + GcStressTrackAtIP(CallsiteIP, ht, true); + } + return bRes; + } + +private: + static CrstStatic s_lock; + static UInt32 s_lGcStressRNGSeed; + static UInt32 s_lGcStressFreqDenom; + static volatile InitState s_initState; + +public: + static CallsiteCountSHash s_callsites; // exposed to the DAC +}; + +// public interface: + +CallsiteCountSHash GcStressControl::s_callsites; +CrstStatic GcStressControl::s_lock; +UInt32 GcStressControl::s_lGcStressRNGSeed = 0; +UInt32 GcStressControl::s_lGcStressFreqDenom = 0; +volatile GcStressControl::InitState GcStressControl::s_initState = GcStressControl::isNotInited; + +GPTR_IMPL_INIT(CallsiteCountSHash, g_pCallsites, &GcStressControl::s_callsites); + +bool ShouldHijackForGcStress(UIntNative CallsiteIP, HijackType ht) +{ + return GcStressControl::ShouldHijack(CallsiteIP, ht); +} + +#endif // FEATURE_GC_STRESS & !DACCESS_COMPILE + + |