Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8303229: JFR: Preserve disk repository after exit
Reviewed-by: dholmes, mgronlun
  • Loading branch information
egahlin committed Apr 3, 2023
1 parent ecec611 commit 336a23e
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 45 deletions.
90 changes: 50 additions & 40 deletions src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
Expand Up @@ -367,14 +367,15 @@ GrowableArray<const char*>* JfrDCmd::argument_name_array() const {
JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
bool heap) : DCmdWithParser(output, heap),
_repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
_dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
_stack_depth("stackdepth", "Stack Depth", "JULONG", false, "64"),
_dump_path("dumppath", "Path to dump, e.g. \\\"My Dump path\\\"", "STRING", false, NULL),
_stack_depth("stackdepth", "Stack depth", "JULONG", false, "64"),
_global_buffer_count("globalbuffercount", "Number of global buffers,", "JULONG", false, "20"),
_global_buffer_size("globalbuffersize", "Size of a global buffers,", "MEMORY SIZE", false, "512k"),
_thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "MEMORY SIZE", false, "8k"),
_memory_size("memorysize", "Overall memory size, ", "MEMORY SIZE", false, "10m"),
_max_chunk_size("maxchunksize", "Size of an individual disk chunk", "MEMORY SIZE", false, "12m"),
_sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true"),
_sample_threads("samplethreads", "Activate thread sampling", "BOOLEAN", false, "true"),
_preserve_repository("preserve-repository", "Preserve the disk repository after JVM exit", "BOOLEAN", false, "false"),
_verbose(true) {
_dcmdparser.add_dcmd_option(&_repository_path);
_dcmdparser.add_dcmd_option(&_dump_path);
Expand All @@ -385,56 +386,60 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out
_dcmdparser.add_dcmd_option(&_memory_size);
_dcmdparser.add_dcmd_option(&_max_chunk_size);
_dcmdparser.add_dcmd_option(&_sample_threads);
_dcmdparser.add_dcmd_option(&_preserve_repository);
};

void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const {
outputStream* out = output();
// 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890
out->print_cr("Options:");
out->print_cr("");
out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy");
out->print_cr(" option: change the memorysize parameter to alter the number of");
out->print_cr(" global buffers. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)");
out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy");
out->print_cr(" option: change the memorysize parameter to alter the number of");
out->print_cr(" global buffers. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)");
out->print_cr("");
out->print_cr(" globalbuffersize (Optional) Size of the global buffers, in bytes. This option is a");
out->print_cr(" legacy option: change the memorysize parameter to alter the size");
out->print_cr(" of the global buffers. This value cannot be changed once JFR has");
out->print_cr(" been initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)");
out->print_cr(" globalbuffersize (Optional) Size of the global buffers, in bytes. This option is a");
out->print_cr(" legacy option: change the memorysize parameter to alter the size");
out->print_cr(" of the global buffers. This value cannot be changed once JFR has");
out->print_cr(" been initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)");
out->print_cr("");
out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if");
out->print_cr(" one of the following suffixes is not used: 'm' or 'M' for");
out->print_cr(" megabytes OR 'g' or 'G' for gigabytes. This value cannot be");
out->print_cr(" changed once JFR has been initialized. (STRING, 12M)");
out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if");
out->print_cr(" one of the following suffixes is not used: 'm' or 'M' for");
out->print_cr(" megabytes OR 'g' or 'G' for gigabytes. This value cannot be");
out->print_cr(" changed once JFR has been initialized. (STRING, 12M)");
out->print_cr("");
out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following");
out->print_cr(" suffixes is not used: 'm' or 'M' for megabytes OR 'g' or 'G' for");
out->print_cr(" gigabytes. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (STRING, 10M)");
out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following");
out->print_cr(" suffixes is not used: 'm' or 'M' for megabytes OR 'g' or 'G' for");
out->print_cr(" gigabytes. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (STRING, 10M)");
out->print_cr("");
out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until");
out->print_cr(" they are written to a permanent file. (STRING, The default");
out->print_cr(" location is the temporary directory for the operating system. On");
out->print_cr(" Linux operating systems, the temporary directory is /tmp. On");
out->print_cr(" Windows, the temporary directory is specified by the TMP");
out->print_cr(" environment variable)");
out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until");
out->print_cr(" they are written to a permanent file. (STRING, The default");
out->print_cr(" location is the temporary directory for the operating system. On");
out->print_cr(" Linux operating systems, the temporary directory is /tmp. On");
out->print_cr(" Windows, the temporary directory is specified by the TMP");
out->print_cr(" environment variable)");
out->print_cr("");
out->print_cr(" dumppath (Optional) Path to the location where a recording file is written");
out->print_cr(" in case the VM runs into a critical error, such as a system");
out->print_cr(" crash. (STRING, The default location is the current directory)");
out->print_cr(" dumppath (Optional) Path to the location where a recording file is written");
out->print_cr(" in case the VM runs into a critical error, such as a system");
out->print_cr(" crash. (STRING, The default location is the current directory)");
out->print_cr("");
out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value");
out->print_cr(" greater than the default of 64 may cause a performance");
out->print_cr(" degradation. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (LONG, 64)");
out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value");
out->print_cr(" greater than the default of 64 may cause a performance");
out->print_cr(" degradation. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (LONG, 64)");
out->print_cr("");
out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of");
out->print_cr(" the following suffixes is not used: 'k' or 'K' for kilobytes or");
out->print_cr(" 'm' or 'M' for megabytes. Overriding this parameter could reduce");
out->print_cr(" performance and is not recommended. This value cannot be changed");
out->print_cr(" once JFR has been initialized. (STRING, 8k)");
out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of");
out->print_cr(" the following suffixes is not used: 'k' or 'K' for kilobytes or");
out->print_cr(" 'm' or 'M' for megabytes. Overriding this parameter could reduce");
out->print_cr(" performance and is not recommended. This value cannot be changed");
out->print_cr(" once JFR has been initialized. (STRING, 8k)");
out->print_cr("");
out->print_cr(" preserve-repository (Optional) Preserve files stored in the disk repository after the");
out->print_cr(" Java Virtual Machine has exited. (BOOLEAN, false)");
out->print_cr("");
out->print_cr("Options must be specified using the <key> or <key>=<value> syntax.");
out->print_cr("");
Expand Down Expand Up @@ -480,6 +485,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
jobject thread_buffer_size = NULL;
jobject max_chunk_size = NULL;
jobject memory_size = NULL;
jobject preserve_repository = nullptr;

if (!JfrRecorder::is_created()) {
if (_stack_depth.is_set()) {
Expand Down Expand Up @@ -510,12 +516,15 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
}
}
}
if (_preserve_repository.is_set()) {
preserve_repository = JfrJavaSupport::new_java_lang_Boolean(_preserve_repository.value(), CHECK);
}

