Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 44cde4a

Browse files
authored
Merge pull request eclipse-openj9#7240 from JasonFengJ9/jstat-1
Jstat initial implementation
2 parents efea766 + f85c98b commit 44cde4a

File tree

14 files changed

+395
-37
lines changed

14 files changed

+395
-37
lines changed

jcl/src/java.base/share/classes/module-info.java.extra

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ exports com.ibm.oti.vm to java.management, jdk.attach, jdk.management, openj9.jv
3131
exports com.ibm.oti.util to java.management, jdk.attach, jdk.jcmd, jdk.management, openj9.sharedclasses;
3232
exports openj9.internal.tools.attach.target to jdk.attach, jdk.jcmd, jdk.management;
3333
exports openj9.management.internal to java.management, openj9.jvm;
34+
exports openj9.internal.management to java.management;
3435
exports jdk.internal.org.objectweb.asm to openj9.dtfj, openj9.dtfjview;
3536
// Following allows dtfj/dtfjview modules invoke module addReads & addExports programmatically via reflection APIs
3637
exports jdk.internal.module to openj9.dtfj, openj9.dtfjview;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*[INCLUDE-IF Sidecar18-SE]*/
2+
/*******************************************************************************
3+
* Copyright (c) 2019, 2019 IBM Corp. and others
4+
*
5+
* This program and the accompanying materials are made available under
6+
* the terms of the Eclipse Public License 2.0 which accompanies this
7+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8+
* or the Apache License, Version 2.0 which accompanies this distribution and
9+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10+
*
11+
* This Source Code may also be made available under the following
12+
* Secondary Licenses when the conditions for such availability set
13+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14+
* General Public License, version 2 with the GNU Classpath
15+
* Exception [1] and GNU General Public License, version 2 with the
16+
* OpenJDK Assembly Exception [2].
17+
*
18+
* [1] https://www.gnu.org/software/classpath/license.html
19+
* [2] http://openjdk.java.net/legal/assembly-exception.html
20+
*
21+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
22+
*******************************************************************************/
23+
package openj9.internal.management;
24+
25+
/**
26+
* Container for classloader information.
27+
*/
28+
public class ClassLoaderInfoBaseImpl {
29+
/**
30+
* @return the number of loaded classes
31+
*/
32+
public static native long getLoadedClassCountImpl();
33+
34+
/**
35+
* @return the number of unloaded classes
36+
*/
37+
public static native long getUnloadedClassCountImpl();
38+
}

jcl/src/java.base/share/classes/openj9/internal/tools/attach/target/DiagnosticUtils.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
import java.util.HashMap;
3030
import java.util.Map;
3131
import java.util.function.Function;
32-
import java.util.function.Predicate;
3332

3433
import com.ibm.oti.vm.VM;
3534

