8326116: JFR: Add help option to -XX:StartFlightRecording
Reviewed-by: mgronlun
This commit is contained in:
parent
941bee197f
commit
f7c84137b5
@ -220,6 +220,11 @@ void JfrDCmd::execute(DCmdSource source, TRAPS) {
|
|||||||
if (invalid_state(output(), THREAD)) {
|
if (invalid_state(output(), THREAD)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (source == DCmd_Source_Internal && _args != nullptr && strcmp(_args, "help") == 0) {
|
||||||
|
print_java_help("printStartupHelp");
|
||||||
|
vm_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;C)[Ljava/lang/String;";
|
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;C)[Ljava/lang/String;";
|
||||||
JavaValue result(T_OBJECT);
|
JavaValue result(T_OBJECT);
|
||||||
JfrJavaArguments execute(&result, javaClass(), "execute", signature, CHECK);
|
JfrJavaArguments execute(&result, javaClass(), "execute", signature, CHECK);
|
||||||
@ -241,15 +246,19 @@ void JfrDCmd::execute(DCmdSource source, TRAPS) {
|
|||||||
handle_dcmd_result(output(), result.get_oop(), source, THREAD);
|
handle_dcmd_result(output(), result.get_oop(), source, THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JfrDCmd::print_help(const char* name) const {
|
void JfrDCmd::print_java_help(const char* help_method) const {
|
||||||
static const char signature[] = "()[Ljava/lang/String;";
|
static const char signature[] = "()[Ljava/lang/String;";
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
JavaValue result(T_OBJECT);
|
JavaValue result(T_OBJECT);
|
||||||
JfrJavaArguments printHelp(&result, javaClass(), "printHelp", signature, thread);
|
JfrJavaArguments printHelp(&result, javaClass(), help_method, signature, thread);
|
||||||
invoke(printHelp, thread);
|
invoke(printHelp, thread);
|
||||||
handle_dcmd_result(output(), result.get_oop(), DCmd_Source_MBean, thread);
|
handle_dcmd_result(output(), result.get_oop(), DCmd_Source_MBean, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JfrDCmd::print_help(const char* name) const {
|
||||||
|
print_java_help("printHelp");
|
||||||
|
}
|
||||||
|
|
||||||
static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array) {
|
static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array) {
|
||||||
assert(array != nullptr, "invariant");
|
assert(array != nullptr, "invariant");
|
||||||
DCmdArgumentInfo * const dummy = new DCmdArgumentInfo(nullptr,
|
DCmdArgumentInfo * const dummy = new DCmdArgumentInfo(nullptr,
|
||||||
|
@ -37,6 +37,7 @@ class JfrDCmd : public DCmd {
|
|||||||
JfrDCmd(outputStream* output, bool heap, int num_arguments);
|
JfrDCmd(outputStream* output, bool heap, int num_arguments);
|
||||||
virtual const char* javaClass() const = 0;
|
virtual const char* javaClass() const = 0;
|
||||||
void invoke(JfrJavaArguments& method, TRAPS) const;
|
void invoke(JfrJavaArguments& method, TRAPS) const;
|
||||||
|
void print_java_help(const char* help_method) const;
|
||||||
public:
|
public:
|
||||||
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;
|
||||||
|
@ -55,6 +55,7 @@ import jdk.jfr.internal.jfc.JFC;
|
|||||||
import jdk.jfr.internal.jfc.model.JFCModel;
|
import jdk.jfr.internal.jfc.model.JFCModel;
|
||||||
import jdk.jfr.internal.jfc.model.JFCModelException;
|
import jdk.jfr.internal.jfc.model.JFCModelException;
|
||||||
import jdk.jfr.internal.jfc.model.XmlInput;
|
import jdk.jfr.internal.jfc.model.XmlInput;
|
||||||
|
import jdk.jfr.internal.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFR.start
|
* JFR.start
|
||||||
@ -317,11 +318,35 @@ final class DCmdStart extends AbstractDCmd {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] printStartupHelp() {
|
||||||
|
Map<String, String> parameters = Map.of(
|
||||||
|
"$SYNTAX", "-XX:StartFlightRecording:[options]",
|
||||||
|
"$SOURCE", "-XX:StartFlightRecording:",
|
||||||
|
"$DELIMITER", ",",
|
||||||
|
"$DELIMITER_NAME", "comma",
|
||||||
|
"$DIRECTORY", exampleDirectory(),
|
||||||
|
"$JFC_OPTIONS", jfcOptions()
|
||||||
|
);
|
||||||
|
return Utils.format(helpTemplate(), parameters).lines().toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] printHelp() {
|
public String[] printHelp() {
|
||||||
|
Map<String, String> parameters = Map.of(
|
||||||
|
"$SYNTAX", "JFR.start [options]",
|
||||||
|
"$SOURCE", "$ jcmd <pid> JFR.start ",
|
||||||
|
"$DELIMITER", " ",
|
||||||
|
"$DELIMITER_NAME", "whitespace",
|
||||||
|
"$DIRECTORY", exampleDirectory(),
|
||||||
|
"$JFC_OPTIONS", jfcOptions()
|
||||||
|
);
|
||||||
|
return Utils.format(helpTemplate(), parameters).lines().toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String helpTemplate() {
|
||||||
// 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890
|
// 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890
|
||||||
return """
|
return """
|
||||||
Syntax : JFR.start [options]
|
Syntax : $SYNTAX
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
@ -352,8 +377,8 @@ final class DCmdStart extends AbstractDCmd {
|
|||||||
generated from the PID and the current date in the specified
|
generated from the PID and the current date in the specified
|
||||||
directory. (STRING, no default value)
|
directory. (STRING, no default value)
|
||||||
|
|
||||||
Note: If a filename is given, '%%p' in the filename will be
|
Note: If a filename is given, '%p' in the filename will be
|
||||||
replaced by the PID, and '%%t' will be replaced by the time in
|
replaced by the PID, and '%t' will be replaced by the time in
|
||||||
'yyyy_MM_dd_HH_mm_ss' format.
|
'yyyy_MM_dd_HH_mm_ss' format.
|
||||||
|
|
||||||
maxage (Optional) Maximum time to keep the recorded data on disk. This
|
maxage (Optional) Maximum time to keep the recorded data on disk. This
|
||||||
@ -409,27 +434,28 @@ final class DCmdStart extends AbstractDCmd {
|
|||||||
take precedence. The whitespace character can be omitted for timespan values,
|
take precedence. The whitespace character can be omitted for timespan values,
|
||||||
i.e. 20s. For more information about the settings syntax, see Javadoc of the
|
i.e. 20s. For more information about the settings syntax, see Javadoc of the
|
||||||
jdk.jfr package.
|
jdk.jfr package.
|
||||||
%s
|
$JFC_OPTIONS
|
||||||
Options must be specified using the <key> or <key>=<value> syntax.
|
Options must be specified using the <key> or <key>=<value> syntax. Multiple
|
||||||
|
options are separated with a $DELIMITER_NAME.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
$ jcmd <pid> JFR.start
|
$SOURCE
|
||||||
$ jcmd <pid> JFR.start filename=dump.jfr
|
$SOURCEfilename=dump.jfr
|
||||||
$ jcmd <pid> JFR.start filename=%s
|
$SOURCEfilename=$DIRECTORY
|
||||||
$ jcmd <pid> JFR.start dumponexit=true
|
$SOURCEdumponexit=true
|
||||||
$ jcmd <pid> JFR.start maxage=1h maxsize=1000M
|
$SOURCEmaxage=1h$DELIMITERmaxsize=1000M
|
||||||
$ jcmd <pid> JFR.start settings=profile
|
$SOURCEsettings=profile
|
||||||
$ jcmd <pid> JFR.start delay=5m settings=my.jfc
|
$SOURCEdelay=5m$DELIMITERsettings=my.jfc
|
||||||
$ jcmd <pid> JFR.start gc=high method-profiling=high
|
$SOURCEgc=high$DELIMITERmethod-profiling=high
|
||||||
$ jcmd <pid> JFR.start jdk.JavaMonitorEnter#threshold=1ms
|
$SOURCEjdk.JavaMonitorEnter#threshold=1ms
|
||||||
$ jcmd <pid> JFR.start +HelloWorld#enabled=true +HelloWorld#stackTrace=true
|
$SOURCE+HelloWorld#enabled=true$DELIMITER+HelloWorld#stackTrace=true
|
||||||
$ jcmd <pid> JFR.start settings=user.jfc com.example.UserDefined#enabled=true
|
$SOURCEsettings=user.jfc$DELIMITERcom.example.UserDefined#enabled=true
|
||||||
$ jcmd <pid> JFR.start settings=none +Hello#enabled=true
|
$SOURCEsettings=none$DELIMITER+Hello#enabled=true
|
||||||
|
|
||||||
Note, if the default event settings are modified, overhead may exceed 1%%.
|
Note, if the default event settings are modified, overhead may exceed 1%.
|
||||||
|
|
||||||
""".formatted(jfcOptions(), exampleDirectory()).lines().toArray(String[]::new);
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String jfcOptions() {
|
private static String jfcOptions() {
|
||||||
|
@ -37,6 +37,7 @@ import java.nio.file.Path;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -445,4 +446,26 @@ public final class Utils {
|
|||||||
public static String makeSimpleName(String qualified) {
|
public static String makeSimpleName(String qualified) {
|
||||||
return qualified.substring(qualified.lastIndexOf(".") + 1);
|
return qualified.substring(qualified.lastIndexOf(".") + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String format(String template, Map<String, String> parameters) {
|
||||||
|
StringBuilder sb = new StringBuilder(3 * template.length() / 2);
|
||||||
|
List<String> keys = new ArrayList<>(parameters.keySet());
|
||||||
|
// Sort so longest keys are checked first in case keys overlap.
|
||||||
|
keys.sort((a, b) -> b.length() - a.length());
|
||||||
|
for (int i = 0; i < template.length(); i++) {
|
||||||
|
int index = i;
|
||||||
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
|
String key = keys.get(j);
|
||||||
|
if (template.startsWith(key, i)) {
|
||||||
|
sb.append(parameters.get(key));
|
||||||
|
i += key.length() - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == index) {
|
||||||
|
sb.append(template.charAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
47
test/jdk/jdk/jfr/startupargs/TestStartHelp.java
Normal file
47
test/jdk/jdk/jfr/startupargs/TestStartHelp.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, 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 jdk.jfr.Recording;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @key jfr
|
||||||
|
* @requires vm.hasJFR
|
||||||
|
* @library /test/lib /test/jdk
|
||||||
|
* @run main jdk.jfr.startupargs.TestStartHelp
|
||||||
|
*/
|
||||||
|
public class TestStartHelp {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-XX:StartFlightRecording:help");
|
||||||
|
OutputAnalyzer out = ProcessTools.executeProcess(pb);
|
||||||
|
out.shouldContain("Syntax : -XX:StartFlightRecording:[options]");
|
||||||
|
out.shouldContain("options are separated with a comma.");
|
||||||
|
out.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user