static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
static const char method[] = "execute";
static const char signature[] = "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
"Ljava/lang/Long;)[Ljava/lang/String;";
"Ljava/lang/Long;Ljava/lang/Boolean;)[Ljava/lang/String;";

JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
execute_args.set_receiver(h_dcmd_instance);
Expand All @@ -530,6 +539,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
execute_args.push_jobject(thread_buffer_size);
execute_args.push_jobject(memory_size);
execute_args.push_jobject(max_chunk_size);
execute_args.push_jobject(preserve_repository);

JfrJavaSupport::call_virtual(&execute_args, THREAD);
handle_dcmd_result(output(), result.get_oop(), source, THREAD);
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/jfr/dcmd/jfrDcmds.hpp
Expand Up @@ -157,6 +157,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
DCmdArgument<MemorySizeArgument> _memory_size;
DCmdArgument<MemorySizeArgument> _max_chunk_size;
DCmdArgument<bool> _sample_threads;
DCmdArgument<bool> _preserve_repository;
bool _verbose;

public:
Expand All @@ -177,7 +178,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
return p;
}
static int num_arguments() { return 9; }
static int num_arguments() { return 10; }
virtual void execute(DCmdSource source, TRAPS);
virtual void print_help(const char* name) const;
};
Expand Down
12 changes: 12 additions & 0 deletions src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp
Expand Up @@ -165,6 +165,7 @@ const char* const default_sample_threads = "true";
const char* const default_stack_depth = "64";
const char* const default_retransform = "true";
const char* const default_old_object_queue_size = "256";
const char* const default_preserve_repository = "false";
DEBUG_ONLY(const char* const default_sample_protection = "false";)

// statics
Expand Down Expand Up @@ -254,6 +255,13 @@ static DCmdArgument<bool> _dcmd_retransform(
true,
default_retransform);

static DCmdArgument<bool> _dcmd_preserve_repository(
"preserve-repository",
"Preserve disk repository after JVM exit",
"BOOLEAN",
false,
default_preserve_repository);

static DCmdParser _parser;