35+
import openj9.internal.management.ClassLoaderInfoBaseImpl;
3636
import openj9.management.internal.InvalidDumpOptionExceptionBase;
3737
import openj9.management.internal.LockInfoBase;
3838
import openj9.management.internal.ThreadInfoBase;
@@ -84,6 +84,11 @@ public class DiagnosticUtils {
8484
private static final String DIAGNOSTICS_DUMP_SNAP = "Dump.snap"; //$NON-NLS-1$
8585
private static final String DIAGNOSTICS_DUMP_SYSTEM = "Dump.system"; //$NON-NLS-1$
8686

87+
/**
88+
* Get JVM statistics
89+
*/
90+
private static final String DIAGNOSTICS_STAT_CLASS = "jstat.class"; //$NON-NLS-1$
91+
8792
/**
8893
* Key for the command sent to executeDiagnosticCommand()
8994
*/
@@ -288,6 +293,19 @@ private static DiagnosticProperties runGC() {
288293
return DiagnosticProperties.makeCommandSucceeded();
289294
}
290295

296+
private static DiagnosticProperties getJstatClass(String diagnosticCommand) {
297+
IPC.logMessage("jstat command : ", diagnosticCommand); //$NON-NLS-1$
298+
StringWriter buffer = new StringWriter(100);
299+
PrintWriter bufferPrinter = new PrintWriter(buffer);
300+
bufferPrinter.println("Class Loaded Class Unloaded"); //$NON-NLS-1$
301+
// "Class Loaded".length = 12, "Class Unloaded".length = 14
302+
bufferPrinter.printf("%12d %14d%n", //$NON-NLS-1$
303+
Long.valueOf(ClassLoaderInfoBaseImpl.getLoadedClassCountImpl()),
304+
Long.valueOf(ClassLoaderInfoBaseImpl.getUnloadedClassCountImpl()));
305+
bufferPrinter.flush();
306+
return DiagnosticProperties.makeStringResult(buffer.toString());
307+
}
308+
291309
private static DiagnosticProperties doHelp(String diagnosticCommand) {
292310
String[] parts = diagnosticCommand.split(DIAGNOSTICS_OPTION_SEPARATOR);
293311
/* print a list of the available commands */
@@ -346,6 +364,10 @@ private static DiagnosticProperties doHelp(String diagnosticCommand) {
346364
private static final String DIAGNOSTICS_DUMP_SYSTEM_HELP = "Create a native core file.%n" //$NON-NLS-1$
347365
+ FORMAT_PREFIX + DIAGNOSTICS_DUMP_SYSTEM + FILE_PATH_HELP;
348366

367+
private static final String DIAGNOSTICS_JSTAT_CLASS_HELP = "Show JVM classloader statistics.%n" //$NON-NLS-1$
368+
+ FORMAT_PREFIX + DIAGNOSTICS_STAT_CLASS + "%n" //$NON-NLS-1$
369+
+ "NOTE: this utility may significantly affect the performance of the target VM.%n"; //$NON-NLS-1$
370+
349371
/* Initialize the command and help text tables */
350372
static {
351373
commandTable = new HashMap<>();
@@ -377,6 +399,8 @@ private static DiagnosticProperties doHelp(String diagnosticCommand) {
377399

378400
commandTable.put(DIAGNOSTICS_DUMP_SYSTEM, DiagnosticUtils::doDump);
379401
helpTable.put(DIAGNOSTICS_DUMP_SYSTEM, DIAGNOSTICS_DUMP_SYSTEM_HELP);
402+
403+
commandTable.put(DIAGNOSTICS_STAT_CLASS, DiagnosticUtils::getJstatClass);
404+
helpTable.put(DIAGNOSTICS_STAT_CLASS, DIAGNOSTICS_JSTAT_CLASS_HELP);
380405
}
381-
382406
}

jcl/src/java.management/share/classes/com/ibm/java/lang/management/internal/ClassLoadingMXBeanImpl.java

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*[INCLUDE-IF Sidecar17]*/
1+
/*[INCLUDE-IF Sidecar18-SE]*/
22
/*******************************************************************************
33
* Copyright (c) 2005, 2019 IBM Corp. and others
44
*
@@ -27,6 +27,8 @@
2727

2828
import javax.management.ObjectName;
2929

30+
import openj9.internal.management.ClassLoaderInfoBaseImpl;
31+
3032
/**
3133
* Runtime type for {@link ClassLoadingMXBean}.
3234
* <p>
@@ -60,18 +62,12 @@ public static ClassLoadingMXBeanImpl getInstance() {
6062
return instance;
6163
}
6264

63-
/**
64-
* @return the number of loaded classes
65-
* @see #getLoadedClassCount()
66-
*/
67-
private native int getLoadedClassCountImpl();
68-
6965
/**
7066
* {@inheritDoc}
7167
*/
7268
@Override
7369
public int getLoadedClassCount() {
74-
return this.getLoadedClassCountImpl();
70+
return (int)ClassLoaderInfoBaseImpl.getLoadedClassCountImpl();
7571
}
7672

7773
/**
@@ -88,18 +84,12 @@ public long getTotalLoadedClassCount() {
8884
return this.getTotalLoadedClassCountImpl();
8985
}
9086

91-
/**
92-
* @return the total number of unloaded classes
93-
* @see #getUnloadedClassCount()
94-
*/
95-
private native long getUnloadedClassCountImpl();
96-
9787
/**
9888
* {@inheritDoc}
9989
*/
10090
@Override
10191
public long getUnloadedClassCount() {
102-
return this.getUnloadedClassCountImpl();
92+
return ClassLoaderInfoBaseImpl.getUnloadedClassCountImpl();
10393
}
10494

10595
/**
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*[INCLUDE-IF Sidecar18-SE]*/
2+
/*******************************************************************************
3+
* Copyright (c) 2019, 2019 IBM Corp. and others
4+
*
5+
* This program and the accompanying materials are made available under
6+
* the terms of the Eclipse Public License 2.0 which accompanies this
7+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8+
* or the Apache License, Version 2.0 which accompanies this distribution and
9+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10+
*
11+
* This Source Code may also be made available under the following
12+
* Secondary Licenses when the conditions for such availability set
13+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14+
* General Public License, version 2 with the GNU Classpath
15+
* Exception [1] and GNU General Public License, version 2 with the
16+
* OpenJDK Assembly Exception [2].
17+
*
18+
* [1] https://www.gnu.org/software/classpath/license.html
19+
* [2] http://openjdk.java.net/legal/assembly-exception.html
20+
*
21+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
22+
*******************************************************************************/
23+
24+
package openj9.tools.attach.diagnostics.tools;
25+
26+
import java.io.IOException;
27+
28+
import openj9.internal.tools.attach.target.AttachHandler;
29+
import openj9.internal.tools.attach.target.DiagnosticProperties;
30+
import openj9.internal.tools.attach.target.IPC;
31+
import openj9.tools.attach.diagnostics.attacher.AttacherDiagnosticsProvider;
32+
33+
/**
34+
* JStat A tool for statistics monitoring of another Java process
35+
*
36+
*/
37+
@SuppressWarnings("nls")
38+
public class Jstat {
39+
40+
private static String vmid;
41+
private static String statOption;
42+
43+
private static final String OPTION_CLASS = "-class";
44+
private static final String[] OPTIONS = { OPTION_CLASS };
45+
46+
private static final String ERROR_AN_ARG_REQUIRED = "An argument is required";
47+
private static final String ERROR_INVALID_ARG = "An invalid argument";
48+
private static final String ERROR_INVALID_OPTION = "An invalid option";
49+
private static final String ERROR_INVALID_VMID = "Can't monitor this utility JVM itself: ";
50+
private static final String ERROR_NOT_EXIST_VMID = "No such process for vmid: ";
51+
private static final String ERROR_OPTION_REQUIRED = "An <option> is required";
52+
private static final String ERROR_VMID_REQUIRED = "A <vmid> is required";
53+
54+
private static String HELPTEXT = "jstat: obtain statistics information about a Java process%n"
55+
+ " Usage:%n"
56+
+ " jstat [<option>] [<vmid>]%n"
57+
+ "%n"
58+
+ " option:%n"
59+
+ " -J : supply arguments to the Java VM running jstat%n"
60+
+ " -h : print this help message%n"
61+
+ " -options : list the available command options%n"
62+
+ " -class : Classloading statistics%n"
63+
+ " <vmid>: Attach API VM ID as shown in jps or other Attach API-based tools%n"
64+
+ "NOTE: this utility may significantly affect the performance of the target VM.%n"
65+
+ "At least one option must be selected.%n";
66+
67+
/**
68+
* Print a list of Java processes and information about them.
69+
*
70+
* @param args
71+
* Arguments to the application
72+
*/
73+
public static void main(String[] args) {
74+
if (parseArguments(args)) {
75+
if (vmid == null || vmid.isEmpty()) {
76+
// no valid vmid supplied, print error message and help text, and exit
77+
Util.exitJVMWithReasonAndHelp(ERROR_VMID_REQUIRED, HELPTEXT);
78+
}
79+
80+
AttacherDiagnosticsProvider diagProvider = new AttacherDiagnosticsProvider();
81+
String myId = AttachHandler.getVmId();
82+
83+
if (vmid.equals(myId)) {
84+
// this utility doesn't monitor itself, print error message and help text, and exit
85+
Util.exitJVMWithReasonAndHelp(ERROR_INVALID_VMID + vmid, HELPTEXT);
86+
}
87+
88+
// if the ID looks like a process ID, check if it is running
89+
if (vmid.matches("\\d+")) {
90+
if (!IPC.processExists(Long.parseLong(vmid))) {
91+
Util.exitJVMWithReasonAndHelp(ERROR_NOT_EXIST_VMID + vmid, HELPTEXT);
92+
}
93+
}
94+
95+
try {
96+
diagProvider.attach(vmid);
97+
Util.runCommandAndPrintResult(diagProvider, statOption, "jstat");
98+
} catch (Exception e) {
99+
System.err.printf("Error getting data from %s", vmid);
100+
final String msg = e.getMessage();
101+
if (msg == null) {
102+
System.err.println();
103+
} else {
104+
if (msg.matches(IPC.INCOMPATIBLE_JAVA_VERSION)) {
105+
System.err.println(": incompatible target JVM");
106+
} else {
107+
System.err.printf(": %s%n", msg);
108+
}
109+
}
110+
if (DiagnosticProperties.isDebug) {
111+
e.printStackTrace();
112+
}
113+
} finally {
114+
try {
115+
diagProvider.detach();
116+
} catch (IOException e) {
117+
// ignore
118+
}
119+
}
120+
}
121+
}
122+
123+
private static boolean parseArguments(String[] args) {
124+
boolean foundStatOption = false;
125+
126+
if ((args == null) || (args.length == 0)) {
127+
// no argument supplied, print error message and help text, and exit
128+
Util.exitJVMWithReasonAndHelp(ERROR_AN_ARG_REQUIRED, HELPTEXT);
129+
} else if (Util.checkHelpOption(args[0])) {
130+
// Help argument is supplied, print help text
131+
System.out.printf(HELPTEXT);
132+
} else if ("-options".equals(args[0])) {
133+
if (args.length > 1) {
134+
// there are more arguments after -options, print error message and help text, and exit
135+
Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT);
136+
}
137+
// print options available
138+
for (String option : OPTIONS) {
139+
System.out.println(option);
140+
}
141+
} else {
142+
for (String arg : args) {
143+
if (arg.startsWith("-")) {
144+
if (statOption != null) {
145+
// one option has already been set, print error message and help text, and exit
146+
Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT);
147+
} else {
148+
foundStatOption = true;
149+
switch (arg) {
150+
case OPTION_CLASS:
151+
statOption = "jstat.class";
152+
break;
153+
default:
154+
// invalid option was specified, print error message and help text, and exit
155+
Util.exitJVMWithReasonAndHelp(ERROR_INVALID_OPTION, HELPTEXT);
156+
}
157+
}
158+
} else {
159+
if (statOption == null) {
160+
// no option was specified, print error message and help text, and exit
161+
Util.exitJVMWithReasonAndHelp(ERROR_OPTION_REQUIRED, HELPTEXT);
162+
} else if (vmid != null) {
163+
// one vmid has already been set, print error message and help text, and exit
164+
Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT);
165+
} else {
166+
vmid = arg;
167+
}
168+
}
169+
}
170+
}
171+
172+
return foundStatOption;
173+
}
174+
}

