Skip to content
Draft
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
2 changes: 2 additions & 0 deletions src/coreclr/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class GCToEEInterface

static void TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args);

static bool IsClientBridgeProcessingActive();

// Sync block cache management
static void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2);
static void SyncBlockCacheDemote(int max_gen);
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/gc/env/gctoeeinterface.standalone.inl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ namespace standalone
return ::GCToEEInterface::TriggerClientBridgeProcessing(args);
}

bool IsClientBridgeProcessingActive()
{
return ::GCToEEInterface::IsClientBridgeProcessingActive();
}

void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
::GCToEEInterface::SyncBlockCacheWeakPtrScan(scanProc, lp1, lp2);
Expand Down
27 changes: 27 additions & 0 deletions src/coreclr/gc/gcbridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,9 @@ static void ResetXRefs(ColorData* color)
static uint64_t g_startTime;
static uint64_t g_afterTarjanTime;

// Timestamp, in microseconds, of the last set of cross references handed to the client.
static uint64_t g_lastBridgeRequestTime;

static void BridgeFinish()
{
#if DUMP_GRAPH
Expand Down Expand Up @@ -1111,6 +1114,28 @@ uint8_t** GetRegisteredBridges(size_t* pNumBridges)
return (uint8_t**)g_registeredBridges.data;
}

bool ShouldProcessBridgeObjects(uint32_t condemned)
{
// The client discards any set of cross references handed to it while it is still
// processing a previous one, so computing it would be pure waste.
if (GCToEEInterface::IsClientBridgeProcessingActive())
return false;

// Requests are only throttled for gen0 collections. Bridge objects that are not handed to
// the client are still promoted, so a deferred object cannot be registered again by a later
// gen0 collection; keeping gen1 and gen2 unthrottled bounds how long a dead peer can go
// unreported to the next gen1 collection.
if (condemned > 0)
return true;

int64_t minIntervalMs = GCConfig::GetGCBridgeMinIntervalMs();
if (minIntervalMs <= 0)
return true;

uint64_t now = GetHighPrecisionTimeStamp();
return (now - g_lastBridgeRequestTime) >= ((uint64_t)minIntervalMs * 1000);
}

static bool TarjanSccAlgorithm()
{
int i;
Expand Down Expand Up @@ -1293,6 +1318,8 @@ MarkCrossReferencesArgs* ProcessBridgeObjects()

BridgeFinish();

g_lastBridgeRequestTime = GetHighPrecisionTimeStamp();

return args;
}

Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/gc/gcbridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
void BridgeResetData();
MarkCrossReferencesArgs* ProcessBridgeObjects();

// Decides whether this collection should hand a fresh set of cross references to the client.
// Returns false when the client is still processing a previous set (the new one would just be
// discarded) or when the request would arrive too soon after the previous one. Only gen0
// collections are ever throttled, so a deferred object is guaranteed to be reconsidered by the
// next gen1 or gen2 collection.
bool ShouldProcessBridgeObjects(uint32_t condemned);

void RegisterBridgeObject(Object *object, uintptr_t context);
uint8_t** GetRegisteredBridges(size_t *pNumBridges);

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/gc/gcconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ class GCConfigStringHolder
INT_CONFIG (GCRegionRange, "GCRegionRange", "System.GC.RegionRange", 0, "Specifies the range for the GC heap") \
INT_CONFIG (GCRegionSize, "GCRegionSize", "System.GC.RegionSize", 0, "Specifies the size for a basic GC region") \
INT_CONFIG (GCEnableSpecialRegions, "GCEnableSpecialRegions", NULL, 0, "Specifies to enable special handling some regions like SIP") \
INT_CONFIG (GCBridgeMinIntervalMs, "GCBridgeMinIntervalMs", "System.GC.BridgeMinIntervalMs", 50, "Minimum number of milliseconds between two consecutive cross-reference (Java bridge) " \
"processing requests handed to the client. Ephemeral collections that occur inside that " \
"window skip the request; collections of gen1 and above are never skipped. 0 disables " \
"throttling.") \
Comment on lines +111 to +114
STRING_CONFIG(LogFile, "GCLogFile", NULL, "Specifies the name of the GC log file") \
STRING_CONFIG(ConfigLogFile, "GCConfigLogFile", NULL, "Specifies the name of the GC config log file") \
INT_CONFIG (BGCFLTuningEnabled, "BGCFLTuningEnabled", NULL, 0, "Enables FL tuning") \
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/gc/gcenv.ee.standalone.inl
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ inline void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesAr
}
}

