Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/Native/Runtime/eventtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,18 @@
#define _VMEVENTTRACE_H_

#include "eventtracebase.h"
#include "gcinterface.h"

#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
struct ProfilingScanContext : ScanContext
{
BOOL fProfilerPinned;
void * pvEtwContext;
void *pHeapId;

ProfilingScanContext(BOOL fProfilerPinnedParam);
};
#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)

namespace ETW
{
Expand Down
12 changes: 11 additions & 1 deletion src/Native/Runtime/gcheaputilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,14 @@
#include "gcheaputilities.h"

// This is the global GC heap, maintained by the VM.
GPTR_IMPL(IGCHeap, g_pGCHeap);
GPTR_IMPL(IGCHeap, g_pGCHeap);

// These globals are variables used within the GC and maintained
// by the EE for use in write barriers. It is the responsibility
// of the GC to communicate updates to these globals to the EE through
// GCToEEInterface::StompWriteBarrier.
GPTR_IMPL_INIT(uint32_t, g_card_table, nullptr);
GPTR_IMPL_INIT(uint8_t, g_lowest_address, nullptr);
GPTR_IMPL_INIT(uint8_t, g_highest_address, nullptr);
uint8_t* g_ephemeral_low = (uint8_t*)1;
uint8_t* g_ephemeral_high = (uint8_t*)~0;
14 changes: 14 additions & 0 deletions src/Native/Runtime/gcheaputilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@
// The singular heap instance.
GPTR_DECL(IGCHeap, g_pGCHeap);

#ifndef DACCESS_COMPILE
extern "C" {
#endif // !DACCESS_COMPILE
GPTR_DECL(uint8_t,g_lowest_address);
GPTR_DECL(uint8_t,g_highest_address);
GPTR_DECL(uint32_t,g_card_table);
#ifndef DACCESS_COMPILE
}
#endif // !DACCESS_COMPILE

extern "C" uint8_t* g_ephemeral_low;
extern "C" uint8_t* g_ephemeral_high;


// GCHeapUtilities provides a number of static methods
// that operate on the global heap instance. It can't be
// instantiated.
Expand Down
209 changes: 197 additions & 12 deletions src/Native/Runtime/gcrhenv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@

#include "holder.h"

#ifdef FEATURE_ETW
#ifndef _INC_WINDOWS
typedef void* LPVOID;
typedef uint32_t UINT;
typedef void* PVOID;
typedef uint64_t ULONGLONG;
typedef uint32_t ULONG;
typedef int64_t LONGLONG;
typedef uint8_t BYTE;
typedef uint16_t UINT16;
#endif // _INC_WINDOWS

#include "etwevents.h"
#include "eventtrace.h"
#else // FEATURE_ETW
#include "etmdummy.h"
#define ETW_EVENT_ENABLED(e,f) false
#endif // FEATURE_ETW

GPTR_IMPL(EEType, g_pFreeObjectEEType);

#define USE_CLR_CACHE_SIZE_BEHAVIOR
Expand Down Expand Up @@ -119,7 +138,7 @@ UInt32 EtwCallback(UInt32 IsEnabled, RH_ETW_CONTEXT * pContext)
FireEtwGCSettings(GCHeapUtilities::GetGCHeap()->GetValidSegmentSize(FALSE),
GCHeapUtilities::GetGCHeap()->GetValidSegmentSize(TRUE),
GCHeapUtilities::IsServerHeap());
GCHeapUtilities::GetGCHeap()->TraceGCSegments();
GCHeapUtilities::GetGCHeap()->DiagTraceGCSegments();
}

