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

Implement initial RAM class persistence feature #20387

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ThanHenderson
Copy link
Contributor

@ThanHenderson ThanHenderson commented Oct 18, 2024

This PR revives RAM class persistence work. It currently rebases/implements: https://github.ibm.com/runtimes/openj9-stratum/pull/7 and https://github.ibm.com/runtimes/openj9-stratum/pull/25.

Current considerations/limitations:

  • No JIT support (i.e. -Xint required)
  • Incompatible with SCC (i.e. -Xshareclasses:none required)
  • ASLR must be turned off (I've been using echo 0 | sudo tee /proc/sys/kernel/randomize_va_space to turn this off)
  • Build must be configured with --enable-snapshots (requires extension repo patches)
  • No functionality to auto-detect whether a specified cache is compatible with the current invocation. (i.e. if you specify ramCache as the cache name for one program, then again for a different program, it will try to reuse the created cache rather than recognizing that it is incompatible and emitting a warning or deleting it and creating a new one).
  • Development only for JDK8, need to reassess to see what is required for later versions.

Example:

# Ensure ASLR is disabled (echo 2 to reset to default)
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

# Run the java program, creating a cache called "ramCache" that persists RAM class data
java -Xint -Xshareclasses:none -Xsnapshot=ramCache <java-program>

# Run the same java program, loading the persisted RAM class data from an image called "ramCache"
java -Xint -Xshareclasses:none -Xsnapshot=ramCache <java-program>

Signed-off-by: Nathan Henderson [email protected]

@ThanHenderson
Copy link
Contributor Author

ping @babsingh

@ThanHenderson ThanHenderson marked this pull request as ready for review October 23, 2024 20:50
@ThanHenderson
Copy link
Contributor Author

fyi @tajila @gacholio @hangshao0

runtime/vm/j9vm.tdf Outdated Show resolved Hide resolved
@@ -147,6 +147,8 @@ option(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES "Enables support for Project Va
option(J9VM_OPT_ROM_IMAGE_SUPPORT "Controls if the VM includes basic support for linked rom images")
option(J9VM_OPT_SHARED_CLASSES "Support for class sharing")

option(J9VM_OPT_SNAPSHOTS "Support for RAM class snapshot images")
Copy link
Contributor

Choose a reason for hiding this comment

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

The equivalent flag is missing for UMA builds.

Copy link
Contributor

Choose a reason for hiding this comment

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

UMA flag is added in j9.flags. Here is an example:

openj9/buildspecs/j9.flags

Lines 1727 to 1730 in 17ee5e7

<flag id="opt_fips">
<description>Add supports for FIPs</description>
<ifRemoved></ifRemoved>
</flag>

 <flag id="opt_snapshots"> 
 	<description>Enable support for RAM class snapshot images</description> 
 	<ifRemoved>Disable support for RAM class snapshot images</ifRemoved> 
 </flag> 

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the name is a little too generic: "snapshots" also apply to CRaC and CRIU.
How about "opt_ram_class_snapshots"? (The cmake name would change accordingly.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm fine with changing this to something else. But the generic-ness of snapshots is more amenable to expanding what data is held in a "snapshot" in the future.

Comment on lines 543 to 547
#========================================#
# RAM Persistence
#========================================#
snapshots:
extra_configure_options: '--enable-snapshots'
Copy link
Contributor

Choose a reason for hiding this comment

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

Without uses, this has no value, but it should be near other features.

@@ -196,6 +196,7 @@ set(J9VM_OPT_OPENJDK_METHODHANDLE OFF CACHE BOOL "")
set(J9VM_OPT_REFLECT ON CACHE BOOL "")
set(J9VM_OPT_ROM_IMAGE_SUPPORT ON CACHE BOOL "")
set(J9VM_OPT_SHARED_CLASSES ON CACHE BOOL "")
set(J9VM_OPT_SNAPSHOTS ON CACHE BOOL "")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the default should be "OFF" for now.

}


Copy link
Contributor

Choose a reason for hiding this comment

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

One blank line is sufficient.

Comment on lines 1608 to 1611
}
#if defined(J9VM_OPT_SNAPSHOTS)
else if (0 == strncmp(args->options[argCursor].optionString, VMOPT_XSNAPSHOT, strlen(VMOPT_XSNAPSHOT))) {
specialArgs->vmSnapshotFilePath = args->options[argCursor].optionString + strlen(VMOPT_XSNAPSHOT);
}
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest moving the closing brace after #endif:

#if defined(J9VM_OPT_SNAPSHOTS)
		} else if (0 == strncmp(args->options[argCursor].optionString, VMOPT_XSNAPSHOT, strlen(VMOPT_XSNAPSHOT))) {
			specialArgs->vmSnapshotFilePath = args->options[argCursor].optionString + strlen(VMOPT_XSNAPSHOT);
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
		}