inline bool GCToEEInterface::IsClientBridgeProcessingActive()
{
assert(g_theGCToCLR != nullptr);
if (g_runtimeSupportedVersion.MajorVersion >= 5)
{
return g_theGCToCLR->IsClientBridgeProcessingActive();
}

return false;
}

inline void GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
assert(g_theGCToCLR != nullptr);
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/gc/gcinterface.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,14 @@ class IGCToCLR {

virtual
void TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args) PURE_VIRTUAL

// The following method is available only with EE_INTERFACE_MAJOR_VERSION >= 5

// Returns true when the client is still processing cross references handed to it by a
// previous call to TriggerClientBridgeProcessing. While that is the case any new set of
// cross references would be discarded by the client, so the GC can skip computing it.
virtual
bool IsClientBridgeProcessingActive() PURE_VIRTUAL
};

#endif // _GCINTERFACE_EE_H_
2 changes: 1 addition & 1 deletion src/coreclr/gc/gcinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

// The major version of the IGCToCLR interface. Breaking changes to this interface
// require bumps in the major version number.
#define EE_INTERFACE_MAJOR_VERSION 4
#define EE_INTERFACE_MAJOR_VERSION 5

struct ScanContext;
struct gc_alloc_context;
Expand Down
13 changes: 9 additions & 4 deletions src/coreclr/gc/objecthandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1535,13 +1535,18 @@ uint8_t** Ref_ScanBridgeObjects(uint32_t condemned, uint32_t maxgen, ScanContext
}

// The callee here will free the allocated memory.
MarkCrossReferencesArgs *args = ProcessBridgeObjects();

if (args != NULL)
if (ShouldProcessBridgeObjects(condemned))
{
GCToEEInterface::TriggerClientBridgeProcessing(args);
MarkCrossReferencesArgs *args = ProcessBridgeObjects();

if (args != NULL)
{
GCToEEInterface::TriggerClientBridgeProcessing(args);
}
}

// Every registered bridge object is promoted whether or not it was handed to the client,
// so skipping the request above only delays reporting it, it never collects it early.
return GetRegisteredBridges(numObjs);
}
#endif // FEATURE_JAVAMARSHAL
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/gc/sample/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesArgs* arg
{
}

bool GCToEEInterface::IsClientBridgeProcessingActive()
{
return false;
}

bool GCToEEInterface::IsPreemptiveGCDisabled()
{
Thread* pThread = ::GetThread();
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/nativeaot/Runtime/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,4 +826,13 @@ void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesArgs* arg
#endif
}

bool GCToEEInterface::IsClientBridgeProcessingActive()
{
#ifdef FEATURE_JAVAMARSHAL
return JavaMarshalNative::IsGCBridgeActive();
#else
return false;
#endif
}

#endif // !DACCESS_COMPILE
2 changes: 2 additions & 0 deletions src/coreclr/nativeaot/Runtime/interoplibinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ class JavaMarshalNative
public:
static void TriggerClientBridgeProcessing(
MarkCrossReferencesArgs* args);

static bool IsGCBridgeActive();
};
#endif // FEATURE_JAVAMARSHAL
5 changes: 5 additions & 0 deletions src/coreclr/nativeaot/Runtime/interoplibinterface_java.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ namespace
}
}

bool JavaMarshalNative::IsGCBridgeActive()
{
return g_GCBridgeActive;
}

void JavaMarshalNative::TriggerClientBridgeProcessing(
_In_ MarkCrossReferencesArgs* args)
{
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/vm/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,22 @@ void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesArgs* arg
#endif // FEATURE_JAVAMARSHAL
}

bool GCToEEInterface::IsClientBridgeProcessingActive()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;

#ifdef FEATURE_JAVAMARSHAL
return Interop::IsGCBridgeActive();
#else
return false;
#endif // FEATURE_JAVAMARSHAL
}

void GCToEEInterface::SyncBlockCacheDemote(int max_gen)
{
CONTRACTL
Expand Down
Loading