Skip to content

Commit

Permalink
Move gcheap walk helpers to opt-in
Browse files Browse the repository at this point in the history
  • Loading branch information
elinor-fung committed Jul 12, 2023
1 parent 1198c13 commit 02e28c9
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 184 deletions.
1 change: 0 additions & 1 deletion src/coreclr/nativeaot/Runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ set(COMMON_RUNTIME_SOURCES
TypeManager.cpp
ObjectLayout.cpp
portable.cpp
profheapwalkhelper.cpp
RestrictedCallouts.cpp
RhConfig.cpp
RuntimeInstance.cpp
Expand Down
22 changes: 1 addition & 21 deletions src/coreclr/nativeaot/Runtime/disabledeventtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,8 @@ void EventTracing_Initialize() { }
void ETW::GCLog::FireGcStart(ETW_GC_INFO * pGcInfo) { }

#ifdef FEATURE_ETW
BOOL ETW::GCLog::ShouldWalkHeapObjectsForEtw() { return FALSE; }
BOOL ETW::GCLog::ShouldWalkHeapRootsForEtw() { return FALSE; }
BOOL ETW::GCLog::ShouldTrackMovementForEtw() { return FALSE; }
BOOL ETW::GCLog::ShouldWalkStaticsAndCOMForEtw() { return FALSE; }
void ETW::GCLog::ForceGC(LONGLONG l64ClientSequenceNumber) { }
void ETW::GCLog::EndHeapDump(ProfilerWalkHeapContext * profilerWalkHeapContext) { }
void ETW::GCLog::BeginMovedReferences(size_t * pProfilingContext) { }
void ETW::GCLog::MovedReference(BYTE * pbMemBlockStart, BYTE * pbMemBlockEnd, ptrdiff_t cbRelocDistance, size_t profilingContext, BOOL fCompacting, BOOL fAllowProfApiNotification) { }
void ETW::GCLog::EndMovedReferences(size_t profilingContext, BOOL fAllowProfApiNotification) { }
void ETW::GCLog::WalkStaticsAndCOMForETW() { }
void ETW::GCLog::ObjectReference(
ProfilerWalkHeapContext* profilerWalkHeapContext,
Object* pObjReferenceSource,
ULONGLONG typeID,
ULONGLONG cRefs,
Object** rgObjReferenceTargets) { }
void ETW::GCLog::RootReference(
LPVOID pvHandle,
Object * pRootedNode,
Object * pSecondaryNodeForDependentHandle,
BOOL fDependentHandle,
ProfilingScanContext * profilingScanContext,
DWORD dwGCFlags,
DWORD rootFlags) { }
void ETW::GCLog::WalkHeap() { }
#endif // FEATURE_ETW
23 changes: 13 additions & 10 deletions src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,21 @@ list(APPEND AOT_EVENTPIPE_MANAGED_TO_NATIVE_SOURCES
${RUNTIME_DIR}/runtimeeventinternal.cpp
)

list(APPEND AOT_EVENTTRACE_SOURCES
${RUNTIME_DIR}/eventtrace.cpp
)

# These are carry-overs from .NET Native and only included for ETW currently
# bulktype : directly emits via ETW with EventWrite
# gcheap : GCHeapDump, GCHeapSurvivalAndMovement - not prioritizing for nativeaot yet
if (FEATURE_ETW)
if (FEATURE_EVENT_TRACE)
list(APPEND AOT_EVENTTRACE_SOURCES
${RUNTIME_DIR}/eventtrace_bulktype.cpp
${RUNTIME_DIR}/eventtrace_gcheap.cpp
${RUNTIME_DIR}/eventtrace.cpp
${RUNTIME_DIR}/profheapwalkhelper.cpp
)

# These are carry-overs from .NET Native and only included for ETW currently
# bulktype : directly emits via ETW with EventWrite
# gcheap : GCHeapDump, GCHeapSurvivalAndMovement - not prioritizing for nativeaot yet
if (FEATURE_ETW)
list(APPEND AOT_EVENTTRACE_SOURCES
${RUNTIME_DIR}/eventtrace_bulktype.cpp
${RUNTIME_DIR}/eventtrace_gcheap.cpp
)
endif()
endif()

list(APPEND EVENTPIPE_SOURCES
Expand Down
11 changes: 10 additions & 1 deletion src/coreclr/nativeaot/Runtime/eventtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ struct ProfilingScanContext : ScanContext
void * pvEtwContext;
void *pHeapId;

ProfilingScanContext(BOOL fProfilerPinnedParam);
ProfilingScanContext(BOOL fProfilerPinnedParam)
: ScanContext()
{
pHeapId = NULL;
fProfilerPinned = fProfilerPinnedParam;
pvEtwContext = NULL;
promotion = true;
}
};
#endif // defined(FEATURE_EVENT_TRACE)

Expand Down Expand Up @@ -187,6 +194,7 @@ namespace ETW
static void MovedReference(BYTE * pbMemBlockStart, BYTE * pbMemBlockEnd, ptrdiff_t cbRelocDistance, size_t profilingContext, BOOL fCompacting, BOOL fAllowProfApiNotification = TRUE);
static void EndMovedReferences(size_t profilingContext, BOOL fAllowProfApiNotification = TRUE);
static void WalkStaticsAndCOMForETW();
static void WalkHeap();
};
};

