diff --git a/runtime/nls/j9vm/j9vm.nls b/runtime/nls/j9vm/j9vm.nls index 8bde591732a..2ecb4601539 100644 --- a/runtime/nls/j9vm/j9vm.nls +++ b/runtime/nls/j9vm/j9vm.nls @@ -2151,4 +2151,27 @@ J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL=The JVM failed to proceed due to the wrong J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.explanation=An error occurred when the JVM attempted to perform upcall in the trivial downcall J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.system_action=The JVM will throw a IllegalThreadStateException. J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.user_response=Ensure the specified linker options for downcall are valid. + +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_FORKJOINPOOL_CNF=The JVM could not reset java.lang.VirtualThread.ForkJoinPool.parallelism due to java.util.concurrent.ForkJoinPool class not found +# START NON-TRANSLATABLE +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_FORKJOINPOOL_CNF.sample_input_1=1 +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_FORKJOINPOOL_CNF.explanation=CRIUSupport::checkpointJVM failed. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_FORKJOINPOOL_CNF.system_action=The JVM will throw a JVMRestoreException. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_FORKJOINPOOL_CNF.user_response=View CRIU documentation to determine how to resolve the exception. +# END NON-TRANSLATABLE + +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_DEFAULT_SCHEDULER_ADDRESS=The JVM could not reset java.lang.VirtualThread.ForkJoinPool.parallelism due to invalid DEFAULT_SCHEDULER address +# START NON-TRANSLATABLE +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_DEFAULT_SCHEDULER_ADDRESS.sample_input_1=1 +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_DEFAULT_SCHEDULER_ADDRESS.explanation=CRIUSupport::checkpointJVM failed. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_DEFAULT_SCHEDULER_ADDRESS.system_action=The JVM will throw a JVMRestoreException. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_DEFAULT_SCHEDULER_ADDRESS.user_response=View CRIU documentation to determine how to resolve the exception. +# END NON-TRANSLATABLE + +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_PARALLELISM_OFFSET=The JVM could not reset java.lang.VirtualThread.ForkJoinPool.parallelism due to invalid parallelism offset +# START NON-TRANSLATABLE +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_PARALLELISM_OFFSET.sample_input_1=1 +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_PARALLELISM_OFFSET.explanation=CRIUSupport::checkpointJVM failed. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_PARALLELISM_OFFSET.system_action=The JVM will throw a JVMRestoreException. +J9NLS_VM_CRIU_RESTORE_RESET_VIRTUALTHREAD_FORKJOINPOOL_PARALLELISM_INVALID_PARALLELISM_OFFSET.user_response=View CRIU documentation to determine how to resolve the exception. # END NON-TRANSLATABLE diff --git a/runtime/oti/VMHelpers.hpp b/runtime/oti/VMHelpers.hpp index 37102cf5316..913b3aca868 100644 --- a/runtime/oti/VMHelpers.hpp +++ b/runtime/oti/VMHelpers.hpp @@ -40,6 +40,7 @@ #include "j9vmconstantpool.h" #include "j9modifiers_api.h" #include "j9cp.h" +#include "vm_api.h" #include "ute.h" #include "AtomicSupport.hpp" #include "ObjectAllocationAPI.hpp" @@ -2072,6 +2073,100 @@ class VM_VMHelpers } } #endif /* JAVA_SPEC_VERSION >= 20 */ + + /** + * Get a static field object within a defining class. + * + * Current thread must have VM access. + * + * @param[in] currentThread the current J9VMThread + * @param[in] definingClassName the defining class name + * @param[in] fieldName the field name + * @param[in] signature the field signature + * + * @return the field object if successs, otherwise NULL + */ + static VMINLINE j9object_t + getStaticFieldObject(J9VMThread *currentThread, const char *definingClassName, const char *fieldName, const char *signature) + { + J9JavaVM *vm = currentThread->javaVM; + j9object_t fieldObject = NULL; + J9InternalVMFunctions const *vmFuncs = vm->internalVMFunctions; + J9Class *definingClass = vmFuncs->peekClassHashTable(currentThread, vm->systemClassLoader, (U_8 *)definingClassName, strlen(definingClassName)); + void *fieldAddress = vmFuncs->staticFieldAddress(currentThread, definingClass, (U_8*)fieldName, strlen(fieldName), (U_8*)signature, strlen(signature), NULL, NULL, 0, NULL); + if (NULL != fieldAddress) { + MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread); + fieldObject = objectAccessBarrier.inlineStaticReadObject(currentThread, definingClass, (j9object_t*)fieldAddress, FALSE); + } + return fieldObject; + } + + /** + * Find the offset of an instance field. + * + * @param[in] currentThread the current J9VMThread + * @param[in] instanceType the instance class + * @param[in] fieldName the field name + * @param[in] fieldSig the field signature + * + * @return the offset + */ + static VMINLINE IDATA + findinstanceFieldOffset(J9VMThread *currentThread, J9Class *instanceType, const char *fieldName, const char *fieldSig) + { + J9JavaVM *vm = currentThread->javaVM; + + IDATA offset = (UDATA)vm->internalVMFunctions->instanceFieldOffset( + currentThread, instanceType, + (U_8 *)fieldName, strlen(fieldName), + (U_8 *)fieldSig, strlen(fieldSig), + NULL, NULL, 0); + + if (-1 != offset) { + offset += J9VMTHREAD_OBJECT_HEADER_SIZE(currentThread); + } + + return offset; + } + +#if defined(J9VM_OPT_CRIU_SUPPORT) + /** + * Reset java.util.concurrent.ForkJoinPool.parallelism with a value supplied. + * + * Current thread must have VM access. + * + * @param[in] currentThread the current J9VMThread + * @param[in] instanceObject a java.util.concurrent.ForkJoinPool instance object + * @param[in] value the I_32 value to be set into the parallelism field + * + * @return true if the value has been set into the field within the instance object, false if not + */ + static VMINLINE bool + resetJUCForkJoinPoolParallelism(J9VMThread *currentThread, j9object_t instanceObject, I_32 value) + { + bool result = false; + J9JavaVM *vm = currentThread->javaVM; + IDATA fieldOffset = vm->checkpointState.jucForkJoinPoolParallelismOffset; + + if (0 == fieldOffset) { +#define JUC_FORKJOINPOOL "java/util/concurrent/ForkJoinPool" + J9Class *definingClass = vm->internalVMFunctions->peekClassHashTable(currentThread, vm->systemClassLoader, (U_8 *)JUC_FORKJOINPOOL, LITERAL_STRLEN(JUC_FORKJOINPOOL)); +#undef JUC_FORKJOINPOOL + if (NULL != definingClass) { + fieldOffset = findinstanceFieldOffset(currentThread, definingClass, "parallelism", "I"); + } else { + fieldOffset = -1; + } + } + if (-1 != fieldOffset) { + MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread); + objectAccessBarrier.inlineMixedObjectStoreI32(currentThread, instanceObject, fieldOffset, value, false); + vm->checkpointState.jucForkJoinPoolParallelismOffset = fieldOffset; + result = true; + } + return result; + } +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ }; #endif /* VMHELPERS_HPP_ */ diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index b0fd3f1b4f5..d986deec4c1 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4202,6 +4202,9 @@ typedef struct J9DelayedLockingOpertionsRecord { typedef struct J9CRIUCheckpointState { U_32 flags; +#if JAVA_SPEC_VERSION >= 20 + UDATA checkpointCPUCount; +#endif /* JAVA_SPEC_VERSION >= 20 */ struct J9DelayedLockingOpertionsRecord *delayedLockingOperationsRoot; struct J9Pool *hookRecords; struct J9Pool *classIterationRestoreHookRecords; @@ -4238,6 +4241,7 @@ typedef struct J9CRIUCheckpointState { UDATA libCRIUHandle; struct J9VMInitArgs *restoreArgsList; char *restoreArgsChars; + IDATA jucForkJoinPoolParallelismOffset; } J9CRIUCheckpointState; #endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ diff --git a/runtime/vm/CRIUHelpers.cpp b/runtime/vm/CRIUHelpers.cpp index d9bab03ca37..7346b9ce946 100644 --- a/runtime/vm/CRIUHelpers.cpp +++ b/runtime/vm/CRIUHelpers.cpp @@ -46,7 +46,6 @@ J9_DECLARE_CONSTANT_UTF8(j9InternalCheckpointHookAPI_name, "org/eclipse/openj9/c static void addInternalJVMCheckpointHook(J9VMThread *currentThread, BOOLEAN isRestore, J9Class *instanceType, BOOLEAN includeSubClass, hookFunc hookFunc); static void cleanupCriuHooks(J9VMThread *currentThread); static BOOLEAN fillinHookRecords(J9VMThread *currentThread, j9object_t object); -static IDATA findinstanceFieldOffsetHelper(J9VMThread *currentThread, J9Class *instanceType, const char *fieldName, const char *fieldSig); static void initializeCriuHooks(J9VMThread *currentThread); static BOOLEAN juRandomReseed(J9VMThread *currentThread, void *userData, const char **nlsMsgFormat); static BOOLEAN criuRestoreInitializeTrace(J9VMThread *currentThread, void *userData, const char **nlsMsgFormat); @@ -162,22 +161,6 @@ addInternalJVMCheckpointHook(J9VMThread *currentThread, BOOLEAN isRestore, J9Cla } } -static IDATA -findinstanceFieldOffsetHelper(J9VMThread *currentThread, J9Class *instanceType, const char *fieldName, const char *fieldSig) -{ - IDATA offset = (UDATA)instanceFieldOffset( - currentThread, instanceType, - (U_8*)fieldName, strlen(fieldName), - (U_8*)fieldSig, strlen(fieldSig), - NULL, NULL, 0); - - if (-1 != offset) { - offset += J9VMTHREAD_OBJECT_HEADER_SIZE(currentThread); - } - - return offset; -} - /** * An internal JVM checkpoint hook is to re-seed java.util.Random.seed.value. * @@ -197,13 +180,13 @@ juRandomReseed(J9VMThread *currentThread, void *userData, const char **nlsMsgFor PORT_ACCESS_FROM_VMC(currentThread); /* Assuming this hook record is to re-seed java.util.Random.seed.value. */ - IDATA seedOffset = findinstanceFieldOffsetHelper(currentThread, hookRecord->instanceType, "seed", "Ljava/util/concurrent/atomic/AtomicLong;"); + IDATA seedOffset = VM_VMHelpers::findinstanceFieldOffset(currentThread, hookRecord->instanceType, "seed", "Ljava/util/concurrent/atomic/AtomicLong;"); if (-1 != seedOffset) { #define JUCA_ATOMICLONG "java/util/concurrent/atomic/AtomicLong" - J9Class *jucaAtomicLongClass = hashClassTableAt(vm->systemClassLoader, (U_8 *)JUCA_ATOMICLONG, LITERAL_STRLEN(JUCA_ATOMICLONG)); + J9Class *jucaAtomicLongClass = peekClassHashTable(currentThread, vm->systemClassLoader, (U_8 *)JUCA_ATOMICLONG, LITERAL_STRLEN(JUCA_ATOMICLONG)); #undef JUCA_ATOMICLONG if (NULL != jucaAtomicLongClass) { - IDATA valueOffset = findinstanceFieldOffsetHelper(currentThread, jucaAtomicLongClass, "value", "J"); + IDATA valueOffset = VM_VMHelpers::findinstanceFieldOffset(currentThread, jucaAtomicLongClass, "value", "J"); if (-1 != valueOffset) { PORT_ACCESS_FROM_JAVAVM(vm); pool_state walkState = {0}; @@ -456,6 +439,22 @@ initializeCriuHooks(J9VMThread *currentThread) } } +#if JAVA_SPEC_VERSION >= 20 + { + J9VMSystemProperty *vtParallelism = NULL; + PORT_ACCESS_FROM_VMC(currentThread); + if (J9SYSPROP_ERROR_NONE != getSystemProperty(vm, "jdk.virtualThreadScheduler.parallelism", &vtParallelism)) { + /* This system property only affects j.l.VirtualThread.ForkJoinPool.parallelism at VM startup. */ + UDATA cpuCount = j9sysinfo_get_number_CPUs_by_type(J9PORT_CPU_TARGET); + if (cpuCount < 1) { + cpuCount = 1; + } + vm->checkpointState.checkpointCPUCount = cpuCount; + Trc_VM_criu_initializeCriuHooks_checkpointCPUCount(currentThread, cpuCount); + } + } +#endif /* JAVA_SPEC_VERSION >= 20 */ + { /* Add restore hook to re-seed java.uti.Random.seed.value */ #define JAVA_UTIL_RANDOM "java/util/Random" @@ -463,6 +462,8 @@ initializeCriuHooks(J9VMThread *currentThread) #undef JAVA_UTIL_RANDOM if (NULL != juRandomClass) { addInternalJVMCheckpointHook(currentThread, TRUE, juRandomClass, FALSE, juRandomReseed); + } else { + Trc_VM_criu_initializeCriuHooks_Random_CNF(currentThread); } addInternalJVMCheckpointHook(currentThread, TRUE, NULL, FALSE, criuRestoreInitializeTrace); addInternalJVMCheckpointHook(currentThread, TRUE, NULL, FALSE, criuRestoreInitializeXrs); @@ -495,8 +496,8 @@ fillinHookRecords(J9VMThread *currentThread, j9object_t object) BOOLEAN result = TRUE; J9InternalHookRecord *hookRecord = (J9InternalHookRecord*)pool_startDo(hookRecords, &walkState); + J9Class *clazz = J9OBJECT_CLAZZ_VM(vm, object); while (NULL != hookRecord) { - J9Class *clazz = J9OBJECT_CLAZZ_VM(vm, object); if ((clazz == hookRecord->instanceType) || (hookRecord->includeSubClass && isSameOrSuperClassOf(hookRecord->instanceType, clazz)) ) { @@ -602,6 +603,29 @@ runInternalJVMRestoreHooks(J9VMThread *currentThread, const char **nlsMsgFormat) } } +#if JAVA_SPEC_VERSION >= 20 + if (0 != vm->checkpointState.checkpointCPUCount) { + /* Only reset j.l.VirtualThread.ForkJoinPool.parallelism if jdk.virtualThreadScheduler.parallelism is not set. */ + PORT_ACCESS_FROM_VMC(currentThread); + UDATA cpuCount = j9sysinfo_get_number_CPUs_by_type(J9PORT_CPU_TARGET); + if (cpuCount < 1) { + /* This matches ForkJoinPool default constructor with Runtime.getRuntime().availableProcessors(). */ + cpuCount = 1; + } + if (cpuCount != vm->checkpointState.checkpointCPUCount) { + j9object_t fjpObject = VM_VMHelpers::getStaticFieldObject(currentThread, "java/lang/VirtualThread", "DEFAULT_SCHEDULER", "Ljava/util/concurrent/ForkJoinPool;"); + if (NULL != fjpObject) { + result = VM_VMHelpers::resetJUCForkJoinPoolParallelism(currentThread, fjpObject, cpuCount); + Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_reset_parallelism(currentThread, fjpObject, cpuCount); + } else { + Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_DEFAULT_SCHEDULER_NULL(currentThread); + } + } else { + Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_same_cpucount(currentThread, cpuCount); + } + } +#endif /* JAVA_SPEC_VERSION >= 20 */ + /* Cleanup at restore. */ cleanupCriuHooks(currentThread); Trc_VM_criu_runRestoreHooks_Exit(currentThread); diff --git a/runtime/vm/j9vm.tdf b/runtime/vm/j9vm.tdf index bb4c849ab1c..ca914d9401c 100644 --- a/runtime/vm/j9vm.tdf +++ b/runtime/vm/j9vm.tdf @@ -930,3 +930,9 @@ TraceExit=Trc_VM_criu_initHooks_Exit Overhead=1 Level=5 Template="initializeCriu TraceException=Trc_VM_criu_setSingleThreadModeJVMCRIUException_triggerOneOffJavaDump Overhead=1 Level=1 Template="setCRIUSingleThreadModeJVMCRIUException triggerOneOffDump() returns %d" TraceException=Trc_VM_checkVisibility_Failed Overhead=1 Level=1 Template="checkVisibility from %p (%.*s) to %p (%.*s) modifiers=%zx lookupOptions=%zx failed" + +TraceEvent=Trc_VM_criu_initializeCriuHooks_checkpointCPUCount Overhead=1 Level=3 Template="initializeCriuHooks() checkpoint CPU count (%zu)" +TraceEvent=Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_same_cpucount Overhead=1 Level=5 Template="Reset j.l.VirtualThread.ForkJoinPool.parallelism: same cpu count (%zu) between C/R" +TraceEvent=Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_reset_parallelism Overhead=1 Level=5 Template="Reset j.l.VirtualThread.ForkJoinPool.parallelism: fjpObject(0x%p) parallelism(%zu) after restore" +TraceException=Trc_VM_criu_initializeCriuHooks_Random_CNF Overhead=1 Level=3 Template="initializeCriuHooks() j.u.Random class not found" +TraceException=Trc_VM_criu_jlVirtualThreadForkJoinPoolResetParallelism_DEFAULT_SCHEDULER_NULL Overhead=1 Level=3 Template="Reset j.l.VirtualThread.ForkJoinPool.parallelism: DEFAULT_SCHEDULER is NULL" diff --git a/test/functional/cmdLineTests/criu/build.xml b/test/functional/cmdLineTests/criu/build.xml index d5850f52ea6..169503294c3 100644 --- a/test/functional/cmdLineTests/criu/build.xml +++ b/test/functional/cmdLineTests/criu/build.xml @@ -41,26 +41,41 @@ - - ===addExports: ${addExports} Ant version is ${ant.version} ============COMPILER SETTINGS============ ===fork: yes ===executable: ${compiler.javac} ===debug: on ===destdir: ${DEST} + + + + + + + + + + + + - + - + + - + + ===addExports: ${addExports} + ===enablePreview: ${enablePreview} + + diff --git a/test/functional/cmdLineTests/criu/criu_nonPortableJDK20Up.xml b/test/functional/cmdLineTests/criu/criu_nonPortableJDK20Up.xml new file mode 100644 index 00000000000..60118050a8d --- /dev/null +++ b/test/functional/cmdLineTests/criu/criu_nonPortableJDK20Up.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$ $TRACE_OPTION$ $ENABLE_PREVIEW$ $ADD_OPENS$" $MAINCLASS_TESTMACHINERESOURCECHANGE$ testVirtualThreadForkJoinPoolParallelism 1 + Killed + Pre-checkpoint + Post-checkpoint + PASSED: testVirtualThreadForkJoinPoolParallelism() + FAILED: testVirtualThreadForkJoinPoolParallelism() + CRIU is not enabled + Operation not permitted + + Thread pid mismatch + do not match expected + Unable to create a thread: + + Could not dump the JVM processes, err=-70 + + + + bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$ $TRACE_OPTION$ $ENABLE_PREVIEW$ $ADD_OPENS$ -Djdk.virtualThreadScheduler.parallelism=3" $MAINCLASS_TESTMACHINERESOURCECHANGE$ testVirtualThreadForkJoinPoolParallelism 1 + Killed + Pre-checkpoint + Post-checkpoint + PASSED: testVirtualThreadForkJoinPoolParallelism() + FAILED: testVirtualThreadForkJoinPoolParallelism() + CRIU is not enabled + Operation not permitted + + Thread pid mismatch + do not match expected + Unable to create a thread: + + Could not dump the JVM processes, err=-70 + + + + bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$ $TRACE_OPTION$ $ENABLE_PREVIEW$ $ADD_OPENS$ -Djdk.virtualThreadScheduler.parallelism=7" $MAINCLASS_TESTMACHINERESOURCECHANGE$ testVirtualThreadForkJoinPoolParallelism 1 + Killed + Pre-checkpoint + Post-checkpoint + PASSED: testVirtualThreadForkJoinPoolParallelism() + FAILED: testVirtualThreadForkJoinPoolParallelism() + CRIU is not enabled + Operation not permitted + + Thread pid mismatch + do not match expected + Unable to create a thread: + + Could not dump the JVM processes, err=-70 + + + + bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$ $TRACE_OPTION$ $ENABLE_PREVIEW$ $ADD_OPENS$" $MAINCLASS_TESTMACHINERESOURCECHANGE$ testVirtualThreadForkJoinPoolParallelismWithOptionsFileV1 1 + Killed + Pre-checkpoint + Post-checkpoint + PASSED: testVirtualThreadForkJoinPoolParallelism() + FAILED: testVirtualThreadForkJoinPoolParallelism() + CRIU is not enabled + Operation not permitted + + Thread pid mismatch + do not match expected + Unable to create a thread: + + Could not dump the JVM processes, err=-70 + + + + bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$ $TRACE_OPTION$ $ENABLE_PREVIEW$ $ADD_OPENS$" $MAINCLASS_TESTMACHINERESOURCECHANGE$ testVirtualThreadForkJoinPoolParallelismWithOptionsFileV2 1 + Killed + Pre-checkpoint + Post-checkpoint + PASSED: testVirtualThreadForkJoinPoolParallelism() + FAILED: testVirtualThreadForkJoinPoolParallelism() + CRIU is not enabled + Operation not permitted + + Thread pid mismatch + do not match expected + Unable to create a thread: + + Could not dump the JVM processes, err=-70 + + diff --git a/test/functional/cmdLineTests/criu/playlist.xml b/test/functional/cmdLineTests/criu/playlist.xml index cdade80263a..8dbb0151f79 100644 --- a/test/functional/cmdLineTests/criu/playlist.xml +++ b/test/functional/cmdLineTests/criu/playlist.xml @@ -377,6 +377,37 @@ 11+ + + cmdLineTester_criu_nonPortableRestoreJDK20Up + + -Xjit -XX:+CRIURestoreNonPortableMode + -Xint -XX:+CRIURestoreNonPortableMode + -Xjit:count=0 -XX:+CRIURestoreNonPortableMode + + + $(JAVA_COMMAND) $(CMDLINETESTER_JVM_OPTIONS) -Xdump \ + -DSCRIPPATH=$(TEST_RESROOT)$(D)criuScript.sh -DTEST_RESROOT=$(TEST_RESROOT) \ + -DJAVA_COMMAND=$(JAVA_COMMAND) -DJVM_OPTIONS=$(Q)$(JVM_OPTIONS)$(Q) \ + -jar $(CMDLINETESTER_JAR) -config $(Q)$(TEST_RESROOT)$(D)criu_nonPortableJDK20Up.xml$(Q) \ + -explainExcludes -xids all,$(PLATFORM),$(VARIATION) -nonZeroExitWhenError; \ + $(TEST_STATUS) + + + CRIU:required + + + sanity + + + functional + + + openj9 + + + 20+ + + cmdLineTester_criu_security diff --git a/test/functional/cmdLineTests/criu/src/org/openj9/criu/TestMachineResourceChange.java b/test/functional/cmdLineTests/criu/src/org/openj9/criu/TestMachineResourceChange.java new file mode 100644 index 00000000000..ff92bfc9ba0 --- /dev/null +++ b/test/functional/cmdLineTests/criu/src/org/openj9/criu/TestMachineResourceChange.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright IBM Corp. and others 2023 + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] https://openjdk.org/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 + *******************************************************************************/ +package org.openj9.criu; + +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.concurrent.ForkJoinPool; + +import org.eclipse.openj9.criu.CRIUSupport; + +public class TestMachineResourceChange { + public static void main(String[] args) throws InterruptedException { + if (args.length == 0) { + throw new RuntimeException("Test name required"); + } else { + String testName = args[0]; + new TestMachineResourceChange().test(testName); + } + } + + private void testVirtualThreadForkJoinPoolParallelism(boolean isCheckpoint, boolean isRestoreSysProp) + throws InterruptedException { + boolean pass = false; + + System.out.println("testVirtualThreadForkJoinPoolParallelism() isCheckpoint = " + isCheckpoint + + ", isRestoreSysProp = " + isRestoreSysProp); + Thread.ofVirtual() + .start(() -> System.out + .println("This is a Virtual Thread after CRIU " + (isCheckpoint ? "checkpoint" : "restore"))) + .join(); + try { + Class vtClz = Class.forName("java.lang.VirtualThread"); + System.out.println("j.l.VirtualThread : " + vtClz); + Field fieldDefaultScheduler = vtClz.getDeclaredField("DEFAULT_SCHEDULER"); + fieldDefaultScheduler.setAccessible(true); + System.out.println("fieldDefaultScheduler = " + fieldDefaultScheduler); + ForkJoinPool fjp = (ForkJoinPool) fieldDefaultScheduler.get(null); + System.out.println("j.u.c.ForkJoinPool : " + fjp); + Field fieldParallelism = ForkJoinPool.class.getDeclaredField("parallelism"); + fieldParallelism.setAccessible(true); + int parallelism = (int) fieldParallelism.get(fjp); + System.out.println("j.l.VirtualThread.ForkJoinPool.parallelism = " + parallelism); + + String parallelismValue = System.getProperty("jdk.virtualThreadScheduler.parallelism"); + Integer parallelismInteger = Integer.getInteger("jdk.virtualThreadScheduler.parallelism"); + if ((parallelismInteger != null) && !isRestoreSysProp) { + // This system property only affects j.l.VirtualThread.ForkJoinPool.parallelism + // at VM startup. + int parallelismSysProp = parallelismInteger.intValue(); + if (parallelismSysProp == parallelism) { + System.out.println( + "PASSED: testVirtualThreadForkJoinPoolParallelism() j.l.VirtualThread.ForkJoinPool.parallelism retrieved equals system property jdk.virtualThreadScheduler.parallelism set - " + + parallelism); + } else { + System.out.println( + "FAILED: testVirtualThreadForkJoinPoolParallelism() j.l.VirtualThread.ForkJoinPool.parallelism retrieved is " + + parallelism + ", but system property jdk.virtualThreadScheduler.parallelism is " + + parallelismSysProp); + } + } else { + int cpuCount = Runtime.getRuntime().availableProcessors(); + if (cpuCount == parallelism) { + System.out.println( + "PASSED: testVirtualThreadForkJoinPoolParallelism() j.l.VirtualThread.ForkJoinPool.parallelism retrieved equals Runtime.getRuntime().availableProcessors() - " + + parallelism); + } else { + System.out.println( + "FAILED: testVirtualThreadForkJoinPoolParallelism() j.l.VirtualThread.ForkJoinPool.parallelism retrieved is " + + parallelism + ", but Runtime.getRuntime().availableProcessors() is " + cpuCount); + } + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println( + "FAILED: testVirtualThreadForkJoinPoolParallelism() throws an exception: " + e.getMessage()); + } + } + + private void test(String testName) throws InterruptedException { + CRIUSupport criu = CRIUTestUtils.prepareCheckPointJVM(CRIUTestUtils.imagePath); + if (criu == null) { + // prepareCheckPointJVM() has an error message "CRIU is not enabled". + return; + } + CRIUTestUtils.showThreadCurrentTime("Before starting " + testName); + switch (testName) { + case "testVirtualThreadForkJoinPoolParallelism": + testVirtualThreadForkJoinPoolParallelism(true, false); + break; + case "testVirtualThreadForkJoinPoolParallelismWithOptionsFileV1": { + String optionsContents = "-Djdk.virtualThreadScheduler.parallelism=5"; + Path optionsFilePath = CRIUTestUtils.createOptionsFile("options", optionsContents); + criu.registerRestoreOptionsFile(optionsFilePath); + testVirtualThreadForkJoinPoolParallelism(true, true); + } + break; + case "testVirtualThreadForkJoinPoolParallelismWithOptionsFileV2": { + String optionsContents = "-Djdk.virtualThreadScheduler.parallelism=9"; + Path optionsFilePath = CRIUTestUtils.createOptionsFile("options", optionsContents); + criu.registerRestoreOptionsFile(optionsFilePath); + testVirtualThreadForkJoinPoolParallelism(true, true); + } + break; + default: + throw new RuntimeException("Unrecognized test name: " + testName); + } + + System.out.println("Pre-checkpoint"); + CRIUTestUtils.checkPointJVMNoSetup(criu, CRIUTestUtils.imagePath, false); + System.out.println("Post-checkpoint"); + + switch (testName) { + case "testVirtualThreadForkJoinPoolParallelism": + testVirtualThreadForkJoinPoolParallelism(false, false); + break; + case "testVirtualThreadForkJoinPoolParallelismWithOptionsFileV1": + case "testVirtualThreadForkJoinPoolParallelismWithOptionsFileV2": + testVirtualThreadForkJoinPoolParallelism(false, true); + break; + default: + } + + CRIUTestUtils.showThreadCurrentTime("End " + testName); + } +}