diff --git a/src/coreclr/src/gc/env/gcenv.ee.h b/src/coreclr/src/gc/env/gcenv.ee.h index 986acabacbeccb..d596575ad2b4a5 100644 --- a/src/coreclr/src/gc/env/gcenv.ee.h +++ b/src/coreclr/src/gc/env/gcenv.ee.h @@ -86,7 +86,7 @@ class GCToEEInterface static uint32_t GetTotalNumSizedRefHandles(); static bool AnalyzeSurvivorsRequested(int condemnedGeneration); - static void AnalyzeSurvivorsFinished(int condemnedGeneration); + static void AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()); static void VerifySyncTableEntry(); static void UpdateGCEventStatus(int publicLevel, int publicKeywords, int privateLevel, int privateKeywords); diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index f6910c0b246476..34c983521b614f 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -20909,9 +20909,19 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p) if (gc_t_join.joined()) #endif //MULTIPLE_HEAPS { + uint64_t promoted_bytes_global = 0; #ifdef HEAP_ANALYZE heap_analyze_enabled = FALSE; - GCToEEInterface::AnalyzeSurvivorsFinished(condemned_gen_number); +#ifdef MULTIPLE_HEAPS + for (int i = 0; i < n_heaps; i++) + { + promoted_bytes_global += promoted_bytes (i); + } +#else + promoted_bytes_global = promoted_bytes (0); +#endif //MULTIPLE_HEAPS + + GCToEEInterface::AnalyzeSurvivorsFinished (settings.gc_index, condemned_gen_number, promoted_bytes_global, GCHeap::ReportGenerationBounds); #endif // HEAP_ANALYZE GCToEEInterface::AfterGcScanRoots (condemned_gen_number, max_generation, &sc); diff --git a/src/coreclr/src/gc/gcee.cpp b/src/coreclr/src/gc/gcee.cpp index 2964b14190e9b6..4912f2e8669129 100644 --- a/src/coreclr/src/gc/gcee.cpp +++ b/src/coreclr/src/gc/gcee.cpp @@ -53,6 +53,11 @@ void GCHeap::UpdatePreGCCounters() #endif // BACKGROUND_GC FIRE_EVENT(GCStart_V2, count, depth, reason, static_cast(type)); + ReportGenerationBounds(); +} + +void GCHeap::ReportGenerationBounds() +{ g_theGCHeap->DiagDescrGenerations([](void*, int generation, uint8_t* rangeStart, uint8_t* rangeEnd, uint8_t* rangeEndReserved) { uint64_t range = static_cast(rangeEnd - rangeStart); @@ -148,12 +153,7 @@ void GCHeap::UpdatePostGCCounters() #endif //FEATURE_EVENT_TRACE #ifdef FEATURE_EVENT_TRACE - g_theGCHeap->DiagDescrGenerations([](void*, int generation, uint8_t* rangeStart, uint8_t* rangeEnd, uint8_t* rangeEndReserved) - { - uint64_t range = static_cast(rangeEnd - rangeStart); - uint64_t rangeReserved = static_cast(rangeEndReserved - rangeStart); - FIRE_EVENT(GCGenerationRange, generation, rangeStart, range, rangeReserved); - }, nullptr); + ReportGenerationBounds(); FIRE_EVENT(GCEnd_V1, static_cast(pSettings->gc_index), condemned_gen); diff --git a/src/coreclr/src/gc/gcenv.ee.standalone.inl b/src/coreclr/src/gc/gcenv.ee.standalone.inl index 650812644b0185..f14b327a31e16c 100644 --- a/src/coreclr/src/gc/gcenv.ee.standalone.inl +++ b/src/coreclr/src/gc/gcenv.ee.standalone.inl @@ -274,10 +274,10 @@ inline bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration) return g_theGCToCLR->AnalyzeSurvivorsRequested(condemnedGeneration); } -inline void GCToEEInterface::AnalyzeSurvivorsFinished(int condemnedGeneration) +inline void GCToEEInterface::AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()) { assert(g_theGCToCLR != nullptr); - g_theGCToCLR->AnalyzeSurvivorsFinished(condemnedGeneration); + g_theGCToCLR->AnalyzeSurvivorsFinished(gcIndex, condemnedGeneration, promoted_bytes, reportGenerationBounds); } inline void GCToEEInterface::VerifySyncTableEntry() diff --git a/src/coreclr/src/gc/gcimpl.h b/src/coreclr/src/gc/gcimpl.h index d1f062efb44cad..b1c8cb91a7b6de 100644 --- a/src/coreclr/src/gc/gcimpl.h +++ b/src/coreclr/src/gc/gcimpl.h @@ -31,7 +31,7 @@ inline void deleteGCShadow() {} inline void checkGCWriteBarrier() {} #endif -void GCProfileWalkHeap(); +void GCProfileWalkHeap(bool etwOnly); class gc_heap; class CFinalize; @@ -57,7 +57,7 @@ class GCHeap : public IGCHeapInternal friend void EnterAllocLock(); friend void LeaveAllocLock(); friend void ProfScanRootsHelper(Object** object, ScanContext *pSC, uint32_t dwFlags); - friend void GCProfileWalkHeap(); + friend void GCProfileWalkHeap(bool etwOnly); public: //In order to keep gc.cpp cleaner, ugly EE specific code is relegated to methods. @@ -315,6 +315,8 @@ class GCHeap : public IGCHeapInternal size_t GetLastGCGenerationSize(int gen); virtual void Shutdown(); + + static void ReportGenerationBounds(); }; #endif // GCIMPL_H_ diff --git a/src/coreclr/src/gc/gcinterface.ee.h b/src/coreclr/src/gc/gcinterface.ee.h index 158da1867dbb18..f61fdf5c5e6532 100644 --- a/src/coreclr/src/gc/gcinterface.ee.h +++ b/src/coreclr/src/gc/gcinterface.ee.h @@ -414,7 +414,7 @@ class IGCToCLR { bool AnalyzeSurvivorsRequested(int condemnedGeneration) = 0; virtual - void AnalyzeSurvivorsFinished(int condemnedGeneration) = 0; + void AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()) = 0; virtual void VerifySyncTableEntry() = 0; diff --git a/src/coreclr/src/gc/sample/gcenv.ee.cpp b/src/coreclr/src/gc/sample/gcenv.ee.cpp index 4ed20f07786e87..1480e62c23b497 100644 --- a/src/coreclr/src/gc/sample/gcenv.ee.cpp +++ b/src/coreclr/src/gc/sample/gcenv.ee.cpp @@ -339,7 +339,7 @@ inline bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration) return false; } -inline void GCToEEInterface::AnalyzeSurvivorsFinished(int condemnedGeneration) +inline void GCToEEInterface::AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()) { } diff --git a/src/coreclr/src/inc/clrconfigvalues.h b/src/coreclr/src/inc/clrconfigvalues.h index efeac155253c9c..bf49107ea062e1 100644 --- a/src/coreclr/src/inc/clrconfigvalues.h +++ b/src/coreclr/src/inc/clrconfigvalues.h @@ -709,6 +709,13 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeRundown, W("EventPipeRundown"), 1, "E RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeCircularMB, W("EventPipeCircularMB"), 1024, "The EventPipe circular buffer size in megabytes.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeProcNumbers, W("EventPipeProcNumbers"), 0, "Enable/disable capturing processor numbers in EventPipe event headers") +// +// Generational Aware Analysis +// +RETAIL_CONFIG_DWORD_INFO(INTERNAL_GCGenAnalysisGen, W("GCGenAnalysisGen"), 0, "The generation to trigger generational aware analysis") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_GCGenAnalysisBytes, W("GCGenAnalysisBytes"), 0, "The number of bytes to trigger generational aware analysis") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_GCGenAnalysisIndex, W("GCGenAnalysisIndex"), 0, "The gc index to trigger generational aware analysis") + // // Diagnostics Ports // diff --git a/src/coreclr/src/vm/CMakeLists.txt b/src/coreclr/src/vm/CMakeLists.txt index 6c97ca4ee013f3..0cb75e5629f3c4 100644 --- a/src/coreclr/src/vm/CMakeLists.txt +++ b/src/coreclr/src/vm/CMakeLists.txt @@ -357,6 +357,7 @@ set(VM_SOURCES_WKS gcenv.ee.common.cpp gcenv.os.cpp gchelpers.cpp + genanalysis.cpp genmeth.cpp hosting.cpp ibclogger.cpp diff --git a/src/coreclr/src/vm/ClrEtwAll.man b/src/coreclr/src/vm/ClrEtwAll.man index cf2108b4e56ac3..cb4eb215bd85ba 100644 --- a/src/coreclr/src/vm/ClrEtwAll.man +++ b/src/coreclr/src/vm/ClrEtwAll.man @@ -3795,6 +3795,13 @@ task="AssemblyLoader" symbol="KnownPathProbed" message="$(string.RuntimePublisher.KnownPathProbedEventMessage)"/> + + + @@ -7548,6 +7555,8 @@ + + diff --git a/src/coreclr/src/vm/ceemain.cpp b/src/coreclr/src/vm/ceemain.cpp index 75bb51cca4911d..b1cbb7ba947093 100644 --- a/src/coreclr/src/vm/ceemain.cpp +++ b/src/coreclr/src/vm/ceemain.cpp @@ -220,6 +220,8 @@ #include "gdbjit.h" #endif // FEATURE_GDBJIT +#include "genanalysis.h" + #ifndef CROSSGEN_COMPILE static int GetThreadUICultureId(__out LocaleIDValue* pLocale); // TODO: This shouldn't use the LCID. We should rely on name instead @@ -676,6 +678,7 @@ void EEStartupHelper() // Initialize the event pipe. EventPipe::Initialize(); #endif // FEATURE_PERFTRACING + GenAnalysis::Initialize(); #ifdef TARGET_UNIX PAL_SetShutdownCallback(EESocketCleanupHelper); diff --git a/src/coreclr/src/vm/eventpipe.cpp b/src/coreclr/src/vm/eventpipe.cpp index 51264b1f351c5e..a25f6c20370a51 100644 --- a/src/coreclr/src/vm/eventpipe.cpp +++ b/src/coreclr/src/vm/eventpipe.cpp @@ -22,6 +22,7 @@ #include "win32threadpool.h" #include "ceemain.h" #include "configuration.h" +#include "genanalysis.h" #ifdef TARGET_UNIX #include "pal.h" @@ -164,7 +165,7 @@ void EventPipe::EnableViaEnvironmentVariables() { outputPath = configOutputPath; } - auto configuration = XplatEventLoggerConfiguration(); + LPWSTR configToParse = eventpipeConfig; int providerCnt = 0; @@ -183,6 +184,7 @@ void EventPipe::EnableViaEnvironmentVariables() } else { + auto configuration = XplatEventLoggerConfiguration(); // Count how many providers there are to parse static WCHAR comma = W(','); while (*configToParse != '\0') diff --git a/src/coreclr/src/vm/eventpipesession.cpp b/src/coreclr/src/vm/eventpipesession.cpp index 49b9d54b1c1523..6e85703598c1f4 100644 --- a/src/coreclr/src/vm/eventpipesession.cpp +++ b/src/coreclr/src/vm/eventpipesession.cpp @@ -81,6 +81,7 @@ EventPipeSession::EventPipeSession( GetSystemTimeAsFileTime(&m_sessionStartTime); QueryPerformanceCounter(&m_sessionStartTimeStamp); + this->m_paused = false; } EventPipeSession::~EventPipeSession() @@ -315,6 +316,16 @@ bool EventPipeSession::WriteAllBuffersToFile(bool *pEventsWritten) return !m_pFile->HasErrors(); } +void EventPipeSession::Pause() +{ + this->m_paused = true; +} + +void EventPipeSession::Resume() +{ + this->m_paused = false; +} + bool EventPipeSession::WriteEvent( Thread *pThread, EventPipeEvent &event, @@ -332,6 +343,11 @@ bool EventPipeSession::WriteEvent( } CONTRACTL_END; + if (this->m_paused) + { + return true; + } + // Filter events specific to "this" session based on precomputed flag on provider/events. if (event.IsEnabled(GetMask())) { diff --git a/src/coreclr/src/vm/eventpipesession.h b/src/coreclr/src/vm/eventpipesession.h index 10974859c6b535..39d91f85360718 100644 --- a/src/coreclr/src/vm/eventpipesession.h +++ b/src/coreclr/src/vm/eventpipesession.h @@ -96,6 +96,20 @@ class EventPipeSession void DisableIpcStreamingThread(); + // Note - access to this field is NOT synchronized + // + // This field is currently modified in EventPipe::EnableViaEnvironmentVariables() during process startup + // and GCToEEInterface::AnalyzeSurvivorsFinished() while the GC has already synchronized all the threads. + // + // It is read in EventPipeSession::WriteEvent(). While it is possible for other preemptive threads to read + // the field while GC is happening, it should not happen because the only gcGenAwareSession only subscribe + // to GC events. + // + // This functionality is a workaround because we couldn't safely Enable()/Disable() the session where we wanted to due to lock-leveling. + // we expect to remove it in the future once that limitation is resolved + // other scenarios are discouraged from using this given that we plan to make it go away + bool m_paused; + public: EventPipeSession( uint32_t index, @@ -111,6 +125,24 @@ class EventPipeSession ~EventPipeSession(); + /** + * Please do not use this function, see EventPipeSession::m_paused for more information + */ + void Pause(); + + /** + * Please do not use this function, see EventPipeSession::m_paused for more information + */ + void Resume(); + + /** + * Please do not use this function, see EventPipeSession::m_paused for more information + */ + bool Paused() + { + return this->m_paused; + } + uint64_t GetMask() const { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/src/vm/eventtrace.cpp b/src/coreclr/src/vm/eventtrace.cpp index 67a1340723976e..802c5211ab71ab 100644 --- a/src/coreclr/src/vm/eventtrace.cpp +++ b/src/coreclr/src/vm/eventtrace.cpp @@ -1095,9 +1095,14 @@ void BulkComLogger::WriteRcw(RCW *pRcw, Object *obj) _ASSERTE(m_currRcw < kMaxRcwCount); #ifdef FEATURE_COMINTEROP + TypeHandle typeHandle = obj->GetGCSafeTypeHandleIfPossible(); + if (typeHandle == NULL) + { + return; + } EventRCWEntry &rcw = m_etwRcwData[m_currRcw]; rcw.ObjectID = (ULONGLONG)obj; - rcw.TypeID = (ULONGLONG)obj->GetTypeHandle().AsTAddr(); + rcw.TypeID = (ULONGLONG)typeHandle.AsTAddr(); rcw.IUnk = (ULONGLONG)pRcw->GetIUnknown_NoAddRef(); rcw.VTable = (ULONGLONG)pRcw->GetVTablePtr(); rcw.RefCount = pRcw->GetRefCount(); @@ -1179,10 +1184,16 @@ void BulkComLogger::WriteCcw(ComCallWrapper *pCcw, Object **handle, Object *obj) flags |= EventCCWEntry::Strong; } + TypeHandle typeHandle = obj->GetGCSafeTypeHandleIfPossible(); + if (typeHandle == NULL) + { + return; + } + EventCCWEntry &ccw = m_etwCcwData[m_currCcw++]; ccw.RootID = (ULONGLONG)handle; ccw.ObjectID = (ULONGLONG)obj; - ccw.TypeID = (ULONGLONG)obj->GetTypeHandle().AsTAddr(); + ccw.TypeID = (ULONGLONG)typeHandle.AsTAddr(); ccw.IUnk = (ULONGLONG)iUnk; ccw.RefCount = refCount; ccw.JupiterRefCount = 0; @@ -1463,7 +1474,12 @@ void BulkStaticsLogger::WriteEntry(AppDomain *domain, Object **address, Object * m_domain = domain; } - ULONGLONG th = (ULONGLONG)obj->GetTypeHandle().AsTAddr(); + TypeHandle typeHandle = obj->GetGCSafeTypeHandleIfPossible(); + if (typeHandle == NULL) + { + return; + } + ULONGLONG th = (ULONGLONG)typeHandle.AsTAddr(); ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(m_typeLogger, th, ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime); // We should have at least 512 characters remaining in the buffer here. diff --git a/src/coreclr/src/vm/fastserializer.cpp b/src/coreclr/src/vm/fastserializer.cpp index a15880079b6f70..238e5b772f2cc4 100644 --- a/src/coreclr/src/vm/fastserializer.cpp +++ b/src/coreclr/src/vm/fastserializer.cpp @@ -72,7 +72,6 @@ FileStreamWriter::FileStreamWriter(const SString &outputFilePath) m_pFileStream = new CFileStream(); if (FAILED(m_pFileStream->OpenForWrite(outputFilePath))) { - _ASSERTE(!"Unable to open file for write."); delete m_pFileStream; m_pFileStream = NULL; return; diff --git a/src/coreclr/src/vm/finalizerthread.cpp b/src/coreclr/src/vm/finalizerthread.cpp index a46166b3a85e35..facb5e4c1928e3 100644 --- a/src/coreclr/src/vm/finalizerthread.cpp +++ b/src/coreclr/src/vm/finalizerthread.cpp @@ -7,6 +7,9 @@ #include "finalizerthread.h" #include "threadsuspend.h" #include "jithost.h" +#include "eventpipe.h" +#include "eventpipesession.h" +#include "genanalysis.h" #ifdef FEATURE_COMINTEROP #include "runtimecallablewrapper.h" @@ -214,12 +217,8 @@ void FinalizerThread::WaitForFinalizerEvent (CLREvent *event) } } - - static BOOL s_FinalizerThreadOK = FALSE; - - VOID FinalizerThread::FinalizerThreadWorker(void *args) { SCAN_IGNORE_THROW; @@ -267,6 +266,18 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args) g_TriggerHeapDump = FALSE; } #endif + if (gcGenAnalysisState == GcGenAnalysisState::Done) + { + gcGenAnalysisState = GcGenAnalysisState::Disabled; + EventPipe::Disable(gcGenAnalysisEventPipeSessionId); + // Writing an empty file to indicate completion + fclose(fopen(GENAWARE_COMPLETION_FILE_NAME,"w+")); +#ifdef GEN_ANALYSIS_STRESS + { + GenAnalysis::EnableGenerationalAwareSession(); + } +#endif + } if (!bPriorityBoosted) { diff --git a/src/coreclr/src/vm/gcenv.ee.cpp b/src/coreclr/src/vm/gcenv.ee.cpp index 394475996015ca..54bde52c750b41 100644 --- a/src/coreclr/src/vm/gcenv.ee.cpp +++ b/src/coreclr/src/vm/gcenv.ee.cpp @@ -685,7 +685,7 @@ void GCProfileWalkHeapWorker(BOOL fProfilerPinned, BOOL fShouldWalkHeapRootsForE } #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) -void GCProfileWalkHeap() +void GCProfileWalkHeap(bool etwOnly) { BOOL fWalkedHeapForProfiler = FALSE; @@ -702,7 +702,7 @@ void GCProfileWalkHeap() #if defined (GC_PROFILING) { - BEGIN_PIN_PROFILER(CORProfilerTrackGC()); + BEGIN_PIN_PROFILER(!etwOnly && CORProfilerTrackGC()); GCProfileWalkHeapWorker(TRUE /* fProfilerPinned */, fShouldWalkHeapRootsForEtw, fShouldWalkHeapObjectsForEtw); fWalkedHeapForProfiler = TRUE; END_PIN_PROFILER(); @@ -764,7 +764,7 @@ void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurr // we will do these for all GCs. if (!fConcurrent) { - GCProfileWalkHeap(); + GCProfileWalkHeap(false); } if (CORProfilerTrackBasicGC() || (!fConcurrent && CORProfilerTrackGC())) @@ -1582,7 +1582,7 @@ bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration) return false; } -void GCToEEInterface::AnalyzeSurvivorsFinished(int condemnedGeneration) +void GCToEEInterface::AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()) { LIMITED_METHOD_CONTRACT; @@ -1596,6 +1596,25 @@ void GCToEEInterface::AnalyzeSurvivorsFinished(int condemnedGeneration) DACNotify::DoGCNotification(gea); } } + + if (gcGenAnalysisState == GcGenAnalysisState::Enabled) + { +#ifndef GEN_ANALYSIS_STRESS + if ((condemnedGeneration == gcGenAnalysisGen) && (promoted_bytes > (uint64_t)gcGenAnalysisBytes) && (gcIndex > (uint64_t)gcGenAnalysisIndex)) +#endif + { + gcGenAnalysisEventPipeSession->Resume(); + FireEtwGenAwareBegin(); + s_forcedGCInProgress = true; + GCProfileWalkHeap(true); + s_forcedGCInProgress = false; + reportGenerationBounds(); + FireEtwGenAwareEnd(); + gcGenAnalysisEventPipeSession->Pause(); + gcGenAnalysisState = GcGenAnalysisState::Done; + EnableFinalization(true); + } + } } void GCToEEInterface::VerifySyncTableEntry() diff --git a/src/coreclr/src/vm/gcenv.ee.h b/src/coreclr/src/vm/gcenv.ee.h index 908fb465dc98e4..c9a1cc27ab6c15 100644 --- a/src/coreclr/src/vm/gcenv.ee.h +++ b/src/coreclr/src/vm/gcenv.ee.h @@ -77,7 +77,7 @@ class GCToEEInterface : public IGCToCLR { uint32_t GetTotalNumSizedRefHandles(); bool AnalyzeSurvivorsRequested(int condemnedGeneration); - void AnalyzeSurvivorsFinished(int condemnedGeneration); + void AnalyzeSurvivorsFinished(size_t gcIndex, int condemnedGeneration, uint64_t promoted_bytes, void (*reportGenerationBounds)()); void VerifySyncTableEntry(); diff --git a/src/coreclr/src/vm/gcenv.ee.standalone.cpp b/src/coreclr/src/vm/gcenv.ee.standalone.cpp index 8aa1d4893fea96..93638697aeaae0 100644 --- a/src/coreclr/src/vm/gcenv.ee.standalone.cpp +++ b/src/coreclr/src/vm/gcenv.ee.standalone.cpp @@ -15,6 +15,9 @@ #include "gctoclreventsink.h" #include "configuration.h" +#include "eventpipe.h" +#include "eventpipesession.h" +#include "genanalysis.h" // the method table for the WeakReference class extern MethodTable* pWeakReferenceMT; diff --git a/src/coreclr/src/vm/gcenv.ee.static.cpp b/src/coreclr/src/vm/gcenv.ee.static.cpp index 5e1b452b256af6..63a0795f975e6e 100644 --- a/src/coreclr/src/vm/gcenv.ee.static.cpp +++ b/src/coreclr/src/vm/gcenv.ee.static.cpp @@ -15,6 +15,9 @@ #include "gctoclreventsink.h" #include "configuration.h" +#include "eventpipe.h" +#include "eventpipesession.h" +#include "genanalysis.h" // the method table for the WeakReference class extern MethodTable* pWeakReferenceMT; diff --git a/src/coreclr/src/vm/genanalysis.cpp b/src/coreclr/src/vm/genanalysis.cpp new file mode 100644 index 00000000000000..e679467c9ebb9c --- /dev/null +++ b/src/coreclr/src/vm/genanalysis.cpp @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "common.h" +#include "genanalysis.h" + +GcGenAnalysisState gcGenAnalysisState = GcGenAnalysisState::Uninitialized; +EventPipeSession* gcGenAnalysisEventPipeSession = nullptr; +uint64_t gcGenAnalysisEventPipeSessionId = (uint64_t)-1; +GcGenAnalysisState gcGenAnalysisConfigured = GcGenAnalysisState::Uninitialized; +int64_t gcGenAnalysisGen = -1; +int64_t gcGenAnalysisBytes = 0; +int64_t gcGenAnalysisIndex = 0; + +/* static */ void GenAnalysis::Initialize() +{ +#ifndef GEN_ANALYSIS_STRESS + if (gcGenAnalysisConfigured == GcGenAnalysisState::Uninitialized) + { + if (CLRConfig::IsConfigOptionSpecified(W("GCGenAnalysisGen"))) + { + gcGenAnalysisGen = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GCGenAnalysisGen); + if (CLRConfig::IsConfigOptionSpecified(W("GCGenAnalysisBytes"))) + { + gcGenAnalysisBytes = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GCGenAnalysisBytes); + if (CLRConfig::IsConfigOptionSpecified(W("GCGenAnalysisIndex"))) + { + gcGenAnalysisIndex = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GCGenAnalysisIndex); + gcGenAnalysisConfigured = GcGenAnalysisState::Enabled; + } + else + { + gcGenAnalysisConfigured = GcGenAnalysisState::Disabled; + } + } + else + { + gcGenAnalysisConfigured = GcGenAnalysisState::Disabled; + } + } + } + if ((gcGenAnalysisConfigured == GcGenAnalysisState::Enabled) && (gcGenAnalysisState == GcGenAnalysisState::Uninitialized)) +#endif + { + EnableGenerationalAwareSession(); + } +} + +/* static */ void GenAnalysis::EnableGenerationalAwareSession() +{ + LPCWSTR outputPath = nullptr; + outputPath = GENAWARE_FILE_NAME; + NewHolder pProviders = nullptr; + int providerCnt = 1; + pProviders = new EventPipeProviderConfiguration[providerCnt]; + const uint64_t GCHeapAndTypeNamesKeyword = 0x00001000000; // This keyword is necessary for the type names + const uint64_t GCHeapSurvivalAndMovementKeyword = 0x00000400000; // This keyword is necessary for the generation range data. + const uint64_t GCHeapDumpKeyword = 0x00000100000; // This keyword is necessary for enabling walking the heap + const uint64_t TypeKeyword = 0x00000080000; // This keyword is necessary for enabling BulkType events + const uint64_t keyword = GCHeapAndTypeNamesKeyword|GCHeapSurvivalAndMovementKeyword|GCHeapDumpKeyword|TypeKeyword; + pProviders[0] = EventPipeProviderConfiguration(W("Microsoft-Windows-DotNETRuntime"), keyword, 5, nullptr); + gcGenAnalysisEventPipeSessionId = EventPipe::Enable( + outputPath, + 1024, + pProviders, + providerCnt, + EventPipeSessionType::File, + EventPipeSerializationFormat::NetTraceV4, + false, + nullptr + ); + if (gcGenAnalysisEventPipeSessionId > 0) + { + gcGenAnalysisEventPipeSession= EventPipe::GetSession(gcGenAnalysisEventPipeSessionId); + gcGenAnalysisEventPipeSession->Pause(); + EventPipe::StartStreaming(gcGenAnalysisEventPipeSessionId); + gcGenAnalysisState = GcGenAnalysisState::Enabled; + } +} diff --git a/src/coreclr/src/vm/genanalysis.h b/src/coreclr/src/vm/genanalysis.h new file mode 100644 index 00000000000000..3ed25d8cf7b825 --- /dev/null +++ b/src/coreclr/src/vm/genanalysis.h @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// #define GEN_ANALYSIS_STRESS + +#ifndef __GENANALYSIS_H__ +#define __GENANALYSIS_H__ + +#include "eventpipe.h" +#include "eventpipesession.h" + +enum GcGenAnalysisState +{ + Uninitialized = 0, + Enabled = 1, + Disabled = 2, + Done = 3, +}; + +#define GENAWARE_FILE_NAME W("gcgenaware.nettrace") +#define GENAWARE_COMPLETION_FILE_NAME "gcgenaware.nettrace.completed" + +extern bool s_forcedGCInProgress; +extern GcGenAnalysisState gcGenAnalysisState; +extern EventPipeSession* gcGenAnalysisEventPipeSession; +extern uint64_t gcGenAnalysisEventPipeSessionId; +extern GcGenAnalysisState gcGenAnalysisConfigured; +extern int64_t gcGenAnalysisGen; +extern int64_t gcGenAnalysisBytes; +extern int64_t gcGenAnalysisIndex; + +class GenAnalysis +{ +public: + static void Initialize(); + static void EnableGenerationalAwareSession(); +}; + +#endif diff --git a/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp index a5e4206a5a1aac..487e12313708da 100644 --- a/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp @@ -1091,7 +1091,7 @@ bool HeapWalkHelper(Object * pBO, void * pvContext) OBJECTREF * arrObjRef = NULL; size_t cNumRefs = 0; bool bOnStack = false; - MethodTable * pMT = pBO->GetMethodTable(); + MethodTable * pMT = pBO->GetGCSafeMethodTable(); ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;