提交 0a8332f5 编写于 作者: Y Yifei Zhang 提交者: 云矅

[JWarmup] Invoke JWarmup via jcmd

Summary: Invoke JWarmup APIs via jcmd

Test Plan: test/jwarmup/jcmd/TestInvokeJWarmupViaJcmd.java

Reviewers: kuaiwei, luchsh

Issue: https://aone.alibaba-inc.com/task/22023553

CR: https://aone.alibaba-inc.com/task/22023553
上级 0e8ab8e7
...@@ -410,6 +410,10 @@ ...@@ -410,6 +410,10 @@
template(signers_name, "signers_name") \ template(signers_name, "signers_name") \
template(loader_data_name, "loader_data") \ template(loader_data_name, "loader_data") \
template(dependencies_name, "dependencies") \ template(dependencies_name, "dependencies") \
template(com_alibaba_jwarmup_JWarmUp, "com/alibaba/jwarmup/JWarmUp") \
template(jwarmup_notify_application_startup_is_done_name, "notifyApplicationStartUpIsDone") \
template(jwarmup_check_if_compilation_is_complete_name, "checkIfCompilationIsComplete") \
template(jwarmup_notify_jvm_deopt_warmup_methods_name, "notifyJVMDeoptWarmUpMethods") \
template(jwarmup_dummy_name, "dummy") \ template(jwarmup_dummy_name, "dummy") \
template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \
template(getFileURL_name, "getFileURL") \ template(getFileURL_name, "getFileURL") \
......
...@@ -63,6 +63,7 @@ void DCmdRegistrant::register_dcmds(){ ...@@ -63,6 +63,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JWarmupDCmd>(full_export, true, false));
// Enhanced JMX Agent Support // Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an // These commands won't be exported via the DiagnosticCommandMBean until an
...@@ -743,3 +744,108 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { ...@@ -743,3 +744,108 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
output()->print_cr("Target VM does not support GC log file rotation."); output()->print_cr("Target VM does not support GC log file rotation.");
} }
} }
JWarmupDCmd::JWarmupDCmd(outputStream* output, bool heap_allocated) : DCmdWithParser(output, heap_allocated),
_notify_startup("-notify", "Notify JVM that application startup is done", "BOOLEAN", false, "false"),
_check_compile_finished("-check", "Check if the last compilation submitted by JWarmup is complete", "BOOLEAN", false, "false"),
_deopt("-deopt", "Notify JVM to de-optimize warmup methods", "BOOLEAN", false, "false"),
_help("-help", "Print this help information", "BOOLEAN", false, "false")
{
_dcmdparser.add_dcmd_option(&_notify_startup);
_dcmdparser.add_dcmd_option(&_check_compile_finished);
_dcmdparser.add_dcmd_option(&_deopt);
_dcmdparser.add_dcmd_option(&_help);
}
int JWarmupDCmd::num_arguments() {
ResourceMark rm;
JWarmupDCmd* dcmd = new JWarmupDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void JWarmupDCmd::execute(DCmdSource source, TRAPS) {
assert(is_init_completed(), "JVM is not fully initialized. Please try it later.");
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::com_alibaba_jwarmup_JWarmUp(), true, CHECK);
instanceKlassHandle ik (THREAD, k);
if (ik->should_be_initialized()) {
ik->initialize(THREAD);
}
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
if (_notify_startup.value()) {
if (!CompilationWarmUp) {
output()->print_cr("CompilationWarmUp is off, "
"notifyApplicationStartUpIsDone is invalid");
return;
}
JavaValue result(T_VOID);
JavaCalls::call_static(&result, ik, vmSymbols::jwarmup_notify_application_startup_is_done_name(), vmSymbols::void_method_signature(), THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
} else if (_check_compile_finished.value()) {
if (!CompilationWarmUp) {
output()->print_cr("CompilationWarmUp is off, "
"checkIfCompilationIsComplete is invalid");
return;
}
JavaValue result(T_BOOLEAN);
JavaCalls::call_static(&result, ik, vmSymbols::jwarmup_check_if_compilation_is_complete_name(), vmSymbols::void_boolean_signature(), THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
if (result.get_jboolean()) {
output()->print_cr("Last compilation task is completed.");
} else {
output()->print_cr("Last compilation task is not completed.");
}
} else if (_deopt.value()) {
if (!(CompilationWarmUp && CompilationWarmUpExplicitDeopt)) {
output()->print_cr("CompilationWarmUp or CompilationWarmUpExplicitDeopt is off, "
"notifyJVMDeoptWarmUpMethods is invalid");
return;
}
JavaValue result(T_VOID);
JavaCalls::call_static(&result, ik, vmSymbols::jwarmup_notify_jvm_deopt_warmup_methods_name(), vmSymbols::void_method_signature(), THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
} else if (_help.value()) {
print_info();
} else {
print_info();
}
}
void JWarmupDCmd::print_info() {
output()->print_cr("The following commands are available:\n"
"-notify: %s\n"
"-check: %s\n"
"-deopt: %s\n"
"-help: %s\n",
_notify_startup.description(), _check_compile_finished.description(), _deopt.description(), _help.description());
}
\ No newline at end of file
...@@ -442,4 +442,23 @@ public: ...@@ -442,4 +442,23 @@ public:
} }
}; };
class JWarmupDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _notify_startup;
DCmdArgument<bool> _check_compile_finished;
DCmdArgument<bool> _deopt;
DCmdArgument<bool> _help;
void print_info();
public:
JWarmupDCmd(outputStream* output, bool heap_allocated);
static const char* name() {
return "JWarmup";
}
static const char* description() {
return "JWarmup command. ";
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*
*/
import com.oracle.java.testlibrary.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.lang.reflect.Field;
import static com.oracle.java.testlibrary.Asserts.assertTrue;
/*
* @test TestInvokeJWarmupViaJcmd
* @library /testlibrary
* @build TestInvokeJWarmupViaJcmd
* @run main TestInvokeJWarmupViaJcmd
* @run main/othervm TestInvokeJWarmupViaJcmd
* @summary test invoking JWarmup APIs via jcmd
*/
public class TestInvokeJWarmupViaJcmd {
public static void main(String[] args) throws Exception {
Recording.run();
CheckNotifyStartup.run();
CheckCompilationSuccess.run();
CheckCompilationFail.run();
CheckDeopt.run();
}
}
class Main {
public static void main(String[] args) throws Exception {
Main main = new Main();
for (int i = 0; i < 20000; i++) {
main.foo();
}
// Waiting for recording or jcmd.
Thread.sleep(12000);
System.out.println("done!");
}
public void foo() {}
}
/**
* JWarmup command
*/
class JCMDArg {
public static final String notify = "-notify";
public static final String check = "-check";
public static final String deopt = "-deopt";
}
class ProgramArg {
public static final String Recording = "Recording";
public static final String NotifyStartup = "NotifyStartup";
public static final String CheckCompilationSuccess = "CheckCompilationSuccess";
public static final String CheckCompilationFail = "CheckCompilationFail";
public static final String Deopt = "Deopt";
}
/**
* JVM options
*/
class JVMArg {
public static final List<String> Recording = new ArrayList(Arrays.asList(
"-XX:-ClassUnloading",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-ClassUnloadingWithConcurrentMark",
"-XX:CompilationWarmUpLogfile=jwarmup.log",
"-XX:+CompilationWarmUpRecording",
"-XX:CompilationWarmUpRecordTime=10"
));
public static final List<String> Running = new ArrayList(Arrays.asList(
"-XX:+CompilationWarmUp",
"-XX:+CompilationWarmUpExplicitDeopt",
"-XX:-TieredCompilation",
"-XX:CompilationWarmUpLogfile=jwarmup.log",
"-XX:CompilationWarmUpDeoptTime=0"
));
}
class Recording {
public static void run() throws Exception {
System.out.println("Test Jwarmup recording.");
ProcessBuilderFactory.create(ProgramArg.Recording, JVMArg.Recording).start();
Thread.sleep(15000);
File logFile = new File("./jwarmup.log");
assertTrue(logFile.exists() && logFile.isFile());
}
}
class CheckNotifyStartup {
public static void run() throws Exception {
System.out.println("Test JWarmup notifyStartup.");
ProcessBuilder processBuilder = ProcessBuilderFactory.create(ProgramArg.NotifyStartup, JVMArg.Running);
Process p = processBuilder.start();
Thread.sleep(5000);
String pid = PID.get(p);
assert pid != null;
JcmdCaller.callJcmd(ProgramArg.NotifyStartup, pid);
}
}
class CheckCompilationSuccess {
public static void run() throws Exception {
System.out.println("Test JWarmup checkCompilation.");
ProcessBuilder processBuilder = ProcessBuilderFactory.create(ProgramArg.CheckCompilationSuccess, JVMArg.Running);
Process p = processBuilder.start();
Thread.sleep(5000);
String pid = PID.get(p);
assert pid != null;
JcmdCaller.callJcmd(ProgramArg.CheckCompilationSuccess, pid);
}
}
/**
* Excluding compiling com.alibaba.jwarmup.JWarmUp.dummy() to test a unfinished compilation task.
*/
class CheckCompilationFail {
public static void run() throws Exception {
System.out.println("Test JWarmup checkCompilation.");
List<String> jvmArgs = new ArrayList<>();
jvmArgs.addAll(JVMArg.Running);
jvmArgs.add("-XX:CompileCommand=exclude,com/alibaba/jwarmup/JWarmUp,dummy");
ProcessBuilder processBuilder = ProcessBuilderFactory.create(ProgramArg.CheckCompilationFail, jvmArgs);
Process p = processBuilder.start();
String pid = PID.get(p);
assert pid != null;
Thread.sleep(5000);
JcmdCaller.callJcmd(ProgramArg.CheckCompilationFail, pid);
}
}
class CheckDeopt {
public static void run() throws Exception {
System.out.println("Test JWarmup de-optimization.");
ProcessBuilder processBuilder = ProcessBuilderFactory.create(ProgramArg.Deopt, JVMArg.Running);
Process p = processBuilder.start();
Thread.sleep(5000);
JcmdCaller.callJcmd(ProgramArg.Deopt, PID.get(p));
}
}
class ProcessBuilderFactory {
public static ProcessBuilder create(String programArg, final List<String> jvmArgs) throws Exception {
assert jvmArgs != null && jvmArgs.size() != 0;
List<String> _jvmArgs = new ArrayList<>(jvmArgs);
_jvmArgs.addAll(Arrays.asList(
Main.class.getName(),
programArg
));
return ProcessTools.createJavaProcessBuilder(_jvmArgs.stream().toArray(String[]::new));
}
}
class JcmdCaller {
public static void callJcmd(String arg, String pid) throws Exception {
if (ProgramArg.Recording.equals(arg)) {
return;
} else if (ProgramArg.NotifyStartup.equals(arg)) {
ProcessBuilder processBuilder = notifyStartup(pid);
OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
output.shouldContain("Command executed successfully");
} else if (ProgramArg.CheckCompilationSuccess.equals(arg)) {
ProcessBuilder processBuilder = checkCompilation(pid);
OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
output.shouldContain("Last compilation task is completed.");
} else if (ProgramArg.CheckCompilationFail.equals(arg)) {
ProcessBuilder processBuilder = checkCompilation(pid);
OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
output.shouldContain("Last compilation task is not completed.");
} else if (ProgramArg.Deopt.equals(arg)) {
ProcessBuilder processBuilder = deopt(pid);
OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
output.shouldContain("Command executed successfully");
} else {
throw new RuntimeException(String.format("Unrecognized argument: %s", arg));
}
}
private static ProcessBuilder notifyStartup(String pid) {
JDKToolLauncher notify = JDKToolLauncher.create("jcmd")
.addToolArg(pid)
.addToolArg("JWarmup")
.addToolArg(JCMDArg.notify);
return new ProcessBuilder(notify.getCommand());
}
private static ProcessBuilder checkCompilation(String pid) throws Exception {
// Invoke notifyStartup() before checkCompilation().
ProcessBuilder processBuilder = notifyStartup(pid);
Process p = processBuilder.start();
p.waitFor();
JDKToolLauncher check = JDKToolLauncher.create("jcmd")
.addToolArg(pid)
.addToolArg("JWarmup")
.addToolArg(JCMDArg.check);
return new ProcessBuilder(check.getCommand());
}
private static ProcessBuilder deopt(String pid) {
JDKToolLauncher deopt = JDKToolLauncher.create("jcmd")
.addToolArg(pid)
.addToolArg("JWarmup")
.addToolArg(JCMDArg.deopt);
return new ProcessBuilder(deopt.getCommand());
}
}
class PID {
public static String get(Process p) throws Exception {
if ("java.lang.UNIXProcess".equals(p.getClass().getName())) {
Field f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
long pid = f.getLong(p);
f.setAccessible(false);
return Long.toString(pid);
} else {
throw new RuntimeException("Unable to obtain pid.");
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册