Skip to content

Commit

Permalink
Introduce Flush Caches For GC hook
Browse files Browse the repository at this point in the history
It will trigger before flushing itself, so that users can report or
process stats for various application thread caches before they are
cleared.

Signed-off-by: Aleksandar Micic <Aleksandar_Micic@ca.ibm.com>
  • Loading branch information
Aleksandar Micic authored and Aleksandar Micic committed Mar 1, 2024
1 parent f9174a0 commit ced2f45
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 14 deletions.
36 changes: 22 additions & 14 deletions gc/base/OMRVMInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,17 @@ extern "C" {
* Actions required prior to walking the heap.
*/
void
hookWalkHeapStart(J9HookInterface** hook, uintptr_t eventNum, void* eventData, void* userData)
hookWalkHeapStart(J9HookInterface **hook, uintptr_t eventNum, void *eventData, void *userData)
{
MM_WalkHeapStartEvent* event = (MM_WalkHeapStartEvent*)eventData;
MM_WalkHeapStartEvent *event = (MM_WalkHeapStartEvent *)eventData;
GC_OMRVMInterface::flushCachesForWalk(event->omrVM);
}

/**
* Actions required after to walking the heap.
*/
void
hookWalkHeapEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData, void* userData)
hookWalkHeapEnd(J9HookInterface** hook, uintptr_t eventNum, void *eventData, void *userData)
{
/* Nothing to do right now */
}
Expand All @@ -69,7 +69,7 @@ hookWalkHeapEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData, voi
void
GC_OMRVMInterface::initializeExtensions(MM_GCExtensionsBase *extensions)
{
J9HookInterface** mmPrivateHooks = J9_HOOK_INTERFACE(extensions->privateHookInterface);
J9HookInterface **mmPrivateHooks = J9_HOOK_INTERFACE(extensions->privateHookInterface);

(*mmPrivateHooks)->J9HookRegisterWithCallSite(mmPrivateHooks, J9HOOK_MM_PRIVATE_WALK_HEAP_START, hookWalkHeapStart, OMR_GET_CALLSITE(), NULL);
(*mmPrivateHooks)->J9HookRegisterWithCallSite(mmPrivateHooks, J9HOOK_MM_PRIVATE_WALK_HEAP_END, hookWalkHeapEnd, OMR_GET_CALLSITE(), NULL);
Expand All @@ -88,19 +88,19 @@ GC_OMRVMInterface::getOmrHookInterface(MM_GCExtensionsBase *extensions)
* Flush Cache for walk.
*/
void
GC_OMRVMInterface::flushCachesForWalk(OMR_VM* omrVM)
GC_OMRVMInterface::flushCachesForWalk(OMR_VM *omrVM)
{
/*
* Environment at this point might be fake, so we can not get this thread info
* however only one thread suppose to have an exclusive access at this point
*/
//Assert_MM_true(J9_XACCESS_EXCLUSIVE == vm->exclusiveAccessState);

OMR_VMThread *omrVMThread;
OMR_VMThread *omrVMThread = NULL;

GC_OMRVMThreadListIterator threadListIterator(omrVM);

while((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
while ((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
MM_EnvironmentBase *envToFlush = MM_EnvironmentBase::getEnvironment(omrVMThread);
GC_OMRVMThreadInterface::flushCachesForWalk(envToFlush);
}
Expand All @@ -112,20 +112,28 @@ GC_OMRVMInterface::flushCachesForWalk(OMR_VM* omrVM)
void
GC_OMRVMInterface::flushCachesForGC(MM_EnvironmentBase *env)
{
OMRPORT_ACCESS_FROM_ENVIRONMENT(env);

MM_GCExtensionsBase *extensions = env->getExtensions();
OMR_VMThread *omrVMThread;
OMR_VMThread *omrVMThread = NULL;
UDATA allocatedBytesMax = extensions->bytesAllocatedMost;
OMR_VMThread *vmThreadMax = extensions->vmThreadAllocatedMost;

TRIGGER_J9HOOK_MM_OMR_FLUSH_CACHES_FOR_GC(
extensions->omrHookInterface,
env->getOmrVMThread(),
omrtime_hires_clock(),
J9HOOK_MM_OMR_FLUSH_CACHES_FOR_GC);

GC_OMRVMThreadListIterator threadListIterator(env->getOmrVM());

while((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
while ((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
/* Grab allocation bytes stats per-thread before they're cleared */
MM_EnvironmentBase* threadEnv = MM_EnvironmentBase::getEnvironment(omrVMThread);
MM_AllocationStats * stats= threadEnv->_objectAllocationInterface->getAllocationStats();
MM_EnvironmentBase *threadEnv = MM_EnvironmentBase::getEnvironment(omrVMThread);
MM_AllocationStats *stats= threadEnv->_objectAllocationInterface->getAllocationStats();
UDATA allocatedBytes = stats->bytesAllocated();

if(allocatedBytes >= allocatedBytesMax){
if (allocatedBytes >= allocatedBytesMax){
allocatedBytesMax = allocatedBytes;
vmThreadMax = omrVMThread;
}
Expand All @@ -142,11 +150,11 @@ GC_OMRVMInterface::flushCachesForGC(MM_EnvironmentBase *env)
void
GC_OMRVMInterface::flushNonAllocationCaches(MM_EnvironmentBase *env)
{
OMR_VMThread *omrVMThread;
OMR_VMThread *omrVMThread = NULL;

GC_OMRVMThreadListIterator threadListIterator(env->getOmrVM());

while((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
while ((omrVMThread = threadListIterator.nextOMRVMThread()) != NULL) {
GC_OMRVMThreadInterface::flushNonAllocationCaches(MM_EnvironmentBase::getEnvironment(omrVMThread));
}
}
13 changes: 13 additions & 0 deletions gc/include/omrmm.hdf
Original file line number Diff line number Diff line change
Expand Up @@ -285,4 +285,17 @@ typedef uintptr_t (*condYieldFromGCFunctionPtr) (OMR_VMThread *omrVMThread, uint
<data type="uint64_t" name="timestamp" description="time of event" />
</event>

<event>
<name>J9HOOK_MM_OMR_FLUSH_CACHES_FOR_GC</name>
<description>
This is called slightly after exclusive VM access is acquired, and slightly before various GC start hooks.
This is called before flush itself, which deletes all the stats of the various application thread caches.
So, it's very similar to the GC start event, except all the stats are still available for reporting and processing.
</description>
<struct>MM_FlushCachesForGCEvent</struct>
<data type="struct OMR_VMThread*" name="currentThread" description="current thread" />
<data type="uint64_t" name="timestamp" description="time of event" />
<data type="uintptr_t" name="eventid" description="unique identifier for event" />
</event>

</interface>

0 comments on commit ced2f45

Please sign in to comment.