Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap size startup hints #4168

Merged
merged 1 commit into from
Jan 8, 2019
Merged
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
4 changes: 3 additions & 1 deletion runtime/gc/dllinit.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*******************************************************************************
* Copyright (c) 1991, 2017 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -91,6 +91,8 @@ J9VMDllMain(J9JavaVM* vm, IDATA stage, void* reserved)
break;

case ABOUT_TO_BOOTSTRAP :
/* Expand heap based on hints stored by previous runs into Shared Cache */
gcExpandHeapOnStartup(vm);
case JCL_INITIALIZED :
case LIBRARIES_ONUNLOAD :
break;
Expand Down
3 changes: 2 additions & 1 deletion runtime/gc/gctable.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -53,6 +53,7 @@ J9MemoryManagerFunctions MemoryManagerFunctions = {
j9gc_get_private_hook_interface,
gcStartupHeapManagement,
gcShutdownHeapManagement,
j9gc_jvmPhaseChange,
initializeMutatorModelJava,
cleanupMutatorModelJava,
#if defined(J9VM_GC_FINALIZATION)
Expand Down
3 changes: 2 additions & 1 deletion runtime/gc_base/gc_internal.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -101,6 +101,7 @@ extern J9_CFUNC void j9gc_objaccess_copyObjectFields(J9VMThread *vmThread, J9Cla
extern J9_CFUNC j9object_t j9gc_objaccess_asConstantPoolObject(J9VMThread *vmThread, j9object_t toConvert, UDATA allocationFlags);
extern J9_CFUNC jvmtiIterationControl j9mm_iterate_heaps(J9JavaVM *vm, J9PortLibrary *portLibrary, UDATA flags, jvmtiIterationControl(*func)(J9JavaVM *vm, struct J9MM_IterateHeapDescriptor *heapDesc, void *userData), void *userData);
extern J9_CFUNC int gcStartupHeapManagement(J9JavaVM * vm);
extern J9_CFUNC void j9gc_jvmPhaseChange(J9VMThread *currentThread, UDATA phase);
extern J9_CFUNC void j9gc_ext_reachable_from_object_do(J9VMThread *vmThread, j9object_t objectPtr, jvmtiIterationControl(*func)(j9object_t *slotPtr, j9object_t sourcePtr, void *userData, IDATA type, IDATA index, IDATA wasReportedBefore), void *userData, UDATA walkFlags);
extern J9_CFUNC UDATA moveObjectToMemorySpace(J9VMThread *vmThread, void *destinationMemorySpace, j9object_t objectPtr);
/* TODO: The signature of allocateMemoryForSublistFragment temporarily uses void* instead of OMR_VMThread* since the latter is a class */
Expand Down
104 changes: 103 additions & 1 deletion runtime/gc_modron_startup/mminit.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -597,6 +597,108 @@ gcStartupHeapManagement(J9JavaVM *javaVM)
return result;
}

void j9gc_jvmPhaseChange(J9VMThread *currentThread, UDATA phase)
{
J9JavaVM *vm = currentThread->javaVM;
MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm);
MM_EnvironmentBase env(currentThread->omrVMThread);
if (J9VM_PHASE_NOT_STARTUP == phase) {

if (NULL != vm->sharedClassConfig) {
if (extensions->isStandardGC()) {
/* read old values from SC */
uintptr_t hintDefaultOld = 0;
uintptr_t hintTenureOld = 0;
vm->sharedClassConfig->findGCHints(currentThread, &hintDefaultOld, &hintTenureOld);
/* Nothing to do if read fails, we'll just assume the old values are 0 */

/* Get the current heap size values.
* Default/Tenure MemorySubSpace is of type Generic (which is MemoryPool owner, while the parents are of type Flat/SemiSpace).
* For SemiSpace the latter (parent) ones are what we want to deal with (expand), since it's what includes both Allocate And Survivor children.
* For Flat it would probably make no difference if we used parent or child, but let's be consistent and use parent, too.
*/
MM_MemorySubSpace *defaultMemorySubSpace = extensions->heap->getDefaultMemorySpace()->getDefaultMemorySubSpace()->getParent();
MM_MemorySubSpace *tenureMemorySubspace = extensions->heap->getDefaultMemorySpace()->getTenureMemorySubSpace()->getParent();

/* Default MSS is either OLD or NEW at a time (flat or generational), but we can safely ask for both. We cannot just use plain
* getActiveMemorySize() without arguments since it would return just Allocate size for Nursery, but we need total Nursery size.
*/
uintptr_t hintDefault = defaultMemorySubSpace->getActiveMemorySize(MEMORY_TYPE_OLD | MEMORY_TYPE_NEW);
uintptr_t hintTenure = 0;

/* Standard GCs always have Default MSS (which is equal to Tenure for flat heap configuration).
* So the simplest is always fetch Default, regardless if's generational haep configuration or not.
* We fetch Tenure only if only not equal to Default (which implies it's generational) */
if (defaultMemorySubSpace != tenureMemorySubspace) {
hintTenure = tenureMemorySubspace->getActiveMemorySize();
}

/* Gradually learn, by averaging new values with old values - it may take a few restarts before hint converge to stable values */
hintDefault = (uintptr_t)MM_Math::weightedAverage(hintDefaultOld, hintDefault, (1.0 - extensions->heapSizeStatupHintWeightNewValue));
hintTenure = (uintptr_t)MM_Math::weightedAverage(hintTenureOld, hintTenure, (1.0 - extensions->heapSizeStatupHintWeightNewValue));

vm->sharedClassConfig->storeGCHints(currentThread, hintDefault, hintTenure, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

as we discussed we should double check are we allowed to update shared cache every JVM run

Copy link
Member

@pshipton pshipton Jan 7, 2019

Choose a reason for hiding this comment

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

The hints in the shared cache can be updated, although it does lock down the cache while doing so. Fewer updates are better. The hints are updated in place, there is no shared cache expansion involved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is only a single update per VM run (on PHASE_NOT_STARTUP transition).

Copy link
Member

Choose a reason for hiding this comment

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

It basically serializes JVM startup. i.e. say 100 JVMs are started at the same time, all of them will wait to update the shared cache, one at a time.

/* Nothing to do if store fails, storeGCHints already issues a trace point */
}
}
}
}


void
gcExpandHeapOnStartup(J9JavaVM *javaVM)
{
J9SharedClassConfig *sharedClassConfig = javaVM->sharedClassConfig;
MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(javaVM);
J9VMThread *currentThread = javaVM->internalVMFunctions->currentVMThread(javaVM);
MM_EnvironmentBase env(currentThread->omrVMThread);

if (NULL != sharedClassConfig) {
if (extensions->isStandardGC()) {
uintptr_t hintDefault = 0;
uintptr_t hintTenure = 0;

if (0 == sharedClassConfig->findGCHints(currentThread, &hintDefault, &hintTenure)) {

/* Default/Tenure MemorySubSpace is of type Generic (which is MemoryPool owner, while the parents are of type Flat/SemiSpace).
* For SemiSpace the latter (parent) ones are what we want to deal with (expand), since it's what includes both Allocate And Survivor children.
* For Flat it would probably make no difference if we used parent or child, but let's be consistent and use parent, too.
*/
MM_MemorySubSpace *defaultMemorySubSpace = extensions->heap->getDefaultMemorySpace()->getDefaultMemorySubSpace()->getParent();
MM_MemorySubSpace *tenureMemorySubspace = extensions->heap->getDefaultMemorySpace()->getTenureMemorySubSpace()->getParent();


/* Standard GCs always have Default MSS (which is equal to Tenure for flat heap configuration).
* So the simplest is always deal with Default, regardless if's generational heap configuration or not.
* We deal with Tenure only if only not equal to Default (which implies it's generational)
* We are a bit conservative and aim for slightly lower values that historically recorded by hints.
*/
uintptr_t hintDefaultAdjusted = (uintptr_t)(hintDefault * extensions->heapSizeStatupHintConservativeFactor);
uintptr_t defaultCurrent = defaultMemorySubSpace->getActiveMemorySize(MEMORY_TYPE_OLD | MEMORY_TYPE_NEW);
if (hintDefaultAdjusted > defaultCurrent) {
extensions->heap->getResizeStats()->setLastExpandReason(HINT_PREVIOUS_RUNS);
defaultMemorySubSpace->expand(&env, hintDefaultAdjusted - defaultCurrent);
}


if (defaultMemorySubSpace != tenureMemorySubspace) {
uintptr_t hintTenureAdjusted = (uintptr_t)(hintTenure * extensions->heapSizeStatupHintConservativeFactor);
uintptr_t tenureCurrent = tenureMemorySubspace->getActiveMemorySize();

if (hintTenureAdjusted > tenureCurrent) {
extensions->heap->getResizeStats()->setLastExpandReason(HINT_PREVIOUS_RUNS);
tenureMemorySubspace->expand(&env, hintTenureAdjusted - tenureCurrent);
}
}

}
/* Nothing to do if findGCHints failed. It already issues a trace point - no need to duplicate it here */
}
/* todo: Balanced GC */
}
}


/**
* Cleanup Finalizer and Heap components
*/
Expand Down
5 changes: 4 additions & 1 deletion runtime/gc_modron_startup/mminit.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*******************************************************************************
* Copyright (c) 1991, 2017 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -49,6 +49,9 @@ void gcCleanupHeapStructures(J9JavaVM* vm);

jint triggerGCInitialized(J9VMThread* vmThread);

void gcExpandHeapOnStartup(J9JavaVM *javaVM);


#ifdef __cplusplus
} /* extern "C" { */
#endif
Expand Down
30 changes: 29 additions & 1 deletion runtime/gc_modron_startup/mmparseXXgc.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -937,6 +937,34 @@ gcParseXXgcArguments(J9JavaVM *vm, char *optArg)
continue;
}