Expand All @@ -212,6 +220,7 @@ inline void ETW::GCLog::RootReference(
ProfilingScanContext * profilingScanContext,
DWORD dwGCFlags,
DWORD rootFlags) { }
inline void ETW::GCLog::WalkHeap() { }
#endif

#endif //_VMEVENTTRACE_H_
129 changes: 129 additions & 0 deletions src/coreclr/nativeaot/Runtime/eventtrace_gcheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "eventtrace_etw.h"
#include "eventtracepriv.h"
#include "profheapwalkhelper.h"

/****************************************************************************/
/* Methods that are called from the runtime */
Expand Down Expand Up @@ -964,3 +965,131 @@ void ETW::GCLog::EndHeapDump(ProfilerWalkHeapContext* profilerWalkHeapContext)
profilerWalkHeapContext->pvEtwContext = NULL;
delete pContext;
}

namespace
{
void ProfScanRootsHelper(Object** ppObject, ScanContext* pSC, uint32_t dwFlags)
{
Object* pObj = *ppObject;
if (dwFlags& GC_CALL_INTERIOR)
{
pObj = GCHeapUtilities::GetGCHeap()->GetContainingObject(pObj, true);
if (pObj == nullptr)
return;
}
ScanRootsHelper(pObj, ppObject, pSC, dwFlags);
}

void GcScanRootsForETW(promote_func* fn, int condemned, int max_gen, ScanContext* sc)
{
UNREFERENCED_PARAMETER(condemned);
UNREFERENCED_PARAMETER(max_gen);

FOREACH_THREAD(pThread)
{
if (pThread->IsGCSpecial())
continue;

if (GCHeapUtilities::GetGCHeap()->IsThreadUsingAllocationContextHeap(pThread->GetAllocContext(), sc->thread_number))
continue;

sc->thread_under_crawl = pThread;
sc->dwEtwRootKind = kEtwGCRootKindStack;
pThread->GcScanRoots(reinterpret_cast<void*>(fn), sc);
sc->dwEtwRootKind = kEtwGCRootKindOther;
}
END_FOREACH_THREAD
}

void ScanHandleForETW(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent)
{
ProfilingScanContext* pSC = (ProfilingScanContext*)context;

// Notify ETW of the handle
if (ETW::GCLog::ShouldWalkHeapRootsForEtw())
{
ETW::GCLog::RootReference(
pRef,
*pRef, // object being rooted
pSec, // pSecondaryNodeForDependentHandle
isDependent,
pSC,
0, // dwGCFlags,
flags); // ETW handle flags
}
}

// This is called only if we've determined that either:
// a) The Profiling API wants to do a walk of the heap, and it has pinned the
// profiler in place (so it cannot be detached), and it's thus safe to call into the
// profiler, OR
// b) ETW infrastructure wants to do a walk of the heap either to log roots,
// objects, or both.
// This can also be called to do a single walk for BOTH a) and b) simultaneously. Since
// ETW can ask for roots, but not objects
void GCProfileWalkHeapWorker(BOOL fShouldWalkHeapRootsForEtw, BOOL fShouldWalkHeapObjectsForEtw)
{
ProfilingScanContext SC(FALSE);
unsigned max_generation = GCHeapUtilities::GetGCHeap()->GetMaxGeneration();

// **** Scan roots: Only scan roots if profiling API wants them or ETW wants them.
if (fShouldWalkHeapRootsForEtw)
{
GcScanRootsForETW(&ProfScanRootsHelper, max_generation, max_generation, &SC);
SC.dwEtwRootKind = kEtwGCRootKindFinalizer;
GCHeapUtilities::GetGCHeap()->DiagScanFinalizeQueue(&ProfScanRootsHelper, &SC);

// Handles are kept independent of wks/svr/concurrent builds
SC.dwEtwRootKind = kEtwGCRootKindHandle;
GCHeapUtilities::GetGCHeap()->DiagScanHandles(&ScanHandleForETW, max_generation, &SC);
}

// **** Scan dependent handles: only if ETW wants roots
if (fShouldWalkHeapRootsForEtw)
{
// GcScanDependentHandlesForProfiler double-checks
// CORProfilerTrackConditionalWeakTableElements() before calling into the profiler

ProfilingScanContext* pSC = &SC;

// we'll re-use pHeapId (which was either unused (0) or freed by EndRootReferences2
// (-1)), so reset it to NULL
_ASSERTE((*((size_t *)(&pSC->pHeapId)) == (size_t)(-1)) ||
(*((size_t *)(&pSC->pHeapId)) == (size_t)(0)));
pSC->pHeapId = NULL;

GCHeapUtilities::GetGCHeap()->DiagScanDependentHandles(&ScanHandleForETW, max_generation, &SC);
}

ProfilerWalkHeapContext profilerWalkHeapContext(FALSE, SC.pvEtwContext);

// **** Walk objects on heap: only if ETW wants them.
if (fShouldWalkHeapObjectsForEtw)
{
GCHeapUtilities::GetGCHeap()->DiagWalkHeap(&HeapWalkHelper, &profilerWalkHeapContext, max_generation, true /* walk the large object heap */);
}

// **** Done! Indicate to ETW helpers that the heap walk is done, so any buffers
// should be flushed into the ETW stream
if (fShouldWalkHeapObjectsForEtw || fShouldWalkHeapRootsForEtw)
{
ETW::GCLog::EndHeapDump(&profilerWalkHeapContext);
}
}
}

void ETW::GCLog::WalkHeap()
{
if (ETW::GCLog::ShouldWalkStaticsAndCOMForEtw())
ETW::GCLog::WalkStaticsAndCOMForETW();

BOOL fShouldWalkHeapRootsForEtw = ETW::GCLog::ShouldWalkHeapRootsForEtw();
BOOL fShouldWalkHeapObjectsForEtw = ETW::GCLog::ShouldWalkHeapObjectsForEtw();

// we need to walk the heap if one of GC_PROFILING or FEATURE_EVENT_TRACE
// is defined, since both of them make use of the walk heap worker.
if (fShouldWalkHeapRootsForEtw || fShouldWalkHeapObjectsForEtw)
{
GCProfileWalkHeapWorker(fShouldWalkHeapRootsForEtw, fShouldWalkHeapObjectsForEtw);
}
}
Loading

0 comments on commit 02e28c9

Please sign in to comment.