@@ -26,6 +26,7 @@
#include "j9protos.h"
#include "j9jclnls.h"
#include "j9vmnls.h"
#include "vm_api.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this necessary?

Comment on lines 30 to 32
#if defined(J9VM_OPT_SNAPSHOTS)
#include "j9port_generated.h"
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
Copy link
Contributor

Choose a reason for hiding this comment

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

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Odd. I distinctly remember removing this in a previous revision. It must've slipped back in during a squash at some point. Thanks for catching that.

Comment on lines 139 to 164
} else {
}
#if defined(J9VM_OPT_SNAPSHOTS)
else if (J9_ARE_ANY_BITS_SET(segment->type, MEMORY_TYPE_ROM_CLASS)
&& IS_SNAPSHOTTING_ENABLED(javaVM)
) {
vmsnapshot_free_memory(segment->baseAddress);
}
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
else {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest relocating the braces:

#if defined(J9VM_OPT_SNAPSHOTS)
		} else if (J9_ARE_ANY_BITS_SET(segment->type, MEMORY_TYPE_ROM_CLASS)
			&& IS_SNAPSHOTTING_ENABLED(javaVM)
		) {
			vmsnapshot_free_memory(segment->baseAddress);
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
		} else {

/* TODO: In J9MemorySegmentList flags, add an option to signify allocation from the
* VMSnapshotImpl to replace this check (See @ref omr:j9nongenerated.h).
*/
if (IS_SNAPSHOTTING_ENABLED(javaVM) && ((javaVM->classMemorySegments == segmentList) || (javaVM->memorySegments == segmentList))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest folding this:

	if (IS_SNAPSHOTTING_ENABLED(javaVM)
		&& ((javaVM->classMemorySegments == segmentList) || (javaVM->memorySegments == segmentList))
	) {

Comment on lines 998 to 1014
TraceEntry=Trc_VM_snapshot_readSnapshotFromFile_Entry NoEnv Overhead=1 Level=1 Template="readSnapshotFromFile() Snapshot Heap = %p. File being read = %s"
TraceExit=Trc_VM_snapshot_readSnapshotFromFile_Exit NoEnv Overhead=1 Level=1 Template="readSnapshotFromFile() Snapshot read successful"
TraceEntry=Trc_VM_snapshot_writeSnapshotToFile_Entry NoEnv Overhead=1 Level=1 Template="writeSnapshotToFile() Snapshot Heap = %p. File being written to = %s"
TraceExit=Trc_VM_snapshot_writeSnapshotToFile_Exit NoEnv Overhead=1 Level=1 Template="writeSnapshotTofile() Snapshot write successful"
TraceEntry=Trc_VM_snapshot_subAllocateSnapshotMemory_Entry NoEnv Overhead=1 Level=1 Template="subAllocateMemory() Snapshot Header = %p. Byte amount = %d."
TraceExit=Trc_VM_snapshot_subAllocateSnapshotMemory_Exit NoEnv Overhead=1 Level=1 Template="subAllocateMemory() Memory allocated = %p."
TraceEvent=Trc_VM_snapshot_warmClassLoadFromSnapshot_ClassLoadHookFailed Overhead=1 Level=1 Template="loadWarmClassFromSnapshot() Warm class load hook failed class=%p, %s"
TraceEvent=Trc_VM_snapshot_loadWarmClassFromSnapshot_ClassInfo Overhead=1 Level=1 Template="loadWarmClassFromSnapshot() LoadClass clazz=%p, %s"
Copy link
Contributor

Choose a reason for hiding this comment

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

Not all of these new tracepoints are actually used; please remove the unused ones.

TraceExit=Trc_VM_snapshot_readSnapshotFromFile_Exit NoEnv Overhead=1 Level=1 Template="readSnapshotFromFile() Snapshot read successful"
TraceEntry=Trc_VM_snapshot_writeSnapshotToFile_Entry NoEnv Overhead=1 Level=1 Template="writeSnapshotToFile() Snapshot Heap = %p. File being written to = %s"
TraceExit=Trc_VM_snapshot_writeSnapshotToFile_Exit NoEnv Overhead=1 Level=1 Template="writeSnapshotTofile() Snapshot write successful"
TraceEntry=Trc_VM_snapshot_subAllocateSnapshotMemory_Entry NoEnv Overhead=1 Level=1 Template="subAllocateMemory() Snapshot Header = %p. Byte amount = %d."
Copy link
Contributor

Choose a reason for hiding this comment

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

%d should be %zu

Copy link
Contributor

@dmitripivkine dmitripivkine left a comment

Choose a reason for hiding this comment

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

Change in GC code looks ok. I hope for "restore" case buffers are cleared properly as well.

@ThanHenderson
Copy link
Contributor Author

@keithc-ca I've addressed your comments. And rebased to resolve the merge conflicts.

Comment on lines 1857 to 1860
<flag id="opt_snapshots">
<description>Enable support for RAM class snapshot images</description>
<ifRemoved>Disable support for RAM class snapshot images</ifRemoved>
</flag>
Copy link
Contributor

Choose a reason for hiding this comment

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

Please keep flags sorted alphabetically (this should follow opt_sidecar).

#if defined(J9VM_OPT_SNAPSHOTS)
/* Snapshot utility macros. */
Copy link
Contributor

Choose a reason for hiding this comment

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

Please swap these two lines (the comment relates to the #if ... #endif block.

/* Snapshot utility macros. */
#if defined(J9VM_OPT_SNAPSHOTS)


bool setupRestoreRun();
bool setupSnapshotRun();
bool setupSnapshotRunPostInitialize(void);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove void from all declarations of C++ methods with no parameters.

Comment on lines 277 to 280
#if defined(J9VM_OPT_SNAPSHOTS)
if (!IS_RESTORE_RUN(vm))
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that macros like IS_RESTORE_RUN are always defined, code like this can be simplified:

	if (!IS_RESTORE_RUN(vm)) {

See also near line 568, and similar uses in other files.

Comment on lines 17 to 20
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be:

 * [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

Comment on lines 17 to 20
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be

 * [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

Comment on lines 22 to 24
/*
* VMSnapshotImpl.hpp
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Please fix the indentation here and add a blank line:

/*
 * VMSnapshotImpl.hpp
 */

Comment on lines 134 to 135
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
#endif /* VMSNAPSHOTIMPLE_HPP_ */
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a blank line and fix the typo:

#endif /* defined(J9VM_OPT_SNAPSHOTS) */

#endif /* VMSNAPSHOTIMPL_HPP_ */

#include "j9cfg.h"

#if defined(J9VM_OPT_SNAPSHOTS)

Copy link
Contributor

Choose a reason for hiding this comment

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

This uses a number of types that won't be declared (not even a forward declaration); some includes are needed, at least:

#include "j9nongenerated.h"

Comment on lines 135 to 139
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
#endif /* snapshotfileformat_h */
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a blank line after line 135.

ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk23 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk21 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk17 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk11 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk11 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk17 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk21 that referenced this pull request Oct 31, 2024
ThanHenderson added a commit to ThanHenderson/openj9-openjdk-jdk23 that referenced this pull request Oct 31, 2024
With the motivation of reducing startup time, this patch implements
initial support for a mechanism to persist RAM classes to disk during
a training run and load the persisted snapshot on subsequent
identical production runs.

Towards this goal, this patch:
- Identifies an -Xsnapshot= command-line option that enables the
  snapshotting functionality and takes a string parameter that
  specifies a file path where the snapshot image is/will be.
- Adds SnapshotFileFormat.h file that specifies the format of the
  snapshot image that is persisted to disk. It describes the J9JavaVM
  members that are supported, namely immortal J9ClassLoader objects
  and the J9Class objects that they load.
- Adds the VMSnapshotImpl files that specify and implement the
  snapshotting API and include suballocators wherein the data to include
  within a snapshot is allocated.
- Ensures correct allocation/initialization of the immortal J9ClassLoaders
  and memory segments snapshotting and restoring.
- Enables taking a snapshot on VM shutdown, and restoring during startup.

Co-authored-by: Tobi Ajila <[email protected]>
Co-authored-by: Babneet Singh <[email protected]>
Co-authored-by: Nathan Henderson <[email protected]>
Signed-off-by: Nathan Henderson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants