Skip to content

Commit 4893c32

Browse files
Attach API and JCMD
1 parent 95a51f6 commit 4893c32

33 files changed

+2639
-332
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
package com.oracle.svm.core;
27+
28+
import com.oracle.svm.core.dcmd.AbstractDcmd;
29+
import com.oracle.svm.core.dcmd.DcmdParseException;
30+
31+
public class DumpRuntimeCompilationDcmd extends AbstractDcmd {
32+
33+
public DumpRuntimeCompilationDcmd() {
34+
this.name = "VM.runtime_compilation";
35+
this.impact = "low";
36+
}
37+
38+
@Override
39+
public String parseAndExecute(String[] arguments) throws DcmdParseException {
40+
if (arguments.length > 1) {
41+
throw new DcmdParseException("Too many arguments specified");
42+
}
43+
44+
DumpRuntimeCompilationSupport.dump();
45+
return "Dump created.";
46+
}
47+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DumpRuntimeCompilationOnSignalFeature.java

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, Red Hat Inc. All rights reserved.
34
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45
*
56
* This code is free software; you can redistribute it and/or modify it
@@ -26,14 +27,13 @@
2627

2728
import org.graalvm.nativeimage.Platform;
2829
import org.graalvm.nativeimage.Platform.WINDOWS;
30+
import org.graalvm.nativeimage.ImageSingletons;
2931

32+
import com.oracle.svm.core.dcmd.DcmdSupport;
3033
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3134
import com.oracle.svm.core.feature.InternalFeature;
3235
import com.oracle.svm.core.graal.RuntimeCompilation;
33-
import com.oracle.svm.core.heap.VMOperationInfos;
3436
import com.oracle.svm.core.jdk.RuntimeSupport;
35-
import com.oracle.svm.core.log.Log;
36-
import com.oracle.svm.core.thread.JavaVMOperation;
3737

3838
import jdk.internal.misc.Signal;
3939

@@ -47,7 +47,11 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {
4747

4848
@Override
4949
public void beforeAnalysis(BeforeAnalysisAccess access) {
50-
RuntimeSupport.getRuntimeSupport().addStartupHook(new DumpRuntimeCompilationStartupHook());
50+
if (VMInspectionOptions.hasAttachSupport()) {
51+
ImageSingletons.lookup(DcmdSupport.class).registerDcmd(new DumpRuntimeCompilationDcmd());
52+
} else {
53+
RuntimeSupport.getRuntimeSupport().addStartupHook(new DumpRuntimeCompilationStartupHook());
54+
}
5155
}
5256
}
5357

@@ -67,20 +71,7 @@ static void install() {
6771

6872
@Override
6973
public void handle(Signal arg0) {
70-
DumpRuntimeCompiledMethodsOperation vmOp = new DumpRuntimeCompiledMethodsOperation();
71-
vmOp.enqueue();
74+
DumpRuntimeCompilationSupport.dump();
7275
}
7376

74-
private static class DumpRuntimeCompiledMethodsOperation extends JavaVMOperation {
75-
DumpRuntimeCompiledMethodsOperation() {
76-
super(VMOperationInfos.get(DumpRuntimeCompiledMethodsOperation.class, "Dump runtime compiled methods", SystemEffect.SAFEPOINT));
77-
}
78-
79-
@Override
80-
protected void operate() {
81-
Log log = Log.log();
82-
SubstrateDiagnostics.dumpRuntimeCompilation(log);
83-
log.flush();
84-
}
85-
}
8677
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
27+
package com.oracle.svm.core;
28+
29+
import com.oracle.svm.core.heap.VMOperationInfos;
30+
import com.oracle.svm.core.log.Log;
31+
import com.oracle.svm.core.thread.JavaVMOperation;
32+
33+
public class DumpRuntimeCompilationSupport {
34+
35+
public static void dump() {
36+
DumpRuntimeCompiledMethodsOperation vmOp = new DumpRuntimeCompiledMethodsOperation();
37+
vmOp.enqueue();
38+
}
39+
40+
private static class DumpRuntimeCompiledMethodsOperation extends JavaVMOperation {
41+
DumpRuntimeCompiledMethodsOperation() {
42+
super(VMOperationInfos.get(DumpRuntimeCompiledMethodsOperation.class, "Dump runtime compiled methods", SystemEffect.SAFEPOINT));
43+
}
44+
45+
@Override
46+
protected void operate() {
47+
Log log = Log.log();
48+
SubstrateDiagnostics.dumpRuntimeCompilation(log);
49+
log.flush();
50+
}
51+
}
52+
}
Lines changed: 11 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, Red Hat Inc. All rights reserved.
34
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45
*
56
* This code is free software; you can redistribute it and/or modify it
@@ -24,22 +25,15 @@
2425
*/
2526
package com.oracle.svm.core;
2627

27-
import org.graalvm.nativeimage.CurrentIsolate;
28-
import org.graalvm.nativeimage.IsolateThread;
2928
import org.graalvm.nativeimage.Platform;
3029
import org.graalvm.nativeimage.Platform.WINDOWS;
30+
import org.graalvm.nativeimage.ImageSingletons;
3131

32+
import com.oracle.svm.core.dcmd.DcmdSupport;
33+
import com.oracle.svm.core.thread.ThreadDumpStacksDcmd;
3234
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3335
import com.oracle.svm.core.feature.InternalFeature;
34-
import com.oracle.svm.core.heap.VMOperationInfos;
3536
import com.oracle.svm.core.jdk.RuntimeSupport;
36-
import com.oracle.svm.core.log.Log;
37-
import com.oracle.svm.core.stack.JavaStackWalker;
38-
import com.oracle.svm.core.stack.ThreadStackPrinter.StackFramePrintVisitor;
39-
import com.oracle.svm.core.thread.JavaThreads;
40-
import com.oracle.svm.core.thread.JavaVMOperation;
41-
import com.oracle.svm.core.thread.PlatformThreads;
42-
import com.oracle.svm.core.thread.VMThreads;
4337

4438
import jdk.internal.misc.Signal;
4539

@@ -53,7 +47,11 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {
5347

5448
@Override
5549
public void beforeAnalysis(BeforeAnalysisAccess access) {
56-
RuntimeSupport.getRuntimeSupport().addStartupHook(new DumpThreadStacksOnSignalStartupHook());
50+
if (Platform.includedIn(WINDOWS.class) || !VMInspectionOptions.hasAttachSupport()) {
51+
RuntimeSupport.getRuntimeSupport().addStartupHook(new DumpThreadStacksOnSignalStartupHook());
52+
} else {
53+
ImageSingletons.lookup(DcmdSupport.class).registerDcmd(new ThreadDumpStacksDcmd());
54+
}
5755
}
5856
}
5957

@@ -73,55 +71,6 @@ static void install() {
7371

7472
@Override
7573
public void handle(Signal arg0) {
76-
DumpAllStacksOperation vmOp = new DumpAllStacksOperation();
77-
vmOp.enqueue();
78-
}
79-
80-
private static class DumpAllStacksOperation extends JavaVMOperation {
81-
DumpAllStacksOperation() {
82-
super(VMOperationInfos.get(DumpAllStacksOperation.class, "Dump all stacks", SystemEffect.SAFEPOINT));
83-
}
84-
85-
@Override
86-
protected void operate() {
87-
Log log = Log.log();
88-
log.string("Full thread dump:").newline().newline();
89-
for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) {
90-
if (vmThread == CurrentIsolate.getCurrentThread()) {
91-
/* Skip the signal handler stack */
92-
continue;
93-
}
94-
try {
95-
dumpStack(log, vmThread);
96-
} catch (Exception e) {
97-
log.string("Exception during dumpStack: ").string(e.getClass().getName()).newline();
98-
log.string(e.getMessage()).newline();
99-
}
100-
}
101-
log.flush();
102-
}
103-
104-
private static void dumpStack(Log log, IsolateThread vmThread) {
105-
Thread javaThread = PlatformThreads.fromVMThread(vmThread);
106-
if (javaThread != null) {
107-
log.character('"').string(javaThread.getName()).character('"');
108-
log.string(" #").signed(JavaThreads.getThreadId(javaThread));
109-
if (javaThread.isDaemon()) {
110-
log.string(" daemon");
111-
}
112-
} else {
113-
log.string("(no Java thread)");
114-
}
115-
log.string(" thread=").zhex(vmThread);
116-
if (javaThread != null) {
117-
log.string(" state=").string(javaThread.getState().name());
118-
}
119-
log.newline();
120-
121-
log.indent(true);
122-
StackFramePrintVisitor visitor = new StackFramePrintVisitor();
123-
JavaStackWalker.walkThread(vmThread, visitor, log);
124-
log.indent(false);
125-
}
74+
DumpThreadStacksSupport.dump();
12675
}
12776
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
27+
package com.oracle.svm.core;
28+
29+
import org.graalvm.nativeimage.CurrentIsolate;
30+
import org.graalvm.nativeimage.IsolateThread;
31+
32+
import com.oracle.svm.core.heap.VMOperationInfos;
33+
import com.oracle.svm.core.log.Log;
34+
import com.oracle.svm.core.stack.JavaStackWalker;
35+
import com.oracle.svm.core.stack.ThreadStackPrinter.StackFramePrintVisitor;
36+
import com.oracle.svm.core.thread.JavaThreads;
37+
import com.oracle.svm.core.thread.JavaVMOperation;
38+
import com.oracle.svm.core.thread.PlatformThreads;
39+
import com.oracle.svm.core.thread.VMThreads;
40+
41+
public class DumpThreadStacksSupport {
42+
public static void dump() {
43+
DumpAllStacksOperation vmOp = new DumpAllStacksOperation();
44+
vmOp.enqueue();
45+
}
46+
47+
private static class DumpAllStacksOperation extends JavaVMOperation {
48+
DumpAllStacksOperation() {
49+
super(VMOperationInfos.get(DumpAllStacksOperation.class, "Dump all stacks", SystemEffect.SAFEPOINT));
50+
}
51+
52+
@Override
53+
protected void operate() {
54+
Log log = Log.log();
55+
log.string("Full thread dump:").newline().newline();
56+
for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) {
57+
if (vmThread == CurrentIsolate.getCurrentThread()) {
58+
/* Skip the signal handler stack */
59+
continue;
60+
}
61+
try {
62+
dumpStack(log, vmThread);
63+
} catch (Exception e) {
64+
log.string("Exception during dumpStack: ").string(e.getClass().getName()).newline();
65+
log.string(e.getMessage()).newline();
66+
}
67+
}
68+
log.flush();
69+
}
70+
71+
private static void dumpStack(Log log, IsolateThread vmThread) {
72+
Thread javaThread = PlatformThreads.fromVMThread(vmThread);
73+
if (javaThread != null) {
74+
log.character('"').string(javaThread.getName()).character('"');
75+
log.string(" #").signed(JavaThreads.getThreadId(javaThread));
76+
if (javaThread.isDaemon()) {
77+
log.string(" daemon");
78+
}
79+
} else {
80+
log.string("(no Java thread)");
81+
}
82+
log.string(" thread=").zhex(vmThread);
83+
if (javaThread != null) {
84+
log.string(" state=").string(javaThread.getState().name());
85+
}
86+
log.newline();
87+
88+
log.indent(true);
89+
StackFramePrintVisitor visitor = new StackFramePrintVisitor();
90+
JavaStackWalker.walkThread(vmThread, visitor, log);
91+
log.indent(false);
92+
}
93+
}
94+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ public final class VMInspectionOptions {
6060
private static final String MONITORING_JMXSERVER_NAME = "jmxserver";
6161
private static final String MONITORING_THREADDUMP_NAME = "threaddump";
6262
private static final String MONITORING_NMT_NAME = "nmt";
63+
private static final String MONITORING_ATTACH_NAME = "attach";
6364

6465
private static final List<String> MONITORING_ALL_VALUES = List.of(MONITORING_HEAPDUMP_NAME, MONITORING_JFR_NAME, MONITORING_JVMSTAT_NAME, MONITORING_JMXCLIENT_NAME, MONITORING_JMXSERVER_NAME,
65-
MONITORING_THREADDUMP_NAME, MONITORING_NMT_NAME, MONITORING_ALL_NAME, MONITORING_DEFAULT_NAME);
66+
MONITORING_THREADDUMP_NAME, MONITORING_NMT_NAME, MONITORING_ATTACH_NAME, MONITORING_ALL_NAME, MONITORING_DEFAULT_NAME);
6667
private static final String MONITORING_ALLOWED_VALUES_TEXT = "'" + MONITORING_HEAPDUMP_NAME + "', '" + MONITORING_JFR_NAME + "', '" + MONITORING_JVMSTAT_NAME + "', '" + MONITORING_JMXSERVER_NAME +
67-
"' (experimental), '" + MONITORING_JMXCLIENT_NAME + "' (experimental), '" + MONITORING_THREADDUMP_NAME + "', '" + MONITORING_NMT_NAME + "' (experimental), or '" +
68+
"' (experimental), '" + MONITORING_JMXCLIENT_NAME + "' (experimental), '" + MONITORING_THREADDUMP_NAME + "', '" + MONITORING_NMT_NAME + "', '" + MONITORING_ATTACH_NAME +
69+
"' (experimental), or '" +
6870
MONITORING_ALL_NAME + "' (deprecated behavior: defaults to '" + MONITORING_ALL_NAME + "' if no argument is provided)";
6971

7072
static {
@@ -178,6 +180,11 @@ public static boolean hasNativeMemoryTrackingSupport() {
178180
return hasAllOrKeywordMonitoringSupport(MONITORING_NMT_NAME);
179181
}
180182

183+
@Fold
184+
public static boolean hasAttachSupport() {
185+
return hasAllOrKeywordMonitoringSupport(MONITORING_ATTACH_NAME) && !Platform.includedIn(WINDOWS.class);
186+
}
187+
181188
static class DeprecatedOptions {
182189
@Option(help = "Enables features that allow the VM to be inspected during run time.", type = OptionType.User, //
183190
deprecated = true, deprecationMessage = "Please use '--" + ENABLE_MONITORING_OPTION + "'") //

0 commit comments

Comments
 (0)