static void register_parser_options() {
Expand All @@ -268,6 +276,7 @@ static void register_parser_options() {
_parser.add_dcmd_option(&_dcmd_sample_threads);
_parser.add_dcmd_option(&_dcmd_retransform);
_parser.add_dcmd_option(&_dcmd_old_object_queue_size);
_parser.add_dcmd_option(&_dcmd_preserve_repository);
DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
}

Expand Down Expand Up @@ -379,6 +388,9 @@ bool JfrOptionSet::configure(TRAPS) {
configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
configure._sample_threads.set_value(_dcmd_sample_threads.value());

configure._preserve_repository.set_is_set(_dcmd_preserve_repository.is_set());
configure._preserve_repository.set_value(_dcmd_preserve_repository.value());

configure.set_verbose(false);
configure.execute(DCmd_Source_Internal, THREAD);

Expand Down
6 changes: 6 additions & 0 deletions src/java.base/share/man/java.1
Expand Up @@ -1337,6 +1337,12 @@ buffers.
Maximum number of old objects to track.
By default, the number of objects is set to 256.
.TP
\f[V]preserve-repository=\f[R]{\f[V]true\f[R]|\f[V]false\f[R]}
Specifies whether files stored in the disk repository should be kept
after the JVM has exited.
If false, files are deleted.
By default, this parameter is disabled.
.TP
\f[V]repository=\f[R]\f[I]path\f[R]
Specifies the repository (a directory) for temporary disk storage.
By default, the system\[aq]s temporary directory is used.
Expand Down
6 changes: 6 additions & 0 deletions src/jdk.jcmd/share/man/jcmd.1
Expand Up @@ -402,6 +402,12 @@ On Linux operating systems, the temporary directory is \f[V]/tmp\f[R].
On Windwows, the temporary directory is specified by the \f[V]TMP\f[R]
environment variable.)
.IP \[bu] 2
\f[V]preserve-repository=\f[R]{\f[V]true\f[R]|\f[V]false\f[R]} :
Specifies whether files stored in the disk repository should be kept
after the JVM has exited.
If false, files are deleted.
By default, this parameter is disabled.
.IP \[bu] 2
\f[V]stackdepth\f[R]: (Optional) Stack depth for stack traces.
Setting this value greater than the default of 64 may cause a
performance degradation.
Expand Down
11 changes: 11 additions & 0 deletions src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java
Expand Up @@ -52,13 +52,15 @@ public final class Options {
private static final int DEFAULT_STACK_DEPTH = 64;
private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024;
private static final SafePath DEFAULT_DUMP_PATH = null;
private static final boolean DEFAULT_PRESERVE_REPOSITORY = false;

private static long memorySize;
private static long globalBufferSize;
private static long globalBufferCount;
private static long threadBufferSize;
private static int stackDepth;
private static long maxChunkSize;
private static boolean preserveRepository;

static {
final long pageSize = Unsafe.getUnsafe().pageSize();
Expand Down Expand Up @@ -138,6 +140,14 @@ public static synchronized int getStackDepth() {
return stackDepth;
}

public static synchronized void setPreserveRepository(boolean preserve) {
preserveRepository = preserve;
}

public static synchronized boolean getPreserveRepository() {
return preserveRepository;
}

private static synchronized void reset() {
setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE);
setMemorySize(DEFAULT_MEMORY_SIZE);
Expand All @@ -150,6 +160,7 @@ private static synchronized void reset() {
}
setStackDepth(DEFAULT_STACK_DEPTH);
setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE);
setPreserveRepository(DEFAULT_PRESERVE_REPOSITORY);
}

static synchronized long getWaitInterval() {
Expand Down
4 changes: 4 additions & 0 deletions src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java
Expand Up @@ -160,6 +160,10 @@ private static boolean tryToUseAsRepository(final SafePath path) {
}

synchronized void clear() {
if (Options.getPreserveRepository()) {
return;
}

for (SafePath p : cleanupDirectories) {
try {
SecuritySupport.clearDirectory(p);
Expand Down
23 changes: 19 additions & 4 deletions src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java
Expand Up @@ -51,9 +51,9 @@ final class DCmdConfigure extends AbstractDCmd {
* @param globalBufferCount number of global buffers
* @param globalBufferSize size of global buffers
* @param threadBufferSize size of thread buffer for events
* @param memorySize Size of in memory buffer
* @param maxChunkSize threshold at which a new chunk is created in the disk repository
* @param sampleThreads if thread sampling should be enabled
*
* @param preserveRepository if files in the repository should be deleted on exit.
* @return result
* @throws DCmdException
Expand All @@ -69,7 +69,8 @@ final class DCmdConfigure extends AbstractDCmd {
Long globalBufferSize,
Long threadBufferSize,
Long memorySize,
Long maxChunkSize
Long maxChunkSize,
Boolean preserveRepository

) throws DCmdException {
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
Expand All @@ -80,7 +81,8 @@ final class DCmdConfigure extends AbstractDCmd {
", globalbuffersize=" + globalBufferSize +
", thread_buffer_size=" + threadBufferSize +
", memorysize=" + memorySize +
", maxchunksize=" + maxChunkSize);
", maxchunksize=" + maxChunkSize +
", preserveRepository=" + preserveRepository);
}


Expand All @@ -103,6 +105,14 @@ final class DCmdConfigure extends AbstractDCmd {
updated = true;
}

if (preserveRepository != null) {
Options.setPreserveRepository(preserveRepository.booleanValue());
if (verbose) {
printPreserveRepository();
}
updated = true;
}

if (dumpPath != null) {
try {
Options.setDumpPath(new SafePath(dumpPath));
Expand Down Expand Up @@ -176,6 +186,7 @@ final class DCmdConfigure extends AbstractDCmd {
if (!updated) {
println("Current configuration:");
println();
printPreserveRepository();
printRepositoryPath();
printDumpPath();
printStackDepth();
Expand All @@ -194,6 +205,10 @@ private void printRepositoryPath() {
println();
}

private void printPreserveRepository() {
println("Preserve repository: " + Options.getPreserveRepository());
}

private void printDumpPath() {
print("Dump path: ");
printPath(Options.getDumpPath());
Expand Down

1 comment on commit 336a23e

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.