8303229: JFR: Preserve disk repository after exit

Reviewed-by: dholmes, mgronlun
This commit is contained in:
Erik Gahlin 2023-04-03 08:55:45 +00:00
parent ecec611af6
commit 336a23e70a
10 changed files with 235 additions and 45 deletions

View File

@ -367,14 +367,15 @@ GrowableArray<const char*>* JfrDCmd::argument_name_array() const {
JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output, JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
bool heap) : DCmdWithParser(output, heap), bool heap) : DCmdWithParser(output, heap),
_repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL), _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), _dump_path("dumppath", "Path to dump, e.g. \\\"My Dump path\\\"", "STRING", false, NULL),
_stack_depth("stackdepth", "Stack Depth", "JULONG", false, "64"), _stack_depth("stackdepth", "Stack depth", "JULONG", false, "64"),
_global_buffer_count("globalbuffercount", "Number of global buffers,", "JULONG", false, "20"), _global_buffer_count("globalbuffercount", "Number of global buffers,", "JULONG", false, "20"),
_global_buffer_size("globalbuffersize", "Size of a global buffers,", "MEMORY SIZE", false, "512k"), _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"), _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"), _memory_size("memorysize", "Overall memory size, ", "MEMORY SIZE", false, "10m"),
_max_chunk_size("maxchunksize", "Size of an individual disk chunk", "MEMORY SIZE", false, "12m"), _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) { _verbose(true) {
_dcmdparser.add_dcmd_option(&_repository_path); _dcmdparser.add_dcmd_option(&_repository_path);
_dcmdparser.add_dcmd_option(&_dump_path); _dcmdparser.add_dcmd_option(&_dump_path);
@ -385,6 +386,7 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out
_dcmdparser.add_dcmd_option(&_memory_size); _dcmdparser.add_dcmd_option(&_memory_size);
_dcmdparser.add_dcmd_option(&_max_chunk_size); _dcmdparser.add_dcmd_option(&_max_chunk_size);
_dcmdparser.add_dcmd_option(&_sample_threads); _dcmdparser.add_dcmd_option(&_sample_threads);
_dcmdparser.add_dcmd_option(&_preserve_repository);
}; };
void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const {
@ -392,49 +394,52 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const {
// 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 // 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890
out->print_cr("Options:"); out->print_cr("Options:");
out->print_cr(""); out->print_cr("");
out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy"); 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(" 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(" 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(" initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)"); out->print_cr(" memorysize)");
out->print_cr(""); out->print_cr("");
out->print_cr(" globalbuffersize (Optional) Size of the global buffers, in bytes. This option is a"); 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(" 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(" 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(" been initialized. (STRING, default determined by the value for");
out->print_cr(" memorysize)"); out->print_cr(" memorysize)");
out->print_cr(""); out->print_cr("");
out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if"); 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(" 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(" 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(" changed once JFR has been initialized. (STRING, 12M)");
out->print_cr(""); out->print_cr("");
out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following"); 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(" 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(" gigabytes. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (STRING, 10M)"); out->print_cr(" initialized. (STRING, 10M)");
out->print_cr(""); out->print_cr("");
out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until"); 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(" 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(" 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(" Linux operating systems, the temporary directory is /tmp. On");
out->print_cr(" Windows, the temporary directory is specified by the TMP"); out->print_cr(" Windows, the temporary directory is specified by the TMP");
out->print_cr(" environment variable)"); out->print_cr(" environment variable)");
out->print_cr(""); out->print_cr("");
out->print_cr(" dumppath (Optional) Path to the location where a recording file is written"); 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(" 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(" crash. (STRING, The default location is the current directory)");
out->print_cr(""); out->print_cr("");
out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value"); 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(" 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(" degradation. This value cannot be changed once JFR has been");
out->print_cr(" initialized. (LONG, 64)"); out->print_cr(" initialized. (LONG, 64)");
out->print_cr(""); out->print_cr("");
out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of"); 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(" 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(" '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(" performance and is not recommended. This value cannot be changed");
out->print_cr(" once JFR has been initialized. (STRING, 8k)"); 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("");
out->print_cr("Options must be specified using the <key> or <key>=<value> syntax."); out->print_cr("Options must be specified using the <key> or <key>=<value> syntax.");
out->print_cr(""); out->print_cr("");
@ -480,6 +485,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
jobject thread_buffer_size = NULL; jobject thread_buffer_size = NULL;
jobject max_chunk_size = NULL; jobject max_chunk_size = NULL;
jobject memory_size = NULL; jobject memory_size = NULL;
jobject preserve_repository = nullptr;
if (!JfrRecorder::is_created()) { if (!JfrRecorder::is_created()) {
if (_stack_depth.is_set()) { if (_stack_depth.is_set()) {
@ -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 klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
static const char method[] = "execute"; static const char method[] = "execute";
static const char signature[] = "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/Integer;" 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/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); JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
execute_args.set_receiver(h_dcmd_instance); execute_args.set_receiver(h_dcmd_instance);
@ -530,6 +539,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
execute_args.push_jobject(thread_buffer_size); execute_args.push_jobject(thread_buffer_size);
execute_args.push_jobject(memory_size); execute_args.push_jobject(memory_size);
execute_args.push_jobject(max_chunk_size); execute_args.push_jobject(max_chunk_size);
execute_args.push_jobject(preserve_repository);
JfrJavaSupport::call_virtual(&execute_args, THREAD); JfrJavaSupport::call_virtual(&execute_args, THREAD);
handle_dcmd_result(output(), result.get_oop(), source, THREAD); handle_dcmd_result(output(), result.get_oop(), source, THREAD);

View File

@ -157,6 +157,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
DCmdArgument<MemorySizeArgument> _memory_size; DCmdArgument<MemorySizeArgument> _memory_size;
DCmdArgument<MemorySizeArgument> _max_chunk_size; DCmdArgument<MemorySizeArgument> _max_chunk_size;
DCmdArgument<bool> _sample_threads; DCmdArgument<bool> _sample_threads;
DCmdArgument<bool> _preserve_repository;
bool _verbose; bool _verbose;
public: public:
@ -177,7 +178,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL}; JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
return p; return p;
} }
static int num_arguments() { return 9; } static int num_arguments() { return 10; }
virtual void execute(DCmdSource source, TRAPS); virtual void execute(DCmdSource source, TRAPS);
virtual void print_help(const char* name) const; virtual void print_help(const char* name) const;
}; };

View File

@ -165,6 +165,7 @@ const char* const default_sample_threads = "true";
const char* const default_stack_depth = "64"; const char* const default_stack_depth = "64";
const char* const default_retransform = "true"; const char* const default_retransform = "true";
const char* const default_old_object_queue_size = "256"; 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";) DEBUG_ONLY(const char* const default_sample_protection = "false";)
// statics // statics
@ -254,6 +255,13 @@ static DCmdArgument<bool> _dcmd_retransform(
true, true,
default_retransform); 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 DCmdParser _parser;
static void register_parser_options() { static void register_parser_options() {
@ -268,6 +276,7 @@ static void register_parser_options() {
_parser.add_dcmd_option(&_dcmd_sample_threads); _parser.add_dcmd_option(&_dcmd_sample_threads);
_parser.add_dcmd_option(&_dcmd_retransform); _parser.add_dcmd_option(&_dcmd_retransform);
_parser.add_dcmd_option(&_dcmd_old_object_queue_size); _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);) DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
} }
@ -379,6 +388,9 @@ bool JfrOptionSet::configure(TRAPS) {
configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set()); configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
configure._sample_threads.set_value(_dcmd_sample_threads.value()); 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.set_verbose(false);
configure.execute(DCmd_Source_Internal, THREAD); configure.execute(DCmd_Source_Internal, THREAD);

View File

@ -1337,6 +1337,12 @@ buffers.
Maximum number of old objects to track. Maximum number of old objects to track.
By default, the number of objects is set to 256. By default, the number of objects is set to 256.
.TP .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] \f[V]repository=\f[R]\f[I]path\f[R]
Specifies the repository (a directory) for temporary disk storage. Specifies the repository (a directory) for temporary disk storage.
By default, the system\[aq]s temporary directory is used. By default, the system\[aq]s temporary directory is used.

View File

@ -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] On Windwows, the temporary directory is specified by the \f[V]TMP\f[R]
environment variable.) environment variable.)
.IP \[bu] 2 .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. \f[V]stackdepth\f[R]: (Optional) Stack depth for stack traces.
Setting this value greater than the default of 64 may cause a Setting this value greater than the default of 64 may cause a
performance degradation. performance degradation.