// Special check for the runtime provider's GCHeapCollectKeyword. Profilers
Expand Down Expand Up @@ -686,8 +705,8 @@ void RedhawkGCInterface::ScanHeap(GcScanObjectFunction pfnScanCallback, void *pC
// static
void RedhawkGCInterface::ScanObject(void *pObject, GcScanObjectFunction pfnScanCallback, void *pContext)
{
#if !defined(DACCESS_COMPILE) && (defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE))
GCHeapUtilities::GetGCHeap()->WalkObject((Object*)pObject, (walk_fn)pfnScanCallback, pContext);
#if !defined(DACCESS_COMPILE) && defined(FEATURE_EVENT_TRACE)
GCHeapUtilities::GetGCHeap()->DiagWalkObject((Object*)pObject, (walk_fn)pfnScanCallback, pContext);
#else
UNREFERENCED_PARAMETER(pObject);
UNREFERENCED_PARAMETER(pfnScanCallback);
Expand Down Expand Up @@ -759,7 +778,7 @@ void RedhawkGCInterface::ScanStaticRoots(GcScanRootFunction pfnScanCallback, voi
// static
void RedhawkGCInterface::ScanHandleTableRoots(GcScanRootFunction pfnScanCallback, void *pContext)
{
#if !defined(DACCESS_COMPILE) && (defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE))
#if !defined(DACCESS_COMPILE) && defined(FEATURE_EVENT_TRACE)
ScanRootsContext sContext;
sContext.m_pfnCallback = pfnScanCallback;
sContext.m_pContext = pContext;
Expand Down Expand Up @@ -1148,6 +1167,166 @@ Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threa
return threadStubArgs.m_pThread;
}

void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
{
UNREFERENCED_PARAMETER(gen);
UNREFERENCED_PARAMETER(isInduced);
}

void GCToEEInterface::DiagUpdateGenerationBounds()
{
}

void GCToEEInterface::DiagWalkFReachableObjects(void* gcContext)
{
UNREFERENCED_PARAMETER(gcContext);
}

void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurrent)
{
UNREFERENCED_PARAMETER(index);
UNREFERENCED_PARAMETER(gen);
UNREFERENCED_PARAMETER(reason);
UNREFERENCED_PARAMETER(fConcurrent);
}

// Note on last parameter: when calling this for bgc, only ETW
// should be sending these events so that existing profapi profilers
// don't get confused.
void WalkMovedReferences(uint8_t* begin, uint8_t* end,
ptrdiff_t reloc,
size_t context,
BOOL fCompacting,
BOOL fBGC)
{
UNREFERENCED_PARAMETER(begin);
UNREFERENCED_PARAMETER(end);
UNREFERENCED_PARAMETER(reloc);
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(fCompacting);
UNREFERENCED_PARAMETER(fBGC);
}

//
// Diagnostics code
//

#ifdef FEATURE_EVENT_TRACE
inline BOOL ShouldTrackMovementForProfilerOrEtw()
{
if (ETW::GCLog::ShouldTrackMovementForEtw())
return true;

return false;
}
#endif // FEATURE_EVENT_TRACE

void GCToEEInterface::DiagWalkSurvivors(void* gcContext)
{
#ifdef FEATURE_EVENT_TRACE
if (ShouldTrackMovementForProfilerOrEtw())
{
size_t context = 0;
ETW::GCLog::BeginMovedReferences(&context);
GCHeapUtilities::GetGCHeap()->DiagWalkSurvivorsWithType(gcContext, &WalkMovedReferences, context, walk_for_gc);
ETW::GCLog::EndMovedReferences(context);
}
#else
UNREFERENCED_PARAMETER(gcContext);
#endif // FEATURE_EVENT_TRACE
}

void GCToEEInterface::DiagWalkLOHSurvivors(void* gcContext)
{
#ifdef FEATURE_EVENT_TRACE
if (ShouldTrackMovementForProfilerOrEtw())
{
size_t context = 0;
ETW::GCLog::BeginMovedReferences(&context);
GCHeapUtilities::GetGCHeap()->DiagWalkSurvivorsWithType(gcContext, &WalkMovedReferences, context, walk_for_loh);
ETW::GCLog::EndMovedReferences(context);
}
#else
UNREFERENCED_PARAMETER(gcContext);
#endif // FEATURE_EVENT_TRACE
}

void GCToEEInterface::DiagWalkBGCSurvivors(void* gcContext)
{
#ifdef FEATURE_EVENT_TRACE
if (ShouldTrackMovementForProfilerOrEtw())
{
size_t context = 0;
ETW::GCLog::BeginMovedReferences(&context);
GCHeapUtilities::GetGCHeap()->DiagWalkSurvivorsWithType(gcContext, &WalkMovedReferences, context, walk_for_bgc);
ETW::GCLog::EndMovedReferences(context);
}
#else
UNREFERENCED_PARAMETER(gcContext);
#endif // FEATURE_EVENT_TRACE
}

void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
{
// CoreRT doesn't patch the write barrier like CoreCLR does, but it
// still needs to record the changes in the GC heap.
assert(args != nullptr);
switch (args->operation)
{
case WriteBarrierOp::StompResize:
// StompResize requires a new card table, a new lowest address, and
// a new highest address
assert(args->card_table != nullptr);
assert(args->lowest_address != nullptr);
assert(args->highest_address != nullptr);
g_card_table = args->card_table;

// We need to make sure that other threads executing checked write barriers
// will see the g_card_table update before g_lowest/highest_address updates.
// Otherwise, the checked write barrier may AV accessing the old card table
// with address that it does not cover. Write barriers access card table
// without memory barriers for performance reasons, so we need to flush
// the store buffers here.
FlushProcessWriteBuffers();

g_lowest_address = args->lowest_address;
VolatileStore(&g_highest_address, args->highest_address);
return;
case WriteBarrierOp::StompEphemeral:
// StompEphemeral requires a new ephemeral low and a new ephemeral high
assert(args->ephemeral_low != nullptr);
assert(args->ephemeral_high != nullptr);
g_ephemeral_low = args->ephemeral_low;
g_ephemeral_high = args->ephemeral_high;
return;
case WriteBarrierOp::Initialize:
// This operation should only be invoked once, upon initialization.
assert(g_card_table == nullptr);
assert(g_lowest_address == nullptr);
assert(g_highest_address == nullptr);
assert(args->card_table != nullptr);
assert(args->lowest_address != nullptr);
assert(args->highest_address != nullptr);
assert(args->ephemeral_low != nullptr);
assert(args->ephemeral_high != nullptr);
assert(args->is_runtime_suspended && "the runtime must be suspended here!");

g_card_table = args->card_table;
g_lowest_address = args->lowest_address;
g_highest_address = args->highest_address;
g_ephemeral_low = args->ephemeral_low;
g_ephemeral_high = args->ephemeral_high;
return;
case WriteBarrierOp::SwitchToWriteWatch:
case WriteBarrierOp::SwitchToNonWriteWatch:
assert(!"CoreRT does not have an implementation of non-OS WriteWatch");
return;
default:
assert(!"Unknokwn WriteBarrierOp enum");
return;
}
}

#endif // !DACCESS_COMPILE

// NOTE: this method is not in thread.cpp because it needs access to the layout of alloc_context for DAC to know the
Expand Down Expand Up @@ -1339,14 +1518,6 @@ MethodTable * g_pFreeObjectMethodTable;
int32_t g_TrapReturningThreads;
bool g_fFinalizerRunOnShutDown;

void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
{
}

void StompWriteBarrierResize(bool /* isRuntimeSuspended */, bool /*bReqUpperBoundsCheck*/)
{
}

bool IsGCThread()
{
return false;
Expand Down Expand Up @@ -1425,3 +1596,17 @@ void CPUGroupInfo::GetGroupForProcessor(uint16_t /*processor_number*/, uint16_t
{
ASSERT_UNCONDITIONALLY("NYI: CPUGroupInfo::GetGroupForProcessor");
}

#ifdef FEATURE_EVENT_TRACE
ProfilingScanContext::ProfilingScanContext(BOOL fProfilerPinnedParam)
: ScanContext()
{
pHeapId = NULL;
fProfilerPinned = fProfilerPinnedParam;
pvEtwContext = NULL;
#ifdef FEATURE_CONSERVATIVE_GC
// To not confuse GCScan::GcScanRoots
promotion = g_pConfig->GetGCConservative();
#endif
}
#endif // FEATURE_EVENT_TRACE
4 changes: 2 additions & 2 deletions src/Native/Runtime/profheapwalkhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ BOOL HeapWalkHelper(Object * pBO, void * pvContext)
//if (pMT->ContainsPointersOrCollectible())
{
// First round through calculates the number of object refs for this class
GCHeapUtilities::GetGCHeap()->WalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);

if (cNumRefs > 0)
{
Expand All @@ -166,7 +166,7 @@ BOOL HeapWalkHelper(Object * pBO, void * pvContext)

// Second round saves off all of the ref values
OBJECTREF * pCurObjRef = arrObjRef;
GCHeapUtilities::GetGCHeap()->WalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/Native/Runtime/unix/PalRedhawkUnix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1457,13 +1457,12 @@ void GCToOSInterface::YieldThread(uint32_t switchCount)

// Reserve virtual memory range.
// Parameters:
// address - starting virtual address, it can be NULL to let the function choose the starting address
// size - size of the virtual memory range
// alignment - requested memory alignment, 0 means no specific alignment requested
// flags - flags to control special settings like write watching
// Return:
// Starting virtual address of the reserved range
void* GCToOSInterface::VirtualReserve(void* address, size_t size, size_t alignment, uint32_t flags)
void* GCToOSInterface::VirtualReserve(size_t size, size_t alignment, uint32_t flags)
{
ASSERT_MSG(!(flags & VirtualReserveFlags::WriteWatch), "WriteWatch not supported on Unix");

Expand All @@ -1474,7 +1473,7 @@ void* GCToOSInterface::VirtualReserve(void* address, size_t size, size_t alignme

size_t alignedSize = size + (alignment - OS_PAGE_SIZE);

void * pRetVal = mmap(address, alignedSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
void * pRetVal = mmap(nullptr, alignedSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);

if (pRetVal != NULL)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Native/Runtime/windows/PalRedhawkMinWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1482,7 +1482,7 @@ void GCToOSInterface::YieldThread(uint32_t /*switchCount*/)
// flags - flags to control special settings like write watching
// Return:
// Starting virtual address of the reserved range
void* GCToOSInterface::VirtualReserve(void* address, size_t size, size_t alignment, uint32_t flags)
void* GCToOSInterface::VirtualReserve(size_t size, size_t alignment, uint32_t flags)
{
DWORD memFlags = (flags & VirtualReserveFlags::WriteWatch) ? (MEM_RESERVE | MEM_WRITE_WATCH) : MEM_RESERVE;
return ::VirtualAlloc(0, size, memFlags, PAGE_READWRITE);
Expand Down
2 changes: 1 addition & 1 deletion src/Native/gc/env/gcenv.base.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ inline HRESULT HRESULT_FROM_WIN32(unsigned long x)
#define UNREFERENCED_PARAMETER(P) (void)(P)

#ifdef PLATFORM_UNIX
#define _vsnprintf vsnprintf
#define _vsnprintf_s(string, sizeInBytes, count, format, args) vsnprintf(string, sizeInBytes, format, args)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am surprised that this compiles - args can be variable number of arguments. Does this need to use some kind of open args syntax to work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the usage it seems like args is always a va_list (and that seems consistent with the Windows CRT definition of _vsnprintf_s).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see.

#define sprintf_s snprintf
#define swprintf_s swprintf
#endif
Expand Down
10 changes: 10 additions & 0 deletions src/Native/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ class GCToEEInterface
static void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param);

static Thread* CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg);

// Diagnostics methods.
static void DiagGCStart(int gen, bool isInduced);
static void DiagUpdateGenerationBounds();
static void DiagGCEnd(size_t index, int gen, int reason, bool fConcurrent);
static void DiagWalkFReachableObjects(void* gcContext);
static void DiagWalkSurvivors(void* gcContext);
static void DiagWalkLOHSurvivors(void* gcContext);
static void DiagWalkBGCSurvivors(void* gcContext);
static void StompWriteBarrier(WriteBarrierParameters* args);
};

#endif // __GCENV_EE_H__
Loading