jcl/src/jdk.jcmd/share/classes/openj9/tools/attach/diagnostics/tools/Util.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.io.InputStream;
3030
import java.io.InputStreamReader;
3131
import java.io.PrintStream;
32+
import java.util.Arrays;
3233
import java.util.Collections;
3334
import java.util.List;
3435
import java.util.Map.Entry;
@@ -153,4 +154,35 @@ static void printProperties(PrintStream out, Properties props) {
153154
}
154155
}
155156

157+
/**
158+
* Print an error message if it is not null or empty.
159+
* Print the help content.
160+
* Terminates JVM.
161+
*
162+
* @param error
163+
* an error message to indicate the cause of the error
164+
* @param help
165+
* the help showing the utility usages
166+
*/
167+
static void exitJVMWithReasonAndHelp(String error, String help) {
168+
if ((error != null) && (!error.isEmpty())) {
169+
System.out.println(error);
170+
}
171+
System.out.printf(help);
172+
System.exit(1);
173+
}
174+
175+
@SuppressWarnings("nls")
176+
private static final String[] HELP_OPTIONS = { "-h", "help", "-help", "--help" };
177+
178+
/**
179+
* Check if the option matches one of HELP_OPTIONS
180+
*
181+
* @param option
182+
* the option to be checked
183+
* @return true if found a match, otherwise false
184+
*/
185+
static boolean checkHelpOption(String option) {
186+
return Arrays.stream(HELP_OPTIONS).anyMatch(option::equalsIgnoreCase);
187+
}
156188
}

0 commit comments

Comments
 (0)