/* * Copyright (c) 2007, 2011, 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. Oracle 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. * * 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 com.sun.tools.visualvm.tools.jvmstat; import com.sun.tools.visualvm.application.Application; import com.sun.tools.visualvm.core.model.Model; import com.sun.tools.visualvm.host.Host; import java.io.File; import java.io.IOException; import java.util.List; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.logging.Logger; import org.openide.util.NbBundle; /** * * This class encapsulates information available via Jvmstat counters. * It is preferred to use this class to get access to java home, * total loaded classes, number of running threads etc. The advantage is * that user code does not depend on particular counter name, which can be * different for different JVM. * @author Tomas Hurka */ public abstract class JvmJvmstatModel extends Model { private static final Logger LOGGER = Logger.getLogger(JvmJvmstatModel.class.getName()); private static final String JAR_SUFFIX = ".jar"; // NOI18N protected Application application; protected JvmstatModel jvmstat; protected MonitoredValue loadedClasses; protected MonitoredValue sharedLoadedClasses; protected MonitoredValue sharedUnloadedClasses; protected MonitoredValue unloadedClasses; protected MonitoredValue threadsDaemon; protected MonitoredValue threadsLive; protected MonitoredValue threadsLivePeak; protected MonitoredValue threadsStarted; protected MonitoredValue applicationTime; protected MonitoredValue upTime; protected long osFrequency; protected String[] genName; protected List<MonitoredValue> genCapacity; protected List<MonitoredValue> genUsed; protected long[] genMaxCapacity; protected JvmJvmstatModel(Application app,JvmstatModel stat) { application = app; jvmstat = stat; genName = new String[2]; genName[0] = NbBundle.getMessage(JvmJvmstatModel.class, "LBL_Heap"); // NOI18N genName[1] = NbBundle.getMessage(JvmJvmstatModel.class, "LBL_PermGen"); // NOI18N } /** * Returns the Java virtual machine command line. * * @return String - contains the command line of the target Java * application or <CODE>NULL</CODE> if the * command line cannot be determined. */ public String getCommandLine() { return jvmstat.findByName("sun.rt.javaCommand"); // NOI18N } /** * Returns the Java virtual machine command line arguments. * * @return String - contains the command line arguments of the target Java * application or <CODE>NULL</CODE> if the * command line arguments cannot be determined. */ public String getJvmArgs() { return jvmstat.findByName("java.rt.vmArgs"); // NOI18N } /** * Returns the Java virtual machine flags. * * @return String - contains the flags of the target Java * application or <CODE>NULL</CODE> if the * flags be determined. */ public String getJvmFlags() { return jvmstat.findByName("java.rt.vmFlags"); // NOI18N } /** * Returns the Java virtual machine home directory. * This method is equivalent to {@link System#getProperty * System.getProperty("java.home")}. * * @return the Java virtual machine home directory. * * @see java.lang.System#getProperty */ public String getJavaHome() { return jvmstat.findByName("java.property.java.home"); // NOI18N } /** * Returns the Java virtual machine VM info. * This method is equivalent to {@link System#getProperty * System.getProperty("java.vm.info")}. * * @return the Java virtual machine VM info. * * @see java.lang.System#getProperty */ public String getVmInfo() { return jvmstat.findByName("java.property.java.vm.info"); // NOI18N } /** * Returns the Java virtual machine implementation name. * This method is equivalent to {@link System#getProperty * System.getProperty("java.vm.name")}. * * @return the Java virtual machine implementation name. * * @see java.lang.System#getProperty */ public String getVmName() { return jvmstat.findByName("java.property.java.vm.name"); // NOI18N } /** * Returns the Java virtual machine implementation version. * This method is equivalent to {@link System#getProperty * System.getProperty("java.vm.version")}. * * @return the Java virtual machine implementation version. * * @see java.lang.System#getProperty */ public String getVmVersion() { return jvmstat.findByName("java.property.java.vm.version"); // NOI18N } /** * Returns the Java virtual machine implementation version. * This method is equivalent to {@link System#getProperty * System.getProperty("java.vm.vendor")}. * * @return the Java virtual machine vendor. * * @see java.lang.System#getProperty */ public String getVmVendor() { return jvmstat.findByName("java.property.java.vm.vendor"); // NOI18N } /** * Returns the Java virtual machine implementation version. * This method is equivalent to {@link System#getProperty * System.getProperty("java.class.path")}. * * @return the Java virtual machine classpath. * * @see java.lang.System#getProperty */ public String getClassPath() { return jvmstat.findByName("java.property.java.class.path"); // NOI18N } /** * Tests if target JVM supports * <a href=http://download.oracle.com/javase/6/docs/technotes/guides/attach/index.html>Attach API</a> * and that support is enabled in target JVM. * @return <CODE>true</CODE> if JVM supports Attach API, <CODE>false</CODE> otherwise */ public boolean isAttachable() { String jvmCapabilities = jvmstat.findByName("sun.rt.jvmCapabilities"); // NOI18N if (jvmCapabilities == null) { return false; } return jvmCapabilities.charAt(0) == '1'; } /** * Return the arguments to the main class for the target Java application. * Returns the arguments to the main class. If the arguments can't be * found, <code>null</code> is returned. * * @return String - contains the arguments to the main class for the * target Java application or the <code>null</code> * if the command line cannot be determined. */ public String getMainArgs() { String commandLine = getCommandLine(); String arg0 = getFirstArgument(); int firstSpace = arg0.length(); if (firstSpace < commandLine.length()) { return commandLine.substring(firstSpace); } return null; } /** * Return the main class for the target Java application. * Returns the main class, if the application started with the <em>-jar</em> option, * it tries to determine main class from the jar file. If * the jar file is not accessible, the main class is simple * name of the jar file. * @return String - the main class of the target Java * application. */ public String getMainClass() { String mainClassName = getFirstArgument(); // if we are on localhost try read main class from jar file if (application.getHost().equals(Host.LOCALHOST)) { File jarFile = new File(mainClassName); if (jarFile.exists()) { try { JarFile jf = new JarFile(jarFile); mainClassName = jf.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS); assert mainClassName!=null; } catch (IOException ex) { LOGGER.throwing(JvmJvmstatModel.class.getName(), "getMainClass", ex); // NOI18N } } } if (mainClassName.endsWith(JAR_SUFFIX)) { mainClassName = mainClassName.replace('\\', '/'); int index = mainClassName.lastIndexOf('/'); if (index != -1) { mainClassName = mainClassName.substring(index + 1); } } mainClassName = mainClassName.replace('\\', '/').replace('/', '.'); return mainClassName; } private String getFirstArgument() { String commandLine = getCommandLine(); String mainClassName = null; // search for jar file int jarIndex = commandLine.indexOf(JAR_SUFFIX); if (jarIndex != -1) { String jarFile = commandLine.substring(0,jarIndex+JAR_SUFFIX.length()); // if this is not end of commandLine check that jar file is separated by space from other arguments if (jarFile.length() == commandLine.length() || commandLine.charAt(jarFile.length()) == ' ') { // jarFile must be on classpath String classPath = getClassPath(); if (classPath != null && classPath.indexOf(jarFile) != -1) { mainClassName = jarFile; } } } // it looks like ordinary commandline with main class if (mainClassName == null) { int firstSpace = commandLine.indexOf(' '); if (firstSpace > 0) { mainClassName = commandLine.substring(0, firstSpace); } else { mainClassName = commandLine; } } return mainClassName; } /** * Returns the total number of classes that have been loaded since * the Java virtual machine has started execution. * * @return the total number of classes loaded. * */ public long getLoadedClasses() { return getLongValue(loadedClasses); } /** * Returns the total number of shared classes that have been loaded since * the Java virtual machine has started execution. * * @return the total number of shared classes loaded. * */ public long getSharedLoadedClasses() { return getLongValue(sharedLoadedClasses); } /** * Returns the total number of shared classes unloaded since the Java virtual machine * has started execution. * * @return the total number of unloaded shared classes. */ public long getSharedUnloadedClasses() { return getLongValue(sharedUnloadedClasses); } /** * Returns the total number of classes unloaded since the Java virtual machine * has started execution. * * @return the total number of unloaded classes. */ public long getUnloadedClasses() { return getLongValue(unloadedClasses); } /** * Returns the current number of live daemon threads. * * @return the current number of live daemon threads. */ public long getThreadsDaemon() { return getLongValue(threadsDaemon); } /** * Returns the current number of live threads including both * daemon and non-daemon threads. * * @return the current number of live threads. */ public long getThreadsLive() { return getLongValue(threadsLive); } /** * Returns the peak live thread count since the Java virtual machine * started or peak was reset. * * @return the peak live thread count. */ public long getThreadsLivePeak() { return getLongValue(threadsLivePeak); } /** * Returns the total number of threads created and also started * since the Java virtual machine started. * * @return the total number of threads started. */ public long getThreadsStarted() { return getLongValue(threadsStarted); } /** * Returns the total time of when application is running in OS ticks. * Application time is the uptime minus time spent in safe points. * Note that this value is updated only at the beginning and e * @return application time of the Java virtual machine in OS ticks. * @see JvmJvmstatModel#getOsFrequency() */ public long getApplicationTime() { return getLongValue(applicationTime); } /** * Returns the uptime of the Java virtual machine in OS ticks. * @return uptime of the Java virtual machine in OS ticks. * @see JvmJvmstatModel#getOsFrequency() */ public long getUpTime() { return getLongValue(upTime); } /** * Returns the names of Java virtual machine spaces. * * @return Index 0 is the display name for heap, * index 1 is display name for Permanent Generation (PermGen) * * @since VisualVM 1.3.6 */ public String[] getGenName() { return genName.clone(); } /** * Returns the amount of memory in bytes that is committed for * the Java virtual machine to use. This amount of memory is * guaranteed for the Java virtual machine to use. * * @return long[0] - the amount of committed heap memory in bytes. * long[1] - the amount of committed Perm Gen memory in bytes. * */ public long[] getGenCapacity() { return getGenerationSum(genCapacity); } /** * Returns the amount of used memory in bytes. * * @return long[0] - the amount of used heap memory in bytes. * long[1] - the amount of used Perm Gen memory in bytes. * */ public long[] getGenUsed() { return getGenerationSum(genUsed); } /** * Returns the maximum amount of memory in bytes that can be * used for memory management. This method returns <tt>-1</tt> * if the maximum memory size is undefined. * * @return long[0] - the maximum amount of heap memory in bytes; * long[1] - the maximum amount of Perm Gen memory in bytes; */ public long[] getGenMaxCapacity() { return genMaxCapacity.clone(); } /** * Returns the number of OS ticks per second. * * @return number of OS ticks per second. */ public long getOsFrequency() { return osFrequency; } protected abstract String getPermGenPrefix(); protected long getLongValue(MonitoredValue val) { if (val != null) { return ((Long)val.getValue()).longValue(); } return 0; } protected long[] getGenerationSum(List<MonitoredValue> values) { long[] results=new long[2]; String prefix = getPermGenPrefix(); for (MonitoredValue value : values) { if (value != null) { long val = ((Long)value.getValue()).longValue(); if (value.getName().startsWith(prefix)) { results[1]+= val; } else { results[0]+= val; } } } return results; } }