Skip to content

Commit

Permalink
Generational aware analysis based on environment variable. (#40332)
Browse files Browse the repository at this point in the history
  • Loading branch information
cshung authored Aug 15, 2020
1 parent 71c83f3 commit f35d747
Show file tree
Hide file tree
Showing 24 changed files with 280 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/coreclr/src/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 11 additions & 1 deletion src/coreclr/src/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/src/gc/gcee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ void GCHeap::UpdatePreGCCounters()
#endif // BACKGROUND_GC

FIRE_EVENT(GCStart_V2, count, depth, reason, static_cast<uint32_t>(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<uint64_t>(rangeEnd - rangeStart);
Expand Down Expand Up @@ -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<uint64_t>(rangeEnd - rangeStart);
uint64_t rangeReserved = static_cast<uint64_t>(rangeEndReserved - rangeStart);
FIRE_EVENT(GCGenerationRange, generation, rangeStart, range, rangeReserved);
}, nullptr);
ReportGenerationBounds();

FIRE_EVENT(GCEnd_V1, static_cast<uint32_t>(pSettings->gc_index), condemned_gen);

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/src/gc/gcenv.ee.standalone.inl
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/src/gc/gcimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ inline void deleteGCShadow() {}
inline void checkGCWriteBarrier() {}
#endif

void GCProfileWalkHeap();
void GCProfileWalkHeap(bool etwOnly);

class gc_heap;
class CFinalize;
Expand All @@ -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.
Expand Down Expand Up @@ -315,6 +315,8 @@ class GCHeap : public IGCHeapInternal
size_t GetLastGCGenerationSize(int gen);

virtual void Shutdown();

static void ReportGenerationBounds();
};

#endif // GCIMPL_H_
2 changes: 1 addition & 1 deletion src/coreclr/src/gc/gcinterface.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/gc/sample/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)())
{

}
7 changes: 7 additions & 0 deletions src/coreclr/src/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/src/vm/ClrEtwAll.man
Original file line number Diff line number Diff line change
Expand Up @@ -3795,6 +3795,13 @@
task="AssemblyLoader"
symbol="KnownPathProbed" message="$(string.RuntimePublisher.KnownPathProbedEventMessage)"/>

<event value="297" version="0" level="win:Informational"
keywords ="GCHeapDumpKeyword"
symbol="GenAwareBegin" message="$(string.RuntimePublisher.GenAwareBeginEventMessage)"/>

<event value="298" version="0" level="win:Informational"
keywords ="GCHeapDumpKeyword"
symbol="GenAwareEnd" message="$(string.RuntimePublisher.GenAwareEndEventMessage)"/>
</events>
</provider>

Expand Down Expand Up @@ -7548,6 +7555,8 @@
<string id="RuntimePublisher.CompilationDiagnosticKeywordMessage" value="CompilationDiagnostic" />
<string id="RuntimePublisher.MethodDiagnosticKeywordMessage" value="MethodDiagnostic" />
<string id="RuntimePublisher.TypeDiagnosticKeywordMessage" value="TypeDiagnostic" />
<string id="RuntimePublisher.GenAwareBeginEventMessage" value="NONE" />
<string id="RuntimePublisher.GenAwareEndEventMessage" value="NONE" />
<string id="RundownPublisher.LoaderKeywordMessage" value="Loader" />
<string id="RundownPublisher.JitKeywordMessage" value="Jit" />
<string id="RundownPublisher.JittedMethodILToNativeMapRundownKeywordMessage" value="JittedMethodILToNativeMapRundown" />
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/vm/ceemain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -676,6 +678,7 @@ void EEStartupHelper()
// Initialize the event pipe.
EventPipe::Initialize();
#endif // FEATURE_PERFTRACING
GenAnalysis::Initialize();

#ifdef TARGET_UNIX
PAL_SetShutdownCallback(EESocketCleanupHelper);
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/src/vm/eventpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "win32threadpool.h"
#include "ceemain.h"
#include "configuration.h"
#include "genanalysis.h"

#ifdef TARGET_UNIX
#include "pal.h"
Expand Down Expand Up @@ -164,7 +165,7 @@ void EventPipe::EnableViaEnvironmentVariables()
{
outputPath = configOutputPath;
}
auto configuration = XplatEventLoggerConfiguration();

LPWSTR configToParse = eventpipeConfig;
int providerCnt = 0;

Expand All @@ -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')
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/src/vm/eventpipesession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ EventPipeSession::EventPipeSession(

GetSystemTimeAsFileTime(&m_sessionStartTime);
QueryPerformanceCounter(&m_sessionStartTimeStamp);
this->m_paused = false;
}

EventPipeSession::~EventPipeSession()
Expand Down Expand Up @@ -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,
Expand All @@ -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()))
{
Expand Down
32 changes: 32 additions & 0 deletions src/coreclr/src/vm/eventpipesession.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
22 changes: 19 additions & 3 deletions src/coreclr/src/vm/eventtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/src/vm/fastserializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 15 additions & 4 deletions src/coreclr/src/vm/finalizerthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -214,12 +217,8 @@ void FinalizerThread::WaitForFinalizerEvent (CLREvent *event)
}
}



static BOOL s_FinalizerThreadOK = FALSE;



VOID FinalizerThread::FinalizerThreadWorker(void *args)
{
SCAN_IGNORE_THROW;
Expand Down Expand Up @@ -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)
{
Expand Down
Loading

0 comments on commit f35d747

Please sign in to comment.