View File

@ -52,6 +52,7 @@ public final class Options {
private static final int DEFAULT_STACK_DEPTH = 64; private static final int DEFAULT_STACK_DEPTH = 64;
private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024; private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024;
private static final SafePath DEFAULT_DUMP_PATH = null; private static final SafePath DEFAULT_DUMP_PATH = null;
private static final boolean DEFAULT_PRESERVE_REPOSITORY = false;
private static long memorySize; private static long memorySize;
private static long globalBufferSize; private static long globalBufferSize;
@ -59,6 +60,7 @@ public final class Options {
private static long threadBufferSize; private static long threadBufferSize;
private static int stackDepth; private static int stackDepth;
private static long maxChunkSize; private static long maxChunkSize;
private static boolean preserveRepository;
static { static {
final long pageSize = Unsafe.getUnsafe().pageSize(); final long pageSize = Unsafe.getUnsafe().pageSize();
@ -138,6 +140,14 @@ public final class Options {
return stackDepth; return stackDepth;
} }
public static synchronized void setPreserveRepository(boolean preserve) {
preserveRepository = preserve;
}
public static synchronized boolean getPreserveRepository() {
return preserveRepository;
}
private static synchronized void reset() { private static synchronized void reset() {
setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE); setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE);
setMemorySize(DEFAULT_MEMORY_SIZE); setMemorySize(DEFAULT_MEMORY_SIZE);
@ -150,6 +160,7 @@ public final class Options {
} }
setStackDepth(DEFAULT_STACK_DEPTH); setStackDepth(DEFAULT_STACK_DEPTH);
setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE); setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE);
setPreserveRepository(DEFAULT_PRESERVE_REPOSITORY);
} }
static synchronized long getWaitInterval() { static synchronized long getWaitInterval() {

View File

@ -160,6 +160,10 @@ public final class Repository {
} }
synchronized void clear() { synchronized void clear() {
if (Options.getPreserveRepository()) {
return;
}
for (SafePath p : cleanupDirectories) { for (SafePath p : cleanupDirectories) {
try { try {
SecuritySupport.clearDirectory(p); SecuritySupport.clearDirectory(p);

View File

@ -51,9 +51,9 @@ final class DCmdConfigure extends AbstractDCmd {
* @param globalBufferCount number of global buffers * @param globalBufferCount number of global buffers
* @param globalBufferSize size of global buffers * @param globalBufferSize size of global buffers
* @param threadBufferSize size of thread buffer for events * @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 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 * @return result
* @throws DCmdException * @throws DCmdException
@ -69,7 +69,8 @@ final class DCmdConfigure extends AbstractDCmd {
Long globalBufferSize, Long globalBufferSize,
Long threadBufferSize, Long threadBufferSize,
Long memorySize, Long memorySize,
Long maxChunkSize Long maxChunkSize,
Boolean preserveRepository
) throws DCmdException { ) throws DCmdException {
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) { if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
@ -80,7 +81,8 @@ final class DCmdConfigure extends AbstractDCmd {
", globalbuffersize=" + globalBufferSize + ", globalbuffersize=" + globalBufferSize +
", thread_buffer_size=" + threadBufferSize + ", thread_buffer_size=" + threadBufferSize +
", memorysize=" + memorySize + ", memorysize=" + memorySize +
", maxchunksize=" + maxChunkSize); ", maxchunksize=" + maxChunkSize +
", preserveRepository=" + preserveRepository);
} }
@ -103,6 +105,14 @@ final class DCmdConfigure extends AbstractDCmd {
updated = true; updated = true;
} }
if (preserveRepository != null) {
Options.setPreserveRepository(preserveRepository.booleanValue());
if (verbose) {
printPreserveRepository();
}
updated = true;
}
if (dumpPath != null) { if (dumpPath != null) {
try { try {
Options.setDumpPath(new SafePath(dumpPath)); Options.setDumpPath(new SafePath(dumpPath));
@ -176,6 +186,7 @@ final class DCmdConfigure extends AbstractDCmd {
if (!updated) { if (!updated) {
println("Current configuration:"); println("Current configuration:");
println(); println();
printPreserveRepository();
printRepositoryPath(); printRepositoryPath();
printDumpPath(); printDumpPath();
printStackDepth(); printStackDepth();
@ -194,6 +205,10 @@ final class DCmdConfigure extends AbstractDCmd {
println(); println();
} }
private void printPreserveRepository() {
println("Preserve repository: " + Options.getPreserveRepository());
}
private void printDumpPath() { private void printDumpPath() {
print("Dump path: "); print("Dump path: ");
printPath(Options.getDumpPath()); printPath(Options.getDumpPath());

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.jfr.jcmd;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import jdk.test.lib.jfr.FileHelper;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Utils;
/**
* @test
* @summary Test verifies that files are left after preserve-repository has been set using jcmd JFR.configure
* @key jfr
* @requires vm.hasJFR
* @library /test/lib /test/jdk
* @run main/othervm jdk.jfr.jcmd.TestJcmdPreserveRepository
*/
public class TestJcmdPreserveRepository {
public static class TestProcess {
public static void main(String... args) {
OutputAnalyzer output = JcmdHelper.jcmd("JFR.configure", "preserve-repository=true");
System.exit(output.getExitValue());
}
}
public static void main(String[] args) throws Throwable {
Path path = Path.of("./preserved");
String[] arguments = {
"-XX:StartFlightRecording",
"-XX:FlightRecorderOptions:repository=" + path,
"-Dtest.jdk=" + System.getProperty("test.jdk"),
TestProcess.class.getName()
};
OutputAnalyzer output = ProcessTools.executeTestJvm(arguments);
output.shouldHaveExitValue(0);
Optional<Path> p = Files.find(path, 99, (a,b) -> a.getFileName().toString().endsWith(".jfr")).findAny();
if (p.isEmpty()) {
throw new Exception("Could not find preserved files in repository");
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.jfr.startupargs;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
/**
* @test
* @summary Tests that -XX:FlightRecorderOptions:preserve-repository works
* @key jfr
* @requires vm.hasJFR
* @modules jdk.jfr
* @library /test/lib
* @run main/othervm jdk.jfr.startupargs.TestPreserveRepository
*/
public class TestPreserveRepository {
public static void main(String... args) throws Exception {
Path path = Path.of("./preserved");
String[] arguments = {
"-XX:StartFlightRecording",
"-XX:FlightRecorderOptions:repository=" + path + ",preserve-repository=true",
"-version"
};
ProcessBuilder pb = ProcessTools.createTestJvm(arguments);
OutputAnalyzer output = ProcessTools.executeProcess(pb);
output.shouldHaveExitValue(0);
Optional<Path> p = Files.find(path, 99, (a,b) -> a.getFileName().toString().endsWith(".jfr")).findAny();
if (p.isEmpty()) {
throw new Exception("Could not find preserved files in repository");
}
}
}