if (try_scan(&scan_start, "heapSizeStatupHintConservativeFactor=")) {
UDATA percentage = 0;
if(!scan_udata_helper(vm, &scan_start, &percentage, "heapSizeStatupHintConservativeFactor=")) {
returnValue = JNI_EINVAL;
break;
}
if(percentage > 100) {
returnValue = JNI_EINVAL;
break;
}
extensions->heapSizeStatupHintConservativeFactor = ((float)percentage) / 100.0;
continue ;
}

if (try_scan(&scan_start, "heapSizeStatupHintWeightNewValue=")) {
UDATA percentage = 0;
if(!scan_udata_helper(vm, &scan_start, &percentage, "heapSizeStatupHintWeightNewValue=")) {
returnValue = JNI_EINVAL;
break;
}
if(percentage > 100) {
returnValue = JNI_EINVAL;
break;
}
extensions->heapSizeStatupHintWeightNewValue = ((float)percentage) / 100.0;
continue ;
}

#if defined (J9VM_GC_VLHGC)
if (try_scan(&scan_start, "fvtest_tarokSimulateNUMA=")) {
UDATA simulatedNodeCount = 0;
Expand Down
3 changes: 2 additions & 1 deletion runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -4298,6 +4298,7 @@ typedef struct J9MemoryManagerFunctions {

int ( *gcStartupHeapManagement)(struct J9JavaVM * vm) ;
void ( *gcShutdownHeapManagement)(struct J9JavaVM * vm) ;
void ( *jvmPhaseChange)(struct J9VMThread *currentThread, UDATA phase);
IDATA ( *initializeMutatorModelJava)(struct J9VMThread* vmThread) ;
void ( *cleanupMutatorModelJava)(struct J9VMThread* vmThread) ;
#if defined(J9VM_GC_FINALIZATION)
Expand Down
5 changes: 4 additions & 1 deletion runtime/vm/vmphases.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2013, 2014 IBM Corp. and others
* Copyright (c) 2013, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -63,6 +63,9 @@ void jvmPhaseChange(J9JavaVM* vm, UDATA phase) {
((J9UtServerInterface *)((UtInterface *)tempRasGbl->utIntf)->server)->StartupComplete(currentThread);
}
}
if (NULL != vm->memoryManagerFunctions) {
vm->memoryManagerFunctions->jvmPhaseChange(currentThread, phase);
}
if (NULL != vm->sharedClassConfig) {
vm->sharedClassConfig->jvmPhaseChange(currentThread, phase);
}
Expand Down