--- old/makefiles/lib/ServiceabilityLibraries.gmk Thu Nov 7 12:13:57 2013 +++ new/makefiles/lib/ServiceabilityLibraries.gmk Thu Nov 7 12:13:57 2013 @@ -275,19 +275,12 @@ ########################################################################################## BUILD_LIBMANAGEMENT_SRC := $(JDK_TOPDIR)/src/share/native/sun/management \ - $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/management \ - $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/com/sun/management + $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/management BUILD_LIBMANAGEMENT_EXCLUDES := BUILD_LIBMANAGEMENT_CFLAGS := -I$(JDK_TOPDIR)/src/share/native/sun/management -ifneq ($(OPENJDK_TARGET_OS), windows) - BUILD_LIBMANAGEMENT_EXCLUDES += OperatingSystem_md.c -else - BUILD_LIBMANAGEMENT_EXCLUDES += UnixOperatingSystem_md.c -endif - ifneq ($(OPENJDK_TARGET_OS), solaris) BUILD_LIBMANAGEMENT_EXCLUDES += SolarisOperatingSystem.c endif --- old/makefiles/mapfiles/libmanagement/mapfile-vers Thu Nov 7 12:13:59 2013 +++ new/makefiles/mapfiles/libmanagement/mapfile-vers Thu Nov 7 12:13:58 2013 @@ -27,17 +27,17 @@ SUNWprivate_1.1 { global: - Java_com_sun_management_UnixOperatingSystem_getCommittedVirtualMemorySize; - Java_com_sun_management_UnixOperatingSystem_getFreePhysicalMemorySize; - Java_com_sun_management_UnixOperatingSystem_getFreeSwapSpaceSize; - Java_com_sun_management_UnixOperatingSystem_getMaxFileDescriptorCount; - Java_com_sun_management_UnixOperatingSystem_getOpenFileDescriptorCount; - Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad; - Java_com_sun_management_UnixOperatingSystem_getProcessCpuTime; - Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad; - Java_com_sun_management_UnixOperatingSystem_getTotalPhysicalMemorySize; - Java_com_sun_management_UnixOperatingSystem_getTotalSwapSpaceSize; - Java_com_sun_management_UnixOperatingSystem_initialize; + Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize; + Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize; + Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize; + Java_sun_management_OperatingSystemImpl_getMaxFileDescriptorCount; + Java_sun_management_OperatingSystemImpl_getOpenFileDescriptorCount; + Java_sun_management_OperatingSystemImpl_getProcessCpuLoad; + Java_sun_management_OperatingSystemImpl_getProcessCpuTime; + Java_sun_management_OperatingSystemImpl_getSystemCpuLoad; + Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize; + Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize; + Java_sun_management_OperatingSystemImpl_initialize; Java_sun_management_ClassLoadingImpl_setVerboseClass; Java_sun_management_DiagnosticCommandImpl_executeDiagnosticCommand; Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommands; --- old/src/share/classes/sun/management/ManagementFactoryHelper.java Thu Nov 7 12:14:00 2013 +++ new/src/share/classes/sun/management/ManagementFactoryHelper.java Thu Nov 7 12:13:59 2013 @@ -46,7 +46,6 @@ import java.util.HashMap; import java.util.List; import com.sun.management.DiagnosticCommandMBean; -import com.sun.management.OSMBeanFactory; import com.sun.management.HotSpotDiagnosticMXBean; import static java.lang.management.ManagementFactory.*; @@ -104,8 +103,7 @@ public static synchronized OperatingSystemMXBean getOperatingSystemMXBean() { if (osMBean == null) { - osMBean = (OperatingSystemImpl) - OSMBeanFactory.getOperatingSystemMXBean(jvm); + osMBean = new OperatingSystemImpl(jvm); } return osMBean; } --- old/src/share/classes/sun/management/OperatingSystemImpl.java Thu Nov 7 12:14:01 2013 +++ /dev/null Thu Nov 7 12:14:01 2013 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2003, 2008, 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 sun.management; - -import java.lang.management.OperatingSystemMXBean; -import java.lang.management.ManagementFactory; -import javax.management.ObjectName; -import sun.misc.Unsafe; - -/** - * Implementation class for the operating system. - * Standard and committed hotspot-specific metrics if any. - * - * ManagementFactory.getOperatingSystemMXBean() returns an instance - * of this class. - */ -public class OperatingSystemImpl implements OperatingSystemMXBean { - - private final VMManagement jvm; - - /** - * Constructor of OperatingSystemImpl class. - */ - protected OperatingSystemImpl(VMManagement vm) { - this.jvm = vm; - } - - public String getName() { - return jvm.getOsName(); - } - - public String getArch() { - return jvm.getOsArch(); - } - - public String getVersion() { - return jvm.getOsVersion(); - } - - public int getAvailableProcessors() { - return jvm.getAvailableProcessors(); - } - - private static final Unsafe unsafe = Unsafe.getUnsafe(); - private double[] loadavg = new double[1]; - public double getSystemLoadAverage() { - if (unsafe.getLoadAverage(loadavg, 1) == 1) { - return loadavg[0]; - } else { - return -1.0; - } - } - public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); - } - -} --- /dev/null Thu Nov 7 12:14:01 2013 +++ new/src/share/classes/sun/management/AbstractOperatingSystemImpl.java Thu Nov 7 12:14:01 2013 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003, 2008, 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 sun.management; + +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; +import javax.management.ObjectName; +import sun.misc.Unsafe; + +/** + * Implementation class for the operating system. + * Standard and committed hotspot-specific metrics if any. + * + * ManagementFactory.getOperatingSystemMXBean() returns an instance + * of this class. + */ +public class AbstractOperatingSystemImpl implements OperatingSystemMXBean { + + private final VMManagement jvm; + + /** + * Constructor of AbstractOperatingSystemImpl class. + */ + protected AbstractOperatingSystemImpl(VMManagement vm) { + this.jvm = vm; + } + + public String getName() { + return jvm.getOsName(); + } + + public String getArch() { + return jvm.getOsArch(); + } + + public String getVersion() { + return jvm.getOsVersion(); + } + + public int getAvailableProcessors() { + return jvm.getAvailableProcessors(); + } + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private double[] loadavg = new double[1]; + public double getSystemLoadAverage() { + if (unsafe.getLoadAverage(loadavg, 1) == 1) { + return loadavg[0]; + } else { + return -1.0; + } + } + public ObjectName getObjectName() { + return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); + } + +} --- old/src/solaris/classes/com/sun/management/UnixOperatingSystem.java Thu Nov 7 12:14:02 2013 +++ /dev/null Thu Nov 7 12:14:02 2013 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2003, 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.management; - -import sun.management.VMManagement; - -/** - * Implementation class for the operating system. - * Standard and committed hotspot-specific metrics if any. - * - * ManagementFactory.getOperatingSystemMXBean() returns an instance - * of this class. - */ -class UnixOperatingSystem - extends sun.management.OperatingSystemImpl - implements UnixOperatingSystemMXBean { - - UnixOperatingSystem(VMManagement vm) { - super(vm); - } - - public native long getCommittedVirtualMemorySize(); - public native long getTotalSwapSpaceSize(); - public native long getFreeSwapSpaceSize(); - public native long getProcessCpuTime(); - public native long getFreePhysicalMemorySize(); - public native long getTotalPhysicalMemorySize(); - public native long getOpenFileDescriptorCount(); - public native long getMaxFileDescriptorCount(); - public native double getSystemCpuLoad(); - public native double getProcessCpuLoad(); - - static { - initialize(); - } - private static native void initialize(); -} --- /dev/null Thu Nov 7 12:14:02 2013 +++ new/src/solaris/classes/sun/management/OperatingSystemImpl.java Thu Nov 7 12:14:02 2013 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003, 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 sun.management; + +/** + * Implementation class for the operating system. + * Standard and committed hotspot-specific metrics if any. + * + * ManagementFactory.getOperatingSystemMXBean() returns an instance + * of this class. + */ +class OperatingSystemImpl extends AbstractOperatingSystemImpl + implements com.sun.management.UnixOperatingSystemMXBean { + + OperatingSystemImpl(VMManagement vm) { + super(vm); + } + + public native long getCommittedVirtualMemorySize(); + public native long getTotalSwapSpaceSize(); + public native long getFreeSwapSpaceSize(); + public native long getProcessCpuTime(); + public native long getFreePhysicalMemorySize(); + public native long getTotalPhysicalMemorySize(); + public native long getOpenFileDescriptorCount(); + public native long getMaxFileDescriptorCount(); + public native double getSystemCpuLoad(); + public native double getProcessCpuLoad(); + + static { + initialize(); + } + private static native void initialize(); +} --- old/src/solaris/native/com/sun/management/LinuxOperatingSystem.c Thu Nov 7 12:14:03 2013 +++ /dev/null Thu Nov 7 12:14:03 2013 @@ -1,332 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "com_sun_management_UnixOperatingSystem.h" - -struct ticks { - uint64_t used; - uint64_t usedKernel; - uint64_t total; -}; - -typedef struct ticks ticks; - -typedef enum { - CPU_LOAD_VM_ONLY, - CPU_LOAD_GLOBAL, -} CpuLoadTarget; - -static struct perfbuf { - int nProcs; - ticks jvmTicks; - ticks cpuTicks; - ticks *cpus; -} counters; - -#define DEC_64 "%lld" - -static void next_line(FILE *f) { - while (fgetc(f) != '\n'); -} - -/** - * Return the total number of ticks since the system was booted. - * If the usedTicks parameter is not NULL, it will be filled with - * the number of ticks spent on actual processes (user, system or - * nice processes) since system boot. Note that this is the total number - * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is - * n times the number of ticks that has passed in clock time. - * - * Returns a negative value if the reading of the ticks failed. - */ -static int get_totalticks(int which, ticks *pticks) { - FILE *fh; - uint64_t userTicks, niceTicks, systemTicks, idleTicks; - int n; - - if((fh = fopen("/proc/stat", "r")) == NULL) { - return -1; - } - - n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, - &userTicks, &niceTicks, &systemTicks, &idleTicks); - - // Move to next line - next_line(fh); - - //find the line for requested cpu faster to just iterate linefeeds? - if (which != -1) { - int i; - for (i = 0; i < which; i++) { - if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, &userTicks, &niceTicks, &systemTicks, &idleTicks) != 4) { - fclose(fh); - return -2; - } - next_line(fh); - } - n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 "\n", - &userTicks, &niceTicks, &systemTicks, &idleTicks); - } - - fclose(fh); - if (n != 4) { - return -2; - } - - pticks->used = userTicks + niceTicks; - pticks->usedKernel = systemTicks; - pticks->total = userTicks + niceTicks + systemTicks + idleTicks; - - return 0; -} - -static int vread_statdata(const char *procfile, const char *fmt, va_list args) { - FILE *f; - int n; - char buf[2048]; - - if ((f = fopen(procfile, "r")) == NULL) { - return -1; - } - - if ((n = fread(buf, 1, sizeof(buf), f)) != -1) { - char *tmp; - - buf[n-1] = '\0'; - /** skip through pid and exec name. the exec name _could be wacky_ (renamed) and - * make scanf go mupp. - */ - if ((tmp = strrchr(buf, ')')) != NULL) { - // skip the ')' and the following space but check that the buffer is long enough - tmp += 2; - if (tmp < buf + n) { - n = vsscanf(tmp, fmt, args); - } - } - } - - fclose(f); - - return n; -} - -static int read_statdata(const char *procfile, const char *fmt, ...) { - int n; - va_list args; - - va_start(args, fmt); - n = vread_statdata(procfile, fmt, args); - va_end(args); - return n; -} - -/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ -static int read_ticks(const char *procfile, uint64_t *userTicks, uint64_t *systemTicks) { - return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "DEC_64" "DEC_64, - userTicks, systemTicks - ); -} - -/** - * Return the number of ticks spent in any of the processes belonging - * to the JVM on any CPU. - */ -static int get_jvmticks(ticks *pticks) { - uint64_t userTicks; - uint64_t systemTicks; - - if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) { - return -1; - } - - // get the total - if (get_totalticks(-1, pticks) < 0) { - return -1; - } - - pticks->used = userTicks; - pticks->usedKernel = systemTicks; - - return 0; -} - -/** - * This method must be called first, before any data can be gathererd. - */ -int perfInit() { - static int initialized=1; - - if (!initialized) { - int i; - - int n = sysconf(_SC_NPROCESSORS_ONLN); - if (n <= 0) { - n = 1; - } - - counters.cpus = calloc(n,sizeof(ticks)); - if (counters.cpus != NULL) { - // For the CPU load - get_totalticks(-1, &counters.cpuTicks); - - for (i = 0; i < n; i++) { - get_totalticks(i, &counters.cpus[i]); - } - // For JVM load - get_jvmticks(&counters.jvmTicks); - initialized = 1; - } - } - - return initialized ? 0 : -1; -} - -#define MAX(a,b) (a>b?a:b) -#define MIN(a,b) (ausedKernel < tmp.usedKernel) { - kdiff = 0; - } else { - kdiff = pticks->usedKernel - tmp.usedKernel; - } - tdiff = pticks->total - tmp.total; - udiff = pticks->used - tmp.used; - - if (tdiff == 0) { - user_load = 0; - } else { - if (tdiff < (udiff + kdiff)) { - tdiff = udiff + kdiff; - } - *pkernelLoad = (kdiff / (double)tdiff); - // BUG9044876, normalize return values to sane values - *pkernelLoad = MAX(*pkernelLoad, 0.0); - *pkernelLoad = MIN(*pkernelLoad, 1.0); - - user_load = (udiff / (double)tdiff); - user_load = MAX(user_load, 0.0); - user_load = MIN(user_load, 1.0); - } - } - } - pthread_mutex_unlock(&lock); - return user_load; -} - -double get_cpu_load(int which) { - double u, s; - u = get_cpuload_internal(which, &s, CPU_LOAD_GLOBAL); - if (u < 0) { - return -1.0; - } - // Cap total systemload to 1.0 - return MIN((u + s), 1.0); -} - -double get_process_load() { - double u, s; - u = get_cpuload_internal(-1, &s, CPU_LOAD_VM_ONLY); - if (u < 0) { - return -1.0; - } - return u + s; -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad -(JNIEnv *env, jobject dummy) -{ - if(perfInit() == 0) { - return get_cpu_load(-1); - } else { - return -1.0; - } -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad -(JNIEnv *env, jobject dummy) -{ - if(perfInit() == 0) { - return get_process_load(); - } else { - return -1.0; - } -} --- /dev/null Thu Nov 7 12:14:03 2013 +++ new/src/solaris/native/sun/management/LinuxOperatingSystem.c Thu Nov 7 12:14:03 2013 @@ -0,0 +1,332 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sun_management_OperatingSystemImpl.h" + +struct ticks { + uint64_t used; + uint64_t usedKernel; + uint64_t total; +}; + +typedef struct ticks ticks; + +typedef enum { + CPU_LOAD_VM_ONLY, + CPU_LOAD_GLOBAL, +} CpuLoadTarget; + +static struct perfbuf { + int nProcs; + ticks jvmTicks; + ticks cpuTicks; + ticks *cpus; +} counters; + +#define DEC_64 "%lld" + +static void next_line(FILE *f) { + while (fgetc(f) != '\n'); +} + +/** + * Return the total number of ticks since the system was booted. + * If the usedTicks parameter is not NULL, it will be filled with + * the number of ticks spent on actual processes (user, system or + * nice processes) since system boot. Note that this is the total number + * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is + * n times the number of ticks that has passed in clock time. + * + * Returns a negative value if the reading of the ticks failed. + */ +static int get_totalticks(int which, ticks *pticks) { + FILE *fh; + uint64_t userTicks, niceTicks, systemTicks, idleTicks; + int n; + + if((fh = fopen("/proc/stat", "r")) == NULL) { + return -1; + } + + n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, + &userTicks, &niceTicks, &systemTicks, &idleTicks); + + // Move to next line + next_line(fh); + + //find the line for requested cpu faster to just iterate linefeeds? + if (which != -1) { + int i; + for (i = 0; i < which; i++) { + if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, &userTicks, &niceTicks, &systemTicks, &idleTicks) != 4) { + fclose(fh); + return -2; + } + next_line(fh); + } + n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 "\n", + &userTicks, &niceTicks, &systemTicks, &idleTicks); + } + + fclose(fh); + if (n != 4) { + return -2; + } + + pticks->used = userTicks + niceTicks; + pticks->usedKernel = systemTicks; + pticks->total = userTicks + niceTicks + systemTicks + idleTicks; + + return 0; +} + +static int vread_statdata(const char *procfile, const char *fmt, va_list args) { + FILE *f; + int n; + char buf[2048]; + + if ((f = fopen(procfile, "r")) == NULL) { + return -1; + } + + if ((n = fread(buf, 1, sizeof(buf), f)) != -1) { + char *tmp; + + buf[n-1] = '\0'; + /** skip through pid and exec name. the exec name _could be wacky_ (renamed) and + * make scanf go mupp. + */ + if ((tmp = strrchr(buf, ')')) != NULL) { + // skip the ')' and the following space but check that the buffer is long enough + tmp += 2; + if (tmp < buf + n) { + n = vsscanf(tmp, fmt, args); + } + } + } + + fclose(f); + + return n; +} + +static int read_statdata(const char *procfile, const char *fmt, ...) { + int n; + va_list args; + + va_start(args, fmt); + n = vread_statdata(procfile, fmt, args); + va_end(args); + return n; +} + +/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ +static int read_ticks(const char *procfile, uint64_t *userTicks, uint64_t *systemTicks) { + return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "DEC_64" "DEC_64, + userTicks, systemTicks + ); +} + +/** + * Return the number of ticks spent in any of the processes belonging + * to the JVM on any CPU. + */ +static int get_jvmticks(ticks *pticks) { + uint64_t userTicks; + uint64_t systemTicks; + + if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) { + return -1; + } + + // get the total + if (get_totalticks(-1, pticks) < 0) { + return -1; + } + + pticks->used = userTicks; + pticks->usedKernel = systemTicks; + + return 0; +} + +/** + * This method must be called first, before any data can be gathererd. + */ +int perfInit() { + static int initialized=1; + + if (!initialized) { + int i; + + int n = sysconf(_SC_NPROCESSORS_ONLN); + if (n <= 0) { + n = 1; + } + + counters.cpus = calloc(n,sizeof(ticks)); + if (counters.cpus != NULL) { + // For the CPU load + get_totalticks(-1, &counters.cpuTicks); + + for (i = 0; i < n; i++) { + get_totalticks(i, &counters.cpus[i]); + } + // For JVM load + get_jvmticks(&counters.jvmTicks); + initialized = 1; + } + } + + return initialized ? 0 : -1; +} + +#define MAX(a,b) (a>b?a:b) +#define MIN(a,b) (ausedKernel < tmp.usedKernel) { + kdiff = 0; + } else { + kdiff = pticks->usedKernel - tmp.usedKernel; + } + tdiff = pticks->total - tmp.total; + udiff = pticks->used - tmp.used; + + if (tdiff == 0) { + user_load = 0; + } else { + if (tdiff < (udiff + kdiff)) { + tdiff = udiff + kdiff; + } + *pkernelLoad = (kdiff / (double)tdiff); + // BUG9044876, normalize return values to sane values + *pkernelLoad = MAX(*pkernelLoad, 0.0); + *pkernelLoad = MIN(*pkernelLoad, 1.0); + + user_load = (udiff / (double)tdiff); + user_load = MAX(user_load, 0.0); + user_load = MIN(user_load, 1.0); + } + } + } + pthread_mutex_unlock(&lock); + return user_load; +} + +double get_cpu_load(int which) { + double u, s; + u = get_cpuload_internal(which, &s, CPU_LOAD_GLOBAL); + if (u < 0) { + return -1.0; + } + // Cap total systemload to 1.0 + return MIN((u + s), 1.0); +} + +double get_process_load() { + double u, s; + u = get_cpuload_internal(-1, &s, CPU_LOAD_VM_ONLY); + if (u < 0) { + return -1.0; + } + return u + s; +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getSystemCpuLoad +(JNIEnv *env, jobject dummy) +{ + if(perfInit() == 0) { + return get_cpu_load(-1); + } else { + return -1.0; + } +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuLoad +(JNIEnv *env, jobject dummy) +{ + if(perfInit() == 0) { + return get_process_load(); + } else { + return -1.0; + } +} --- old/src/solaris/native/com/sun/management/MacosxOperatingSystem.c Thu Nov 7 12:14:05 2013 +++ /dev/null Thu Nov 7 12:14:05 2013 @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2011, 2012, 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. - */ - -#include "com_sun_management_UnixOperatingSystem.h" - -#include -#include -#include - - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad -(JNIEnv *env, jobject dummy) -{ - // This code is influenced by the darwin top source - - kern_return_t kr; - mach_msg_type_number_t count; - host_cpu_load_info_data_t load; - - static jlong last_used = 0; - static jlong last_total = 0; - - count = HOST_CPU_LOAD_INFO_COUNT; - kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&load, &count); - if (kr != KERN_SUCCESS) { - return -1; - } - - jlong used = load.cpu_ticks[CPU_STATE_USER] + load.cpu_ticks[CPU_STATE_NICE] + load.cpu_ticks[CPU_STATE_SYSTEM]; - jlong total = used + load.cpu_ticks[CPU_STATE_IDLE]; - - if (last_used == 0 || last_total == 0) { - // First call, just set the last values - last_used = used; - last_total = total; - // return 0 since we have no data, not -1 which indicates error - return 0; - } - - jlong used_delta = used - last_used; - jlong total_delta = total - last_total; - - jdouble cpu = (jdouble) used_delta / total_delta; - - last_used = used; - last_total = total; - - return cpu; -} - - -#define TIME_VALUE_TO_TIMEVAL(a, r) do { \ - (r)->tv_sec = (a)->seconds; \ - (r)->tv_usec = (a)->microseconds; \ -} while (0) - - -#define TIME_VALUE_TO_MICROSECONDS(TV) \ - ((TV).tv_sec * 1000 * 1000 + (TV).tv_usec) - - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad -(JNIEnv *env, jobject dummy) -{ - // This code is influenced by the darwin top source - - struct task_basic_info_64 task_info_data; - struct task_thread_times_info thread_info_data; - struct timeval user_timeval, system_timeval, task_timeval; - struct timeval now; - mach_port_t task = mach_task_self(); - kern_return_t kr; - - static jlong last_task_time = 0; - static jlong last_time = 0; - - mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT; - kr = task_info(task, - TASK_THREAD_TIMES_INFO, - (task_info_t)&thread_info_data, - &thread_info_count); - if (kr != KERN_SUCCESS) { - // Most likely cause: |task| is a zombie. - return -1; - } - - mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; - kr = task_info(task, - TASK_BASIC_INFO_64, - (task_info_t)&task_info_data, - &count); - if (kr != KERN_SUCCESS) { - // Most likely cause: |task| is a zombie. - return -1; - } - - /* Set total_time. */ - // thread info contains live time... - TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval); - TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval); - timeradd(&user_timeval, &system_timeval, &task_timeval); - - // ... task info contains terminated time. - TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval); - TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval); - timeradd(&user_timeval, &task_timeval, &task_timeval); - timeradd(&system_timeval, &task_timeval, &task_timeval); - - if (gettimeofday(&now, NULL) < 0) { - return -1; - } - jint ncpus = JVM_ActiveProcessorCount(); - jlong time = TIME_VALUE_TO_MICROSECONDS(now) * ncpus; - jlong task_time = TIME_VALUE_TO_MICROSECONDS(task_timeval); - - if ((last_task_time == 0) || (last_time == 0)) { - // First call, just set the last values. - last_task_time = task_time; - last_time = time; - // return 0 since we have no data, not -1 which indicates error - return 0; - } - - jlong task_time_delta = task_time - last_task_time; - jlong time_delta = time - last_time; - if (time_delta == 0) { - return -1; - } - - jdouble cpu = (jdouble) task_time_delta / time_delta; - - last_task_time = task_time; - last_time = time; - - return cpu; - } --- /dev/null Thu Nov 7 12:14:05 2013 +++ new/src/solaris/native/sun/management/MacosxOperatingSystem.c Thu Nov 7 12:14:04 2013 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2011, 2012, 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. + */ + +#include "sun_management_OperatingSystemImpl.h" + +#include +#include +#include + + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getSystemCpuLoad +(JNIEnv *env, jobject dummy) +{ + // This code is influenced by the darwin top source + + kern_return_t kr; + mach_msg_type_number_t count; + host_cpu_load_info_data_t load; + + static jlong last_used = 0; + static jlong last_total = 0; + + count = HOST_CPU_LOAD_INFO_COUNT; + kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&load, &count); + if (kr != KERN_SUCCESS) { + return -1; + } + + jlong used = load.cpu_ticks[CPU_STATE_USER] + load.cpu_ticks[CPU_STATE_NICE] + load.cpu_ticks[CPU_STATE_SYSTEM]; + jlong total = used + load.cpu_ticks[CPU_STATE_IDLE]; + + if (last_used == 0 || last_total == 0) { + // First call, just set the last values + last_used = used; + last_total = total; + // return 0 since we have no data, not -1 which indicates error + return 0; + } + + jlong used_delta = used - last_used; + jlong total_delta = total - last_total; + + jdouble cpu = (jdouble) used_delta / total_delta; + + last_used = used; + last_total = total; + + return cpu; +} + + +#define TIME_VALUE_TO_TIMEVAL(a, r) do { \ + (r)->tv_sec = (a)->seconds; \ + (r)->tv_usec = (a)->microseconds; \ +} while (0) + + +#define TIME_VALUE_TO_MICROSECONDS(TV) \ + ((TV).tv_sec * 1000 * 1000 + (TV).tv_usec) + + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuLoad +(JNIEnv *env, jobject dummy) +{ + // This code is influenced by the darwin top source + + struct task_basic_info_64 task_info_data; + struct task_thread_times_info thread_info_data; + struct timeval user_timeval, system_timeval, task_timeval; + struct timeval now; + mach_port_t task = mach_task_self(); + kern_return_t kr; + + static jlong last_task_time = 0; + static jlong last_time = 0; + + mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT; + kr = task_info(task, + TASK_THREAD_TIMES_INFO, + (task_info_t)&thread_info_data, + &thread_info_count); + if (kr != KERN_SUCCESS) { + // Most likely cause: |task| is a zombie. + return -1; + } + + mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; + kr = task_info(task, + TASK_BASIC_INFO_64, + (task_info_t)&task_info_data, + &count); + if (kr != KERN_SUCCESS) { + // Most likely cause: |task| is a zombie. + return -1; + } + + /* Set total_time. */ + // thread info contains live time... + TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval); + TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval); + timeradd(&user_timeval, &system_timeval, &task_timeval); + + // ... task info contains terminated time. + TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval); + TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval); + timeradd(&user_timeval, &task_timeval, &task_timeval); + timeradd(&system_timeval, &task_timeval, &task_timeval); + + if (gettimeofday(&now, NULL) < 0) { + return -1; + } + jint ncpus = JVM_ActiveProcessorCount(); + jlong time = TIME_VALUE_TO_MICROSECONDS(now) * ncpus; + jlong task_time = TIME_VALUE_TO_MICROSECONDS(task_timeval); + + if ((last_task_time == 0) || (last_time == 0)) { + // First call, just set the last values. + last_task_time = task_time; + last_time = time; + // return 0 since we have no data, not -1 which indicates error + return 0; + } + + jlong task_time_delta = task_time - last_task_time; + jlong time_delta = time - last_time; + if (time_delta == 0) { + return -1; + } + + jdouble cpu = (jdouble) task_time_delta / time_delta; + + last_task_time = task_time; + last_time = time; + + return cpu; + } --- old/src/solaris/native/com/sun/management/UnixOperatingSystem_md.c Thu Nov 7 12:14:06 2013 +++ /dev/null Thu Nov 7 12:14:06 2013 @@ -1,451 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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. - */ - -#include "jni.h" -#include "jni_util.h" -#include "jlong.h" -#include "jvm.h" -#include "management.h" -#include "com_sun_management_UnixOperatingSystem.h" - -#include -#include -#if defined(_ALLBSD_SOURCE) -#include -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#endif -#else -#include -#endif -#include -#include -#ifndef _ALLBSD_SOURCE -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -static jlong page_size = 0; - -#if defined(_ALLBSD_SOURCE) -#define MB (1024UL * 1024UL) -#else - -/* This gets us the new structured proc interfaces of 5.6 & later */ -/* - see comment in */ -#define _STRUCTURED_PROC 1 -#include - -#endif /* _ALLBSD_SOURCE */ - -static struct dirent* read_dir(DIR* dirp, struct dirent* entry) { -#ifdef __solaris__ - struct dirent* dbuf = readdir(dirp); - return dbuf; -#else /* __linux__ || _ALLBSD_SOURCE */ - struct dirent* p; - if (readdir_r(dirp, entry, &p) == 0) { - return p; - } else { - return NULL; - } -#endif -} - -// true = get available swap in bytes -// false = get total swap in bytes -static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) { -#ifdef __solaris__ - long total, avail; - int nswap, i, count; - swaptbl_t *stbl; - char *strtab; - - // First get the number of swap resource entries - if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) { - throw_internal_error(env, "swapctl failed to get nswap"); - return -1; - } - if (nswap == 0) { - return 0; - } - - // Allocate storage for resource entries - stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) + - sizeof(struct swaptable)); - if (stbl == NULL) { - JNU_ThrowOutOfMemoryError(env, 0); - return -1; - } - - // Allocate storage for the table - strtab = (char*) malloc((nswap + 1) * MAXPATHLEN); - if (strtab == NULL) { - free(stbl); - JNU_ThrowOutOfMemoryError(env, 0); - return -1; - } - - for (i = 0; i < (nswap + 1); i++) { - stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN); - } - stbl->swt_n = nswap + 1; - - // Get the entries - if ((count = swapctl(SC_LIST, stbl)) < 0) { - free(stbl); - free(strtab); - throw_internal_error(env, "swapctl failed to get swap list"); - return -1; - } - - // Sum the entries to get total and free swap - total = 0; - avail = 0; - for (i = 0; i < count; i++) { - total += stbl->swt_ent[i].ste_pages; - avail += stbl->swt_ent[i].ste_free; - } - - free(stbl); - free(strtab); - return available ? ((jlong)avail * page_size) : - ((jlong)total * page_size); -#elif defined(__linux__) - int ret; - FILE *fp; - jlong total = 0, avail = 0; - - struct sysinfo si; - ret = sysinfo(&si); - if (ret != 0) { - throw_internal_error(env, "sysinfo failed to get swap size"); - } - total = (jlong)si.totalswap * si.mem_unit; - avail = (jlong)si.freeswap * si.mem_unit; - - return available ? avail : total; -#elif defined(__APPLE__) - struct xsw_usage vmusage; - size_t size = sizeof(vmusage); - if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { - throw_internal_error(env, "sysctlbyname failed"); - } - return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total; -#else /* _ALLBSD_SOURCE */ - /* - * XXXBSD: there's no way available to get swap info in - * FreeBSD. Usage of libkvm is not an option here - */ - // throw_internal_error(env, "Unimplemented in FreeBSD"); - return (0); -#endif -} - -JNIEXPORT void JNICALL -Java_com_sun_management_UnixOperatingSystem_initialize - (JNIEnv *env, jclass cls) -{ - page_size = sysconf(_SC_PAGESIZE); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getCommittedVirtualMemorySize - (JNIEnv *env, jobject mbean) -{ -#ifdef __solaris__ - psinfo_t psinfo; - ssize_t result; - size_t remaining; - char* addr; - int fd; - - fd = JVM_Open("/proc/self/psinfo", O_RDONLY, 0); - if (fd < 0) { - throw_internal_error(env, "Unable to open /proc/self/psinfo"); - return -1; - } - - addr = (char *)&psinfo; - for (remaining = sizeof(psinfo_t); remaining > 0;) { - result = JVM_Read(fd, addr, remaining); - if (result < 0) { - JVM_Close(fd); - throw_internal_error(env, "Unable to read /proc/self/psinfo"); - return -1; - } - remaining -= result; - addr += result; - } - - JVM_Close(fd); - return (jlong) psinfo.pr_size * 1024; -#elif defined(__linux__) - FILE *fp; - unsigned long vsize = 0; - - if ((fp = fopen("/proc/self/stat", "r")) == NULL) { - throw_internal_error(env, "Unable to open /proc/self/stat"); - return -1; - } - - // Ignore everything except the vsize entry - if (fscanf(fp, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %lu %*[^\n]\n", &vsize) == EOF) { - throw_internal_error(env, "Unable to get virtual memory usage"); - fclose(fp); - return -1; - } - - fclose(fp); - return (jlong)vsize; -#elif defined(__APPLE__) - struct task_basic_info t_info; - mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; - - kern_return_t res = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); - if (res != KERN_SUCCESS) { - throw_internal_error(env, "task_info failed"); - } - return t_info.virtual_size; -#else /* _ALLBSD_SOURCE */ - /* - * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. - */ - // throw_internal_error(env, "Unimplemented in FreeBSD"); - return (64 * MB); -#endif -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getTotalSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - return get_total_or_available_swap_space_size(env, JNI_FALSE); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getFreeSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - return get_total_or_available_swap_space_size(env, JNI_TRUE); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getProcessCpuTime - (JNIEnv *env, jobject mbean) -{ -#ifdef __APPLE__ - struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage) != 0) { - throw_internal_error(env, "getrusage failed"); - return -1; - } - jlong microsecs = - usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec + - usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec; - return microsecs * 1000; -#else - jlong clk_tck, ns_per_clock_tick; - jlong cpu_time_ns; - struct tms time; - - /* - * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so - * add a magic to handle it - */ -#if defined(__solaris__) || defined(_SC_CLK_TCK) - clk_tck = (jlong) sysconf(_SC_CLK_TCK); -#elif defined(__linux__) || defined(_ALLBSD_SOURCE) - clk_tck = 100; -#endif - if (clk_tck == -1) { - throw_internal_error(env, - "sysconf failed - not able to get clock tick"); - return -1; - } - - times(&time); - ns_per_clock_tick = (jlong) 1000 * 1000 * 1000 / (jlong) clk_tck; - cpu_time_ns = ((jlong)time.tms_utime + (jlong) time.tms_stime) * - ns_per_clock_tick; - return cpu_time_ns; -#endif -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getFreePhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ -#ifdef __APPLE__ - mach_msg_type_number_t count; - vm_statistics_data_t vm_stats; - kern_return_t res; - - count = HOST_VM_INFO_COUNT; - res = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stats, &count); - if (res != KERN_SUCCESS) { - throw_internal_error(env, "host_statistics failed"); - return -1; - } - return (jlong)vm_stats.free_count * page_size; -#elif defined(_ALLBSD_SOURCE) - /* - * XXBSDL no way to do it in FreeBSD - */ - // throw_internal_error(env, "unimplemented in FreeBSD") - return (128 * MB); -#else // solaris / linux - jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES); - return (num_avail_physical_pages * page_size); -#endif -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getTotalPhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ -#ifdef _ALLBSD_SOURCE - jlong result = 0; - int mib[2]; - size_t rlen; - - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - rlen = sizeof(result); - if (sysctl(mib, 2, &result, &rlen, NULL, 0) != 0) { - throw_internal_error(env, "sysctl failed"); - return -1; - } - return result; -#else // solaris / linux - jlong num_physical_pages = sysconf(_SC_PHYS_PAGES); - return (num_physical_pages * page_size); -#endif -} - - - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getOpenFileDescriptorCount - (JNIEnv *env, jobject mbean) -{ -#ifdef __APPLE__ - // This code is influenced by the darwin lsof source - pid_t my_pid; - struct proc_bsdinfo bsdinfo; - struct proc_fdinfo *fds; - int nfiles; - kern_return_t kres; - int res; - size_t fds_size; - - kres = pid_for_task(mach_task_self(), &my_pid); - if (kres != KERN_SUCCESS) { - throw_internal_error(env, "pid_for_task failed"); - return -1; - } - - // get the maximum number of file descriptors - res = proc_pidinfo(my_pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE); - if (res <= 0) { - throw_internal_error(env, "proc_pidinfo with PROC_PIDTBSDINFO failed"); - return -1; - } - - // allocate memory to hold the fd information (we don't acutally use this information - // but need it to get the number of open files) - fds_size = bsdinfo.pbi_nfiles * sizeof(struct proc_fdinfo); - fds = malloc(fds_size); - if (fds == NULL) { - JNU_ThrowOutOfMemoryError(env, "could not allocate space for file descriptors"); - return -1; - } - - // get the list of open files - the return value is the number of bytes - // proc_pidinfo filled in - res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, fds_size); - if (res <= 0) { - free(fds); - throw_internal_error(env, "proc_pidinfo failed for PROC_PIDLISTFDS"); - return -1; - } - nfiles = res / sizeof(struct proc_fdinfo); - free(fds); - - return nfiles; -#elif defined(_ALLBSD_SOURCE) - /* - * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. - */ - // throw_internal_error(env, "Unimplemented in FreeBSD"); - return (100); -#else /* solaris/linux */ - DIR *dirp; - struct dirent dbuf; - struct dirent* dentp; - jlong fds = 0; - - dirp = opendir("/proc/self/fd"); - if (dirp == NULL) { - throw_internal_error(env, "Unable to open directory /proc/self/fd"); - return -1; - } - - // iterate through directory entries, skipping '.' and '..' - // each entry represents an open file descriptor. - while ((dentp = read_dir(dirp, &dbuf)) != NULL) { - if (isdigit(dentp->d_name[0])) { - fds++; - } - } - - closedir(dirp); - // subtract by 1 which was the fd open for this implementation - return (fds - 1); -#endif -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_UnixOperatingSystem_getMaxFileDescriptorCount - (JNIEnv *env, jobject mbean) -{ - struct rlimit rlp; - - if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) { - throw_internal_error(env, "getrlimit failed"); - return -1; - } - return (jlong) rlp.rlim_cur; -} --- /dev/null Thu Nov 7 12:14:06 2013 +++ new/src/solaris/native/sun/management/OperatingSystemImpl.c Thu Nov 7 12:14:05 2013 @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2003, 2012, 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. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "jvm.h" +#include "management.h" +#include "sun_management_OperatingSystemImpl.h" + +#include +#include +#if defined(_ALLBSD_SOURCE) +#include +#ifdef __APPLE__ +#include +#include +#include +#include +#include +#endif +#else +#include +#endif +#include +#include +#ifndef _ALLBSD_SOURCE +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +static jlong page_size = 0; + +#if defined(_ALLBSD_SOURCE) +#define MB (1024UL * 1024UL) +#else + +/* This gets us the new structured proc interfaces of 5.6 & later */ +/* - see comment in */ +#define _STRUCTURED_PROC 1 +#include + +#endif /* _ALLBSD_SOURCE */ + +static struct dirent* read_dir(DIR* dirp, struct dirent* entry) { +#ifdef __solaris__ + struct dirent* dbuf = readdir(dirp); + return dbuf; +#else /* __linux__ || _ALLBSD_SOURCE */ + struct dirent* p; + if (readdir_r(dirp, entry, &p) == 0) { + return p; + } else { + return NULL; + } +#endif +} + +// true = get available swap in bytes +// false = get total swap in bytes +static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) { +#ifdef __solaris__ + long total, avail; + int nswap, i, count; + swaptbl_t *stbl; + char *strtab; + + // First get the number of swap resource entries + if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) { + throw_internal_error(env, "swapctl failed to get nswap"); + return -1; + } + if (nswap == 0) { + return 0; + } + + // Allocate storage for resource entries + stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) + + sizeof(struct swaptable)); + if (stbl == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return -1; + } + + // Allocate storage for the table + strtab = (char*) malloc((nswap + 1) * MAXPATHLEN); + if (strtab == NULL) { + free(stbl); + JNU_ThrowOutOfMemoryError(env, 0); + return -1; + } + + for (i = 0; i < (nswap + 1); i++) { + stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN); + } + stbl->swt_n = nswap + 1; + + // Get the entries + if ((count = swapctl(SC_LIST, stbl)) < 0) { + free(stbl); + free(strtab); + throw_internal_error(env, "swapctl failed to get swap list"); + return -1; + } + + // Sum the entries to get total and free swap + total = 0; + avail = 0; + for (i = 0; i < count; i++) { + total += stbl->swt_ent[i].ste_pages; + avail += stbl->swt_ent[i].ste_free; + } + + free(stbl); + free(strtab); + return available ? ((jlong)avail * page_size) : + ((jlong)total * page_size); +#elif defined(__linux__) + int ret; + FILE *fp; + jlong total = 0, avail = 0; + + struct sysinfo si; + ret = sysinfo(&si); + if (ret != 0) { + throw_internal_error(env, "sysinfo failed to get swap size"); + } + total = (jlong)si.totalswap * si.mem_unit; + avail = (jlong)si.freeswap * si.mem_unit; + + return available ? avail : total; +#elif defined(__APPLE__) + struct xsw_usage vmusage; + size_t size = sizeof(vmusage); + if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { + throw_internal_error(env, "sysctlbyname failed"); + } + return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total; +#else /* _ALLBSD_SOURCE */ + /* + * XXXBSD: there's no way available to get swap info in + * FreeBSD. Usage of libkvm is not an option here + */ + // throw_internal_error(env, "Unimplemented in FreeBSD"); + return (0); +#endif +} + +JNIEXPORT void JNICALL +Java_sun_management_OperatingSystemImpl_initialize + (JNIEnv *env, jclass cls) +{ + page_size = sysconf(_SC_PAGESIZE); +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize + (JNIEnv *env, jobject mbean) +{ +#ifdef __solaris__ + psinfo_t psinfo; + ssize_t result; + size_t remaining; + char* addr; + int fd; + + fd = JVM_Open("/proc/self/psinfo", O_RDONLY, 0); + if (fd < 0) { + throw_internal_error(env, "Unable to open /proc/self/psinfo"); + return -1; + } + + addr = (char *)&psinfo; + for (remaining = sizeof(psinfo_t); remaining > 0;) { + result = JVM_Read(fd, addr, remaining); + if (result < 0) { + JVM_Close(fd); + throw_internal_error(env, "Unable to read /proc/self/psinfo"); + return -1; + } + remaining -= result; + addr += result; + } + + JVM_Close(fd); + return (jlong) psinfo.pr_size * 1024; +#elif defined(__linux__) + FILE *fp; + unsigned long vsize = 0; + + if ((fp = fopen("/proc/self/stat", "r")) == NULL) { + throw_internal_error(env, "Unable to open /proc/self/stat"); + return -1; + } + + // Ignore everything except the vsize entry + if (fscanf(fp, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %lu %*[^\n]\n", &vsize) == EOF) { + throw_internal_error(env, "Unable to get virtual memory usage"); + fclose(fp); + return -1; + } + + fclose(fp); + return (jlong)vsize; +#elif defined(__APPLE__) + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + kern_return_t res = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); + if (res != KERN_SUCCESS) { + throw_internal_error(env, "task_info failed"); + } + return t_info.virtual_size; +#else /* _ALLBSD_SOURCE */ + /* + * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. + */ + // throw_internal_error(env, "Unimplemented in FreeBSD"); + return (64 * MB); +#endif +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize + (JNIEnv *env, jobject mbean) +{ + return get_total_or_available_swap_space_size(env, JNI_FALSE); +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize + (JNIEnv *env, jobject mbean) +{ + return get_total_or_available_swap_space_size(env, JNI_TRUE); +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuTime + (JNIEnv *env, jobject mbean) +{ +#ifdef __APPLE__ + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) != 0) { + throw_internal_error(env, "getrusage failed"); + return -1; + } + jlong microsecs = + usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec + + usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec; + return microsecs * 1000; +#else + jlong clk_tck, ns_per_clock_tick; + jlong cpu_time_ns; + struct tms time; + + /* + * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so + * add a magic to handle it + */ +#if defined(__solaris__) || defined(_SC_CLK_TCK) + clk_tck = (jlong) sysconf(_SC_CLK_TCK); +#elif defined(__linux__) || defined(_ALLBSD_SOURCE) + clk_tck = 100; +#endif + if (clk_tck == -1) { + throw_internal_error(env, + "sysconf failed - not able to get clock tick"); + return -1; + } + + times(&time); + ns_per_clock_tick = (jlong) 1000 * 1000 * 1000 / (jlong) clk_tck; + cpu_time_ns = ((jlong)time.tms_utime + (jlong) time.tms_stime) * + ns_per_clock_tick; + return cpu_time_ns; +#endif +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize + (JNIEnv *env, jobject mbean) +{ +#ifdef __APPLE__ + mach_msg_type_number_t count; + vm_statistics_data_t vm_stats; + kern_return_t res; + + count = HOST_VM_INFO_COUNT; + res = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stats, &count); + if (res != KERN_SUCCESS) { + throw_internal_error(env, "host_statistics failed"); + return -1; + } + return (jlong)vm_stats.free_count * page_size; +#elif defined(_ALLBSD_SOURCE) + /* + * XXBSDL no way to do it in FreeBSD + */ + // throw_internal_error(env, "unimplemented in FreeBSD") + return (128 * MB); +#else // solaris / linux + jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES); + return (num_avail_physical_pages * page_size); +#endif +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize + (JNIEnv *env, jobject mbean) +{ +#ifdef _ALLBSD_SOURCE + jlong result = 0; + int mib[2]; + size_t rlen; + + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + rlen = sizeof(result); + if (sysctl(mib, 2, &result, &rlen, NULL, 0) != 0) { + throw_internal_error(env, "sysctl failed"); + return -1; + } + return result; +#else // solaris / linux + jlong num_physical_pages = sysconf(_SC_PHYS_PAGES); + return (num_physical_pages * page_size); +#endif +} + + + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getOpenFileDescriptorCount + (JNIEnv *env, jobject mbean) +{ +#ifdef __APPLE__ + // This code is influenced by the darwin lsof source + pid_t my_pid; + struct proc_bsdinfo bsdinfo; + struct proc_fdinfo *fds; + int nfiles; + kern_return_t kres; + int res; + size_t fds_size; + + kres = pid_for_task(mach_task_self(), &my_pid); + if (kres != KERN_SUCCESS) { + throw_internal_error(env, "pid_for_task failed"); + return -1; + } + + // get the maximum number of file descriptors + res = proc_pidinfo(my_pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE); + if (res <= 0) { + throw_internal_error(env, "proc_pidinfo with PROC_PIDTBSDINFO failed"); + return -1; + } + + // allocate memory to hold the fd information (we don't acutally use this information + // but need it to get the number of open files) + fds_size = bsdinfo.pbi_nfiles * sizeof(struct proc_fdinfo); + fds = malloc(fds_size); + if (fds == NULL) { + JNU_ThrowOutOfMemoryError(env, "could not allocate space for file descriptors"); + return -1; + } + + // get the list of open files - the return value is the number of bytes + // proc_pidinfo filled in + res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, fds_size); + if (res <= 0) { + free(fds); + throw_internal_error(env, "proc_pidinfo failed for PROC_PIDLISTFDS"); + return -1; + } + nfiles = res / sizeof(struct proc_fdinfo); + free(fds); + + return nfiles; +#elif defined(_ALLBSD_SOURCE) + /* + * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. + */ + // throw_internal_error(env, "Unimplemented in FreeBSD"); + return (100); +#else /* solaris/linux */ + DIR *dirp; + struct dirent dbuf; + struct dirent* dentp; + jlong fds = 0; + + dirp = opendir("/proc/self/fd"); + if (dirp == NULL) { + throw_internal_error(env, "Unable to open directory /proc/self/fd"); + return -1; + } + + // iterate through directory entries, skipping '.' and '..' + // each entry represents an open file descriptor. + while ((dentp = read_dir(dirp, &dbuf)) != NULL) { + if (isdigit(dentp->d_name[0])) { + fds++; + } + } + + closedir(dirp); + // subtract by 1 which was the fd open for this implementation + return (fds - 1); +#endif +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getMaxFileDescriptorCount + (JNIEnv *env, jobject mbean) +{ + struct rlimit rlp; + + if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) { + throw_internal_error(env, "getrlimit failed"); + return -1; + } + return (jlong) rlp.rlim_cur; +} --- old/src/solaris/native/com/sun/management/SolarisOperatingSystem.c Thu Nov 7 12:14:07 2013 +++ /dev/null Thu Nov 7 12:14:07 2013 @@ -1,241 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "jvm.h" -#include "com_sun_management_UnixOperatingSystem.h" - -typedef struct { - kstat_t *kstat; - uint64_t last_idle; - uint64_t last_total; - double last_ratio; -} cpuload_t; - -static cpuload_t *cpu_loads = NULL; -static unsigned int num_cpus; -static kstat_ctl_t *kstat_ctrl = NULL; - -static void map_cpu_kstat_counters() { - kstat_t *kstat; - int i; - - // Get number of CPU(s) - if ((num_cpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1) { - num_cpus = 1; - } - - // Data structure for saving CPU load - if ((cpu_loads = calloc(num_cpus,sizeof(cpuload_t))) == NULL) { - return; - } - - // Get kstat cpu_stat counters for every CPU - // (loop over kstat to find our cpu_stat(s) - i = 0; - for (kstat = kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { - if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { - - if (kstat_read(kstat_ctrl, kstat, NULL) == -1) { - // Failed to initialize kstat for this CPU so ignore it - continue; - } - - if (i == num_cpus) { - // Found more cpu_stats than reported CPUs - break; - } - - cpu_loads[i++].kstat = kstat; - } - } -} - -static int init_cpu_kstat_counters() { - static int initialized = 0; - - // Concurrence in this method is prevented by the lock in - // the calling method get_cpu_load(); - if(!initialized) { - if ((kstat_ctrl = kstat_open()) != NULL) { - map_cpu_kstat_counters(); - initialized = 1; - } - } - return initialized ? 0 : -1; -} - -static void update_cpu_kstat_counters() { - if(kstat_chain_update(kstat_ctrl) != 0) { - free(cpu_loads); - map_cpu_kstat_counters(); - } -} - -int read_cpustat(cpuload_t *load, cpu_stat_t *cpu_stat) { - if (load->kstat == NULL) { - // no handle. - return -1; - } - if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == -1) { - // disabling for now, a kstat chain update is likely to happen next time - load->kstat = NULL; - return -1; - } - return 0; -} - -double get_single_cpu_load(unsigned int n) { - cpuload_t *load; - cpu_stat_t cpu_stat; - uint_t *usage; - uint64_t c_idle; - uint64_t c_total; - uint64_t d_idle; - uint64_t d_total; - int i; - - if (n >= num_cpus) { - return -1.0; - } - - load = &cpu_loads[n]; - if (read_cpustat(load, &cpu_stat) < 0) { - return -1.0; - } - - usage = cpu_stat.cpu_sysinfo.cpu; - c_idle = usage[CPU_IDLE]; - - for (c_total = 0, i = 0; i < CPU_STATES; i++) { - c_total += usage[i]; - } - - // Calculate diff against previous snapshot - d_idle = c_idle - load->last_idle; - d_total = c_total - load->last_total; - - /** update if weve moved */ - if (d_total > 0) { - // Save current values for next time around - load->last_idle = c_idle; - load->last_total = c_total; - load->last_ratio = (double) (d_total - d_idle) / d_total; - } - - return load->last_ratio; -} - -int get_info(const char *path, void *info, size_t s, off_t o) { - int fd; - int ret = 0; - if ((fd = open(path, O_RDONLY)) < 0) { - return -1; - } - if (pread(fd, info, s, o) != s) { - ret = -1; - } - close(fd); - return ret; -} - -#define MIN(a, b) ((a < b) ? a : b) - -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - -/** - * Return the cpu load (0-1) for proc number 'which' (or average all if which == -1) - */ -double get_cpu_load(int which) { - double load =.0; - - pthread_mutex_lock(&lock); - if(init_cpu_kstat_counters()==0) { - - update_cpu_kstat_counters(); - - if (which == -1) { - unsigned int i; - double t; - - for (t = .0, i = 0; i < num_cpus; i++) { - t += get_single_cpu_load(i); - } - - // Cap total systemload to 1.0 - load = MIN((t / num_cpus), 1.0); - } else { - load = MIN(get_single_cpu_load(which), 1.0); - } - } else { - load = -1.0; - } - pthread_mutex_unlock(&lock); - - return load; -} - -/** - * Return the cpu load (0-1) for the current process (i.e the JVM) - * or -1.0 if the get_info() call failed - */ -double get_process_load(void) { - psinfo_t info; - - // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s - // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. - if (get_info("/proc/self/psinfo",&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) == 0) { - return (double) info.pr_pctcpu / 0x8000; - } - return -1.0; -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad -(JNIEnv *env, jobject dummy) -{ - return get_cpu_load(-1); -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad -(JNIEnv *env, jobject dummy) -{ - return get_process_load(); -} - --- /dev/null Thu Nov 7 12:14:07 2013 +++ new/src/solaris/native/sun/management/SolarisOperatingSystem.c Thu Nov 7 12:14:07 2013 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jvm.h" +#include "sun_management_OperatingSystemImpl.h" + +typedef struct { + kstat_t *kstat; + uint64_t last_idle; + uint64_t last_total; + double last_ratio; +} cpuload_t; + +static cpuload_t *cpu_loads = NULL; +static unsigned int num_cpus; +static kstat_ctl_t *kstat_ctrl = NULL; + +static void map_cpu_kstat_counters() { + kstat_t *kstat; + int i; + + // Get number of CPU(s) + if ((num_cpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1) { + num_cpus = 1; + } + + // Data structure for saving CPU load + if ((cpu_loads = calloc(num_cpus,sizeof(cpuload_t))) == NULL) { + return; + } + + // Get kstat cpu_stat counters for every CPU + // (loop over kstat to find our cpu_stat(s) + i = 0; + for (kstat = kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { + if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { + + if (kstat_read(kstat_ctrl, kstat, NULL) == -1) { + // Failed to initialize kstat for this CPU so ignore it + continue; + } + + if (i == num_cpus) { + // Found more cpu_stats than reported CPUs + break; + } + + cpu_loads[i++].kstat = kstat; + } + } +} + +static int init_cpu_kstat_counters() { + static int initialized = 0; + + // Concurrence in this method is prevented by the lock in + // the calling method get_cpu_load(); + if(!initialized) { + if ((kstat_ctrl = kstat_open()) != NULL) { + map_cpu_kstat_counters(); + initialized = 1; + } + } + return initialized ? 0 : -1; +} + +static void update_cpu_kstat_counters() { + if(kstat_chain_update(kstat_ctrl) != 0) { + free(cpu_loads); + map_cpu_kstat_counters(); + } +} + +int read_cpustat(cpuload_t *load, cpu_stat_t *cpu_stat) { + if (load->kstat == NULL) { + // no handle. + return -1; + } + if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == -1) { + // disabling for now, a kstat chain update is likely to happen next time + load->kstat = NULL; + return -1; + } + return 0; +} + +double get_single_cpu_load(unsigned int n) { + cpuload_t *load; + cpu_stat_t cpu_stat; + uint_t *usage; + uint64_t c_idle; + uint64_t c_total; + uint64_t d_idle; + uint64_t d_total; + int i; + + if (n >= num_cpus) { + return -1.0; + } + + load = &cpu_loads[n]; + if (read_cpustat(load, &cpu_stat) < 0) { + return -1.0; + } + + usage = cpu_stat.cpu_sysinfo.cpu; + c_idle = usage[CPU_IDLE]; + + for (c_total = 0, i = 0; i < CPU_STATES; i++) { + c_total += usage[i]; + } + + // Calculate diff against previous snapshot + d_idle = c_idle - load->last_idle; + d_total = c_total - load->last_total; + + /** update if weve moved */ + if (d_total > 0) { + // Save current values for next time around + load->last_idle = c_idle; + load->last_total = c_total; + load->last_ratio = (double) (d_total - d_idle) / d_total; + } + + return load->last_ratio; +} + +int get_info(const char *path, void *info, size_t s, off_t o) { + int fd; + int ret = 0; + if ((fd = open(path, O_RDONLY)) < 0) { + return -1; + } + if (pread(fd, info, s, o) != s) { + ret = -1; + } + close(fd); + return ret; +} + +#define MIN(a, b) ((a < b) ? a : b) + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +/** + * Return the cpu load (0-1) for proc number 'which' (or average all if which == -1) + */ +double get_cpu_load(int which) { + double load =.0; + + pthread_mutex_lock(&lock); + if(init_cpu_kstat_counters()==0) { + + update_cpu_kstat_counters(); + + if (which == -1) { + unsigned int i; + double t; + + for (t = .0, i = 0; i < num_cpus; i++) { + t += get_single_cpu_load(i); + } + + // Cap total systemload to 1.0 + load = MIN((t / num_cpus), 1.0); + } else { + load = MIN(get_single_cpu_load(which), 1.0); + } + } else { + load = -1.0; + } + pthread_mutex_unlock(&lock); + + return load; +} + +/** + * Return the cpu load (0-1) for the current process (i.e the JVM) + * or -1.0 if the get_info() call failed + */ +double get_process_load(void) { + psinfo_t info; + + // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s + // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. + if (get_info("/proc/self/psinfo",&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) == 0) { + return (double) info.pr_pctcpu / 0x8000; + } + return -1.0; +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getSystemCpuLoad +(JNIEnv *env, jobject dummy) +{ + return get_cpu_load(-1); +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuLoad +(JNIEnv *env, jobject dummy) +{ + return get_process_load(); +} + --- old/src/windows/classes/com/sun/management/OperatingSystem.java Thu Nov 7 12:14:08 2013 +++ /dev/null Thu Nov 7 12:14:08 2013 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2003, 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.management; - -import sun.management.VMManagement; - -/** - * Implementation class for the operating system. - * Standard and committed hotspot-specific metrics if any. - * - * ManagementFactory.getOperatingSystemMXBean() returns an instance - * of this class. - */ -class OperatingSystem - extends sun.management.OperatingSystemImpl - implements OperatingSystemMXBean { - - // psapiLock is a lock to make sure only one thread loading - // PSAPI DLL. - private static Object psapiLock = new Object(); - - OperatingSystem(VMManagement vm) { - super(vm); - } - - public long getCommittedVirtualMemorySize() { - synchronized (psapiLock) { - return getCommittedVirtualMemorySize0(); - } - } - private native long getCommittedVirtualMemorySize0(); - - public native long getTotalSwapSpaceSize(); - public native long getFreeSwapSpaceSize(); - public native long getProcessCpuTime(); - public native long getFreePhysicalMemorySize(); - public native long getTotalPhysicalMemorySize(); - public native double getSystemCpuLoad(); - public native double getProcessCpuLoad(); - - static { - initialize(); - } - private static native void initialize(); -} --- /dev/null Thu Nov 7 12:14:08 2013 +++ new/src/windows/classes/sun/management/OperatingSystemImpl.java Thu Nov 7 12:14:08 2013 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003, 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 sun.management; + +import java.lang.management.OperatingSystemMXBean; + +/** + * Implementation class for the operating system. + * Standard and committed hotspot-specific metrics if any. + * + * ManagementFactory.getOperatingSystemMXBean() returns an instance + * of this class. + */ +class OperatingSystemImpl extends AbstractOperatingSystemImpl + implements OperatingSystemMXBean { + + // psapiLock is a lock to make sure only one thread loading + // PSAPI DLL. + private static Object psapiLock = new Object(); + + OperatingSystemImpl(VMManagement vm) { + super(vm); + } + + public long getCommittedVirtualMemorySize() { + synchronized (psapiLock) { + return getCommittedVirtualMemorySize0(); + } + } + private native long getCommittedVirtualMemorySize0(); + + public native long getTotalSwapSpaceSize(); + public native long getFreeSwapSpaceSize(); + public native long getProcessCpuTime(); + public native long getFreePhysicalMemorySize(); + public native long getTotalPhysicalMemorySize(); + public native double getSystemCpuLoad(); + public native double getProcessCpuLoad(); + + static { + initialize(); + } + private static native void initialize(); +} --- old/src/windows/native/com/sun/management/OperatingSystem_md.c Thu Nov 7 12:14:10 2013 +++ /dev/null Thu Nov 7 12:14:10 2013 @@ -1,941 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -#include "jni.h" -#include "jni_util.h" -#include "jlong.h" -#include "jvm.h" -#include "management.h" -#include "com_sun_management_OperatingSystem.h" - -#include -#include -#include - -#include -#pragma warning (push,0) -#include -#pragma warning (pop) -#include -#include -#include -#include - -/* Disable warnings due to broken header files from Microsoft... */ -#pragma warning(push, 3) -#include -#include -#include -#pragma warning(pop) - -typedef unsigned __int32 juint; -typedef unsigned __int64 julong; - -typedef enum boolean_values { false=0, true=1}; - -static void set_low(jlong* value, jint low) { - *value &= (jlong)0xffffffff << 32; - *value |= (jlong)(julong)(juint)low; -} - -static void set_high(jlong* value, jint high) { - *value &= (jlong)(julong)(juint)0xffffffff; - *value |= (jlong)high << 32; -} - -static jlong jlong_from(jint h, jint l) { - jlong result = 0; // initialization to avoid warning - set_high(&result, h); - set_low(&result, l); - return result; -} - -static HANDLE main_process; - -int perfiInit(void); - -JNIEXPORT void JNICALL -Java_com_sun_management_OperatingSystem_initialize - (JNIEnv *env, jclass cls) -{ - main_process = GetCurrentProcess(); - perfiInit(); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getCommittedVirtualMemorySize0 - (JNIEnv *env, jobject mbean) -{ - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) { - return (jlong)-1L; - } else { - return (jlong) pmc.PagefileUsage; - } -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getTotalSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPageFile; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getFreeSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPageFile; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getProcessCpuTime - (JNIEnv *env, jobject mbean) -{ - - FILETIME process_creation_time, process_exit_time, - process_user_time, process_kernel_time; - - // Using static variables declared above - // Units are 100-ns intervals. Convert to ns. - GetProcessTimes(main_process, &process_creation_time, - &process_exit_time, - &process_kernel_time, &process_user_time); - return (jlong_from(process_user_time.dwHighDateTime, - process_user_time.dwLowDateTime) + - jlong_from(process_kernel_time.dwHighDateTime, - process_kernel_time.dwLowDateTime)) * 100; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getFreePhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPhys; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getTotalPhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPhys; -} - -// Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer. -// Let's just ignore it, since we make sure we have enough buffer anyway. -static int -pdh_fail(PDH_STATUS pdhStat) { - return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA; -} - -// INFO: Using PDH APIs Correctly in a Localized Language (Q287159) -// http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159 -// The index value for the base system counters and objects like processor, -// process, thread, memory, and so forth are always the same irrespective -// of the localized version of the operating system or service pack installed. -#define PDH_PROCESSOR_IDX ((DWORD) 238) -#define PDH_PROCESSOR_TIME_IDX ((DWORD) 6) -#define PDH_PRIV_PROCESSOR_TIME_IDX ((DWORD) 144) -#define PDH_PROCESS_IDX ((DWORD) 230) -#define PDH_ID_PROCESS_IDX ((DWORD) 784) -#define PDH_CONTEXT_SWITCH_RATE_IDX ((DWORD) 146) -#define PDH_SYSTEM_IDX ((DWORD) 2) -#define PDH_VIRTUAL_BYTES_IDX ((DWORD) 174) - -typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)( - HQUERY hQuery, - LPCSTR szFullCounterPath, - DWORD dwUserData, - HCOUNTER *phCounter - ); -typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)( - LPCWSTR szDataSource, - DWORD dwUserData, - HQUERY *phQuery - ); -typedef DWORD (WINAPI *PdhCloseQueryFunc)( - HQUERY hQuery - ); -typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)( - HQUERY hQuery - ); -typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)( - HCOUNTER hCounter, - DWORD dwFormat, - LPDWORD lpdwType, - PPDH_FMT_COUNTERVALUE pValue - ); -typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)( - LPCTSTR szDataSource, - LPCTSTR szMachineName, - LPCTSTR szObjectName, - LPTSTR mszCounterList, - LPDWORD pcchCounterListLength, - LPTSTR mszInstanceList, - LPDWORD pcchInstanceListLength, - DWORD dwDetailLevel, - DWORD dwFlags - ); -typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)( - HCOUNTER hCounter - ); -typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)( - LPCSTR szMachineName, - DWORD dwNameIndex, - LPSTR szNameBuffer, - LPDWORD pcchNameBufferSize - ); -typedef PDH_STATUS (WINAPI *PdhMakeCounterPathFunc)( - PDH_COUNTER_PATH_ELEMENTS *pCounterPathElements, - LPTSTR szFullPathBuffer, - LPDWORD pcchBufferSize, - DWORD dwFlags - ); - -static PdhAddCounterFunc PdhAddCounter_i; -static PdhOpenQueryFunc PdhOpenQuery_i; -static PdhCloseQueryFunc PdhCloseQuery_i; -static PdhCollectQueryDataFunc PdhCollectQueryData_i; -static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i; -static PdhEnumObjectItemsFunc PdhEnumObjectItems_i; -static PdhRemoveCounterFunc PdhRemoveCounter_i; -static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i; -static PdhMakeCounterPathFunc PdhMakeCounterPath_i; - -static HANDLE thisProcess; -static double cpuFactor; -static DWORD num_cpus; - -#define FT2JLONG(X) ((((jlong)X.dwHighDateTime) << 32) | ((jlong)X.dwLowDateTime)) -#define COUNTER_BUF_SIZE 256 -// Min time between query updates. -#define MIN_UPDATE_INTERVAL 500 -#define CONFIG_SUCCESSFUL 0 - -/** - * Struct for PDH queries. - */ -typedef struct { - HQUERY query; - uint64_t lastUpdate; // Last time query was updated (current millis). -} UpdateQueryS, *UpdateQueryP; - -/** - * Struct for the processor load counters. - */ -typedef struct { - UpdateQueryS query; - HCOUNTER* counters; - int noOfCounters; -} MultipleCounterQueryS, *MultipleCounterQueryP; - -/** - * Struct for the jvm process load counter. - */ -typedef struct { - UpdateQueryS query; - HCOUNTER counter; -} SingleCounterQueryS, *SingleCounterQueryP; - -static char* getProcessPDHHeader(void); - -/** - * Currently available counters. - */ -static SingleCounterQueryS cntCtxtSwitchRate; -static SingleCounterQueryS cntVirtualSize; -static SingleCounterQueryS cntProcLoad; -static SingleCounterQueryS cntProcSystemLoad; -static MultipleCounterQueryS multiCounterCPULoad; - -static CRITICAL_SECTION processHeaderLock; -static CRITICAL_SECTION initializationLock; - -/** - * Initialize the perf module at startup. - */ -int -perfiInit(void) -{ - InitializeCriticalSection(&processHeaderLock); - InitializeCriticalSection(&initializationLock); - return 0; -} - -/** - * Dynamically sets up function pointers to the PDH library. - * - * @return CONFIG_SUCCESSFUL on success, negative on failure. - */ -static int -get_functions(HMODULE h, char *ebuf, size_t elen) { - // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods - PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA"); - PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA"); - PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery"); - PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData"); - PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue"); - PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA"); - PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter"); - PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA"); - PdhMakeCounterPath_i = (PdhMakeCounterPathFunc)GetProcAddress(h, "PdhMakeCounterPathA"); - - if (PdhAddCounter_i == NULL || PdhOpenQuery_i == NULL || - PdhCloseQuery_i == NULL || PdhCollectQueryData_i == NULL || - PdhGetFormattedCounterValue_i == NULL || PdhEnumObjectItems_i == NULL || - PdhRemoveCounter_i == NULL || PdhLookupPerfNameByIndex_i == NULL || PdhMakeCounterPath_i == NULL) - { - _snprintf(ebuf, elen, "Required method could not be found."); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Returns the counter value as a double for the specified query. - * Will collect the query data and update the counter values as necessary. - * - * @param query the query to update (if needed). - * @param c the counter to read. - * @param value where to store the formatted value. - * @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc) - * @return CONFIG_SUCCESSFUL if no error - * -1 if PdhCollectQueryData fails - * -2 if PdhGetFormattedCounterValue fails - */ -static int -getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) { - clock_t now; - now = clock(); - - // Need to limit how often we update the query - // to mimise the heisenberg effect. - // (PDH behaves erratically if the counters are - // queried too often, especially counters that - // store and use values from two consecutive updates, - // like cpu load.) - if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) { - if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) { - return -1; - } - query->lastUpdate = now; - } - - if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) { - return -2; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Places the resolved counter name of the counter at the specified index in the - * supplied buffer. There must be enough space in the buffer to hold the counter name. - * - * @param index the counter index as specified in the registry. - * @param buf the buffer in which to place the counter name. - * @param size the size of the counter name buffer. - * @param ebuf the error message buffer. - * @param elen the length of the error buffer. - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -find_name(DWORD index, char *buf, DWORD size) { - PDH_STATUS res; - - if ((res = PdhLookupPerfNameByIndex_i(NULL, index, buf, &size)) != ERROR_SUCCESS) { - - /* printf("Could not open counter %d: error=0x%08x", index, res); */ - /* if (res == PDH_CSTATUS_NO_MACHINE) { */ - /* printf("User probably does not have sufficient privileges to use"); */ - /* printf("performance counters. If you are running on Windows 2003"); */ - /* printf("or Windows Vista, make sure the user is in the"); */ - /* printf("Performance Logs user group."); */ - /* } */ - return -1; - } - - if (size == 0) { - /* printf("Failed to get counter name for %d: empty string", index); */ - return -1; - } - - // windows vista does not null-terminate the string (allthough the docs says it will) - buf[size - 1] = '\0'; - return CONFIG_SUCCESSFUL; -} - -/** - * Sets up the supplied SingleCounterQuery to listen for the specified counter. - * initPDH() must have been run prior to calling this function! - * - * @param counterQuery the counter query to set up. - * @param counterString the string specifying the path to the counter. - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * @returns CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initSingleCounterQuery(SingleCounterQueryP counterQuery, char *counterString) { - if (PdhOpenQuery_i(NULL, 0, &counterQuery->query.query) != ERROR_SUCCESS) { - /* printf("Could not open query for %s", counterString); */ - return -1; - } - if (PdhAddCounter_i(counterQuery->query.query, counterString, 0, &counterQuery->counter) != ERROR_SUCCESS) { - /* printf("Could not add counter %s for query", counterString); */ - if (counterQuery->counter != NULL) { - PdhRemoveCounter_i(counterQuery->counter); - } - if (counterQuery->query.query != NULL) { - PdhCloseQuery_i(counterQuery->query.query); - } - memset(counterQuery, 0, sizeof(SingleCounterQueryS)); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Sets up the supplied SingleCounterQuery to listen for the time spent - * by the HotSpot process. - * - * @param counterQuery the counter query to set up as a process counter. - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * @returns CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initProcLoadCounter(void) { - char time[COUNTER_BUF_SIZE]; - char counter[COUNTER_BUF_SIZE*2]; - - if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); - return initSingleCounterQuery(&cntProcLoad, counter); -} - -static int -initProcSystemLoadCounter(void) { - char time[COUNTER_BUF_SIZE]; - char counter[COUNTER_BUF_SIZE*2]; - - if (find_name(PDH_PRIV_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); - return initSingleCounterQuery(&cntProcSystemLoad, counter); -} - -/** - * Sets up the supplied MultipleCounterQuery to check on the processors. - * (Comment: Refactor and prettify as with the the SingleCounter queries - * if more MultipleCounterQueries are discovered.) - * - * initPDH() must have been run prior to calling this function. - * - * @param multiQuery a pointer to a MultipleCounterQueryS, will be filled in with - * the necessary info to check the PDH processor counters. - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initProcessorCounters(void) { - char processor[COUNTER_BUF_SIZE]; //'Processor' == #238 - char time[COUNTER_BUF_SIZE]; //'Time' == 6 - DWORD c_size, i_size; - HQUERY tmpQuery; - DWORD i, p_count; - BOOL error; - char *instances, *tmp; - PDH_STATUS pdhStat; - - c_size = i_size = 0; - tmpQuery = NULL; - error = false; - - // This __try / __except stuff is there since Windows 2000 beta (or so) sometimes triggered - // an access violation when the user had insufficient privileges to use the performance - // counters. This was previously guarded by a very ugly piece of code which disabled the - // global trap handling in JRockit. Don't know if this really is needed anymore, but otoh, - // if we keep it we don't crash on Win2k beta. /Ihse, 2005-05-30 - __try { - if (find_name(PDH_PROCESSOR_IDX, processor, sizeof(processor)-1) < 0) { - return -1; - } - } __except (EXCEPTION_EXECUTE_HANDLER) { // We'll catch all exceptions here. - /* printf("User does not have sufficient privileges to use performance counters"); */ - return -1; - } - - if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - //ok, now we have enough to enumerate all processors. - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processor, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - NULL, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - if (pdh_fail(pdhStat)) { - /* printf("could not enumerate processors (1) error=%d", pdhStat); */ - return -1; - } - - // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) - instances = calloc(i_size, 1); - if (instances == NULL) { - /* printf("could not allocate memory (1) %d bytes", i_size); */ - error = true; - goto end; - } - - c_size = 0; - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processor, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - instances, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - if (pdh_fail(pdhStat)) { - /* printf("could not enumerate processors (2) error=%d", pdhStat); */ - error = true; - goto end; - } - //count perf count instances. - for (p_count = 0, tmp = instances; *tmp != 0; tmp = &tmp[lstrlen(tmp)+1], p_count++); - - //is this correct for HT? - assert(p_count == num_cpus+1); - - //ok, have number of perf counters. - multiCounterCPULoad.counters = calloc(p_count, sizeof(HCOUNTER)); - if (multiCounterCPULoad.counters == NULL) { - /* printf("could not allocate memory (2) count=%d", p_count); */ - error = true; - goto end; - } - - multiCounterCPULoad.noOfCounters = p_count; - - if (PdhOpenQuery_i(NULL, 0, &multiCounterCPULoad.query.query) != ERROR_SUCCESS) { - /* printf("could not create query"); */ - error = true; - goto end; - } - //now, fetch the counters. - for (i = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[lstrlen(tmp)+1], i++) { - char counter[2*COUNTER_BUF_SIZE]; - - _snprintf(counter, sizeof(counter)-1, "\\%s(%s)\\%s", processor, tmp, time); - - if (PdhAddCounter_i(multiCounterCPULoad.query.query, counter, 0, &multiCounterCPULoad.counters[i]) != ERROR_SUCCESS) { - /* printf("error adding processor counter %s", counter); */ - error = true; - goto end; - } - } - - free(instances); - instances = NULL; - - // Query once to initialize the counters needing at least two queries - // (like the % CPU usage) to calculate correctly. - if (PdhCollectQueryData_i(multiCounterCPULoad.query.query) != ERROR_SUCCESS) - error = true; - - end: - if (instances != NULL) { - free(instances); - } - if (tmpQuery != NULL) { - PdhCloseQuery_i(tmpQuery); - } - if (error) { - int i; - - if (multiCounterCPULoad.counters != NULL) { - for (i = 0; i < multiCounterCPULoad.noOfCounters; i++) { - if (multiCounterCPULoad.counters[i] != NULL) { - PdhRemoveCounter_i(multiCounterCPULoad.counters[i]); - } - } - free(multiCounterCPULoad.counters[i]); - } - if (multiCounterCPULoad.query.query != NULL) { - PdhCloseQuery_i(multiCounterCPULoad.query.query); - } - memset(&multiCounterCPULoad, 0, sizeof(MultipleCounterQueryS)); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Help function that initializes the PDH process header for the JRockit process. - * (You should probably use getProcessPDHHeader() instead!) - * - * initPDH() must have been run prior to calling this function. - * - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * - * @return the PDH instance description corresponding to the JVM process. - */ -static char* -initProcessPDHHeader(void) { - static char hotspotheader[2*COUNTER_BUF_SIZE]; - - char counter[2*COUNTER_BUF_SIZE]; - char processes[COUNTER_BUF_SIZE]; //'Process' == #230 - char pid[COUNTER_BUF_SIZE]; //'ID Process' == 784 - char module_name[MAX_PATH]; - PDH_STATUS pdhStat; - DWORD c_size = 0, i_size = 0; - HQUERY tmpQuery = NULL; - int i, myPid = _getpid(); - BOOL error = false; - char *instances, *tmp, *instance_name, *dot_pos; - - tmpQuery = NULL; - myPid = _getpid(); - error = false; - - if (find_name(PDH_PROCESS_IDX, processes, sizeof(processes) - 1) < 0) { - return NULL; - } - - if (find_name(PDH_ID_PROCESS_IDX, pid, sizeof(pid) - 1) < 0) { - return NULL; - } - //time is same. - - c_size = 0; - i_size = 0; - - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processes, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - NULL, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - //ok, now we have enough to enumerate all processes - if (pdh_fail(pdhStat)) { - /* printf("Could not enumerate processes (1) error=%d", pdhStat); */ - return NULL; - } - - // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) - if ((instances = calloc(i_size, 1)) == NULL) { - /* printf("Could not allocate memory %d bytes", i_size); */ - error = true; - goto end; - } - - c_size = 0; - - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processes, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - instances, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - // ok, now we have enough to enumerate all processes - if (pdh_fail(pdhStat)) { - /* printf("Could not enumerate processes (2) error=%d", pdhStat); */ - error = true; - goto end; - } - - if (PdhOpenQuery_i(NULL, 0, &tmpQuery) != ERROR_SUCCESS) { - /* printf("Could not create temporary query"); */ - error = true; - goto end; - } - - // Find our module name and use it to extract the instance name used by PDH - if (GetModuleFileName(NULL, module_name, MAX_PATH) >= MAX_PATH-1) { - /* printf("Module name truncated"); */ - error = true; - goto end; - } - instance_name = strrchr(module_name, '\\'); //drop path - instance_name++; //skip slash - dot_pos = strchr(instance_name, '.'); //drop .exe - dot_pos[0] = '\0'; - - //now, fetch the counters. - for (tmp = instances; *tmp != 0 && !error; tmp = &tmp[lstrlen(tmp)+1]) { - HCOUNTER hc = NULL; - BOOL done = false; - - // Skip until we find our own process name - if (strcmp(tmp, instance_name) != 0) { - continue; - } - - // iterate over all instance indexes and try to find our own pid - for (i = 0; !done && !error; i++){ - PDH_STATUS res; - _snprintf(counter, sizeof(counter)-1, "\\%s(%s#%d)\\%s", processes, tmp, i, pid); - - if (PdhAddCounter_i(tmpQuery, counter, 0, &hc) != ERROR_SUCCESS) { - /* printf("Failed to create process id query"); */ - error = true; - goto end; - } - - res = PdhCollectQueryData_i(tmpQuery); - - if (res == PDH_INVALID_HANDLE) { - /* printf("Failed to query process id"); */ - res = -1; - done = true; - } else if (res == PDH_NO_DATA) { - done = true; - } else { - PDH_FMT_COUNTERVALUE cv; - - PdhGetFormattedCounterValue_i(hc, PDH_FMT_LONG, NULL, &cv); - /* - * This check seems to be needed for Win2k SMP boxes, since - * they for some reason don't return PDH_NO_DATA for non existing - * counters. - */ - if (cv.CStatus != PDH_CSTATUS_VALID_DATA) { - done = true; - } else if (cv.longValue == myPid) { - _snprintf(hotspotheader, sizeof(hotspotheader)-1, "\\%s(%s#%d)\0", processes, tmp, i); - PdhRemoveCounter_i(hc); - goto end; - } - } - PdhRemoveCounter_i(hc); - } - } - end: - if (instances != NULL) { - free(instances); - } - if (tmpQuery != NULL) { - PdhCloseQuery_i(tmpQuery); - } - if (error) { - return NULL; - } - return hotspotheader; -} - -/** - * Returns the PDH string prefix identifying the HotSpot process. Use this prefix when getting - * counters from the PDH process object representing HotSpot. - * - * Note: this call may take some time to complete. - * - * @param ebuf error buffer. - * @param elen error buffer length. - * - * @return the header to be used when retrieving PDH counters from the HotSpot process. - * Will return NULL if the call failed. - */ -static char * -getProcessPDHHeader(void) { - static char *processHeader = NULL; - - EnterCriticalSection(&processHeaderLock); { - if (processHeader == NULL) { - processHeader = initProcessPDHHeader(); - } - } LeaveCriticalSection(&processHeaderLock); - return processHeader; -} - -int perfInit(void); - -double -perfGetCPULoad(int which) -{ - PDH_FMT_COUNTERVALUE cv; - HCOUNTER c; - - if (perfInit() < 0) { - // warn? - return -1.0; - } - - if (multiCounterCPULoad.query.query == NULL) { - // warn? - return -1.0; - } - - if (which == -1) { - c = multiCounterCPULoad.counters[multiCounterCPULoad.noOfCounters - 1]; - } else { - if (which < multiCounterCPULoad.noOfCounters) { - c = multiCounterCPULoad.counters[which]; - } else { - return -1.0; - } - } - if (getPerformanceData(&multiCounterCPULoad.query, c, &cv, PDH_FMT_DOUBLE ) == CONFIG_SUCCESSFUL) { - return cv.doubleValue / 100; - } - return -1.0; -} - -double -perfGetProcessLoad(void) -{ - PDH_FMT_COUNTERVALUE cv; - - if (perfInit() < 0) { - // warn? - return -1.0; - } - - if (cntProcLoad.query.query == NULL) { - // warn? - return -1.0; - } - - if (getPerformanceData(&cntProcLoad.query, cntProcLoad.counter, &cv, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == CONFIG_SUCCESSFUL) { - double d = cv.doubleValue / cpuFactor; - d = min(1, d); - d = max(0, d); - return d; - } - return -1.0; -} - -/** - * Helper to initialize the PDH library. Loads the library and sets up the functions. - * Note that once loaded, we will never unload the PDH library. - * - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -int -perfInit(void) { - static HMODULE h; - static BOOL running, inited; - - int error; - - if (running) { - return CONFIG_SUCCESSFUL; - } - - error = CONFIG_SUCCESSFUL; - - // this is double checked locking again, but we try to bypass the worst by - // implicit membar at end of lock. - EnterCriticalSection(&initializationLock); { - if (!inited) { - char buf[64] = ""; - SYSTEM_INFO si; - - // CMH. But windows will not care about our affinity when giving - // us measurements. Need the real, raw num cpus. - - GetSystemInfo(&si); - num_cpus = si.dwNumberOfProcessors; - // Initialize the denominator for the jvm load calculations - cpuFactor = num_cpus * 100; - - /** - * Do this dynamically, so we don't fail to start on systems without pdh. - */ - if ((h = LoadLibrary("pdh.dll")) == NULL) { - /* printf("Could not load pdh.dll (%d)", GetLastError()); */ - error = -2; - } else if (get_functions(h, buf, sizeof(buf)) < 0) { - FreeLibrary(h); - h = NULL; - error = -2; - /* printf("Failed to init pdh functions: %s.\n", buf); */ - } else { - if (initProcessorCounters() != 0) { - /* printf("Failed to init system load counters.\n"); */ - } else if (initProcLoadCounter() != 0) { - /* printf("Failed to init process load counter.\n"); */ - } else if (initProcSystemLoadCounter() != 0) { - /* printf("Failed to init process system load counter.\n"); */ - } else { - inited = true; - } - } - } - } LeaveCriticalSection(&initializationLock); - - if (inited && error == CONFIG_SUCCESSFUL) { - running = true; - } - - return error; -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_OperatingSystem_getSystemCpuLoad -(JNIEnv *env, jobject dummy) -{ - return perfGetCPULoad(-1); -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_OperatingSystem_getProcessCpuLoad -(JNIEnv *env, jobject dummy) -{ - return perfGetProcessLoad(); -} --- /dev/null Thu Nov 7 12:14:10 2013 +++ new/src/windows/native/sun/management/OperatingSystemImpl.c Thu Nov 7 12:14:09 2013 @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2003, 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. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "jvm.h" +#include "management.h" +#include "sun_management_OperatingSystemImpl.h" + +#include +#include +#include + +#include +#pragma warning (push,0) +#include +#pragma warning (pop) +#include +#include +#include +#include + +/* Disable warnings due to broken header files from Microsoft... */ +#pragma warning(push, 3) +#include +#include +#include +#pragma warning(pop) + +typedef unsigned __int32 juint; +typedef unsigned __int64 julong; + +typedef enum boolean_values { false=0, true=1}; + +static void set_low(jlong* value, jint low) { + *value &= (jlong)0xffffffff << 32; + *value |= (jlong)(julong)(juint)low; +} + +static void set_high(jlong* value, jint high) { + *value &= (jlong)(julong)(juint)0xffffffff; + *value |= (jlong)high << 32; +} + +static jlong jlong_from(jint h, jint l) { + jlong result = 0; // initialization to avoid warning + set_high(&result, h); + set_low(&result, l); + return result; +} + +static HANDLE main_process; + +int perfiInit(void); + +JNIEXPORT void JNICALL +Java_sun_management_OperatingSystemImpl_initialize + (JNIEnv *env, jclass cls) +{ + main_process = GetCurrentProcess(); + perfiInit(); +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize0 + (JNIEnv *env, jobject mbean) +{ + PROCESS_MEMORY_COUNTERS pmc; + if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) { + return (jlong)-1L; + } else { + return (jlong) pmc.PagefileUsage; + } +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize + (JNIEnv *env, jobject mbean) +{ + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullTotalPageFile; +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize + (JNIEnv *env, jobject mbean) +{ + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullAvailPageFile; +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuTime + (JNIEnv *env, jobject mbean) +{ + + FILETIME process_creation_time, process_exit_time, + process_user_time, process_kernel_time; + + // Using static variables declared above + // Units are 100-ns intervals. Convert to ns. + GetProcessTimes(main_process, &process_creation_time, + &process_exit_time, + &process_kernel_time, &process_user_time); + return (jlong_from(process_user_time.dwHighDateTime, + process_user_time.dwLowDateTime) + + jlong_from(process_kernel_time.dwHighDateTime, + process_kernel_time.dwLowDateTime)) * 100; +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize + (JNIEnv *env, jobject mbean) +{ + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullAvailPhys; +} + +JNIEXPORT jlong JNICALL +Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize + (JNIEnv *env, jobject mbean) +{ + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullTotalPhys; +} + +// Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer. +// Let's just ignore it, since we make sure we have enough buffer anyway. +static int +pdh_fail(PDH_STATUS pdhStat) { + return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA; +} + +// INFO: Using PDH APIs Correctly in a Localized Language (Q287159) +// http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159 +// The index value for the base system counters and objects like processor, +// process, thread, memory, and so forth are always the same irrespective +// of the localized version of the operating system or service pack installed. +#define PDH_PROCESSOR_IDX ((DWORD) 238) +#define PDH_PROCESSOR_TIME_IDX ((DWORD) 6) +#define PDH_PRIV_PROCESSOR_TIME_IDX ((DWORD) 144) +#define PDH_PROCESS_IDX ((DWORD) 230) +#define PDH_ID_PROCESS_IDX ((DWORD) 784) +#define PDH_CONTEXT_SWITCH_RATE_IDX ((DWORD) 146) +#define PDH_SYSTEM_IDX ((DWORD) 2) +#define PDH_VIRTUAL_BYTES_IDX ((DWORD) 174) + +typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)( + HQUERY hQuery, + LPCSTR szFullCounterPath, + DWORD dwUserData, + HCOUNTER *phCounter + ); +typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)( + LPCWSTR szDataSource, + DWORD dwUserData, + HQUERY *phQuery + ); +typedef DWORD (WINAPI *PdhCloseQueryFunc)( + HQUERY hQuery + ); +typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)( + HQUERY hQuery + ); +typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)( + HCOUNTER hCounter, + DWORD dwFormat, + LPDWORD lpdwType, + PPDH_FMT_COUNTERVALUE pValue + ); +typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)( + LPCTSTR szDataSource, + LPCTSTR szMachineName, + LPCTSTR szObjectName, + LPTSTR mszCounterList, + LPDWORD pcchCounterListLength, + LPTSTR mszInstanceList, + LPDWORD pcchInstanceListLength, + DWORD dwDetailLevel, + DWORD dwFlags + ); +typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)( + HCOUNTER hCounter + ); +typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)( + LPCSTR szMachineName, + DWORD dwNameIndex, + LPSTR szNameBuffer, + LPDWORD pcchNameBufferSize + ); +typedef PDH_STATUS (WINAPI *PdhMakeCounterPathFunc)( + PDH_COUNTER_PATH_ELEMENTS *pCounterPathElements, + LPTSTR szFullPathBuffer, + LPDWORD pcchBufferSize, + DWORD dwFlags + ); + +static PdhAddCounterFunc PdhAddCounter_i; +static PdhOpenQueryFunc PdhOpenQuery_i; +static PdhCloseQueryFunc PdhCloseQuery_i; +static PdhCollectQueryDataFunc PdhCollectQueryData_i; +static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i; +static PdhEnumObjectItemsFunc PdhEnumObjectItems_i; +static PdhRemoveCounterFunc PdhRemoveCounter_i; +static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i; +static PdhMakeCounterPathFunc PdhMakeCounterPath_i; + +static HANDLE thisProcess; +static double cpuFactor; +static DWORD num_cpus; + +#define FT2JLONG(X) ((((jlong)X.dwHighDateTime) << 32) | ((jlong)X.dwLowDateTime)) +#define COUNTER_BUF_SIZE 256 +// Min time between query updates. +#define MIN_UPDATE_INTERVAL 500 +#define CONFIG_SUCCESSFUL 0 + +/** + * Struct for PDH queries. + */ +typedef struct { + HQUERY query; + uint64_t lastUpdate; // Last time query was updated (current millis). +} UpdateQueryS, *UpdateQueryP; + +/** + * Struct for the processor load counters. + */ +typedef struct { + UpdateQueryS query; + HCOUNTER* counters; + int noOfCounters; +} MultipleCounterQueryS, *MultipleCounterQueryP; + +/** + * Struct for the jvm process load counter. + */ +typedef struct { + UpdateQueryS query; + HCOUNTER counter; +} SingleCounterQueryS, *SingleCounterQueryP; + +static char* getProcessPDHHeader(void); + +/** + * Currently available counters. + */ +static SingleCounterQueryS cntCtxtSwitchRate; +static SingleCounterQueryS cntVirtualSize; +static SingleCounterQueryS cntProcLoad; +static SingleCounterQueryS cntProcSystemLoad; +static MultipleCounterQueryS multiCounterCPULoad; + +static CRITICAL_SECTION processHeaderLock; +static CRITICAL_SECTION initializationLock; + +/** + * Initialize the perf module at startup. + */ +int +perfiInit(void) +{ + InitializeCriticalSection(&processHeaderLock); + InitializeCriticalSection(&initializationLock); + return 0; +} + +/** + * Dynamically sets up function pointers to the PDH library. + * + * @return CONFIG_SUCCESSFUL on success, negative on failure. + */ +static int +get_functions(HMODULE h, char *ebuf, size_t elen) { + // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods + PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA"); + PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA"); + PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery"); + PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData"); + PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue"); + PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA"); + PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter"); + PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA"); + PdhMakeCounterPath_i = (PdhMakeCounterPathFunc)GetProcAddress(h, "PdhMakeCounterPathA"); + + if (PdhAddCounter_i == NULL || PdhOpenQuery_i == NULL || + PdhCloseQuery_i == NULL || PdhCollectQueryData_i == NULL || + PdhGetFormattedCounterValue_i == NULL || PdhEnumObjectItems_i == NULL || + PdhRemoveCounter_i == NULL || PdhLookupPerfNameByIndex_i == NULL || PdhMakeCounterPath_i == NULL) + { + _snprintf(ebuf, elen, "Required method could not be found."); + return -1; + } + return CONFIG_SUCCESSFUL; +} + +/** + * Returns the counter value as a double for the specified query. + * Will collect the query data and update the counter values as necessary. + * + * @param query the query to update (if needed). + * @param c the counter to read. + * @param value where to store the formatted value. + * @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc) + * @return CONFIG_SUCCESSFUL if no error + * -1 if PdhCollectQueryData fails + * -2 if PdhGetFormattedCounterValue fails + */ +static int +getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) { + clock_t now; + now = clock(); + + // Need to limit how often we update the query + // to mimise the heisenberg effect. + // (PDH behaves erratically if the counters are + // queried too often, especially counters that + // store and use values from two consecutive updates, + // like cpu load.) + if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) { + if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) { + return -1; + } + query->lastUpdate = now; + } + + if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) { + return -2; + } + return CONFIG_SUCCESSFUL; +} + +/** + * Places the resolved counter name of the counter at the specified index in the + * supplied buffer. There must be enough space in the buffer to hold the counter name. + * + * @param index the counter index as specified in the registry. + * @param buf the buffer in which to place the counter name. + * @param size the size of the counter name buffer. + * @param ebuf the error message buffer. + * @param elen the length of the error buffer. + * @return CONFIG_SUCCESSFUL if successful, negative on failure. + */ +static int +find_name(DWORD index, char *buf, DWORD size) { + PDH_STATUS res; + + if ((res = PdhLookupPerfNameByIndex_i(NULL, index, buf, &size)) != ERROR_SUCCESS) { + + /* printf("Could not open counter %d: error=0x%08x", index, res); */ + /* if (res == PDH_CSTATUS_NO_MACHINE) { */ + /* printf("User probably does not have sufficient privileges to use"); */ + /* printf("performance counters. If you are running on Windows 2003"); */ + /* printf("or Windows Vista, make sure the user is in the"); */ + /* printf("Performance Logs user group."); */ + /* } */ + return -1; + } + + if (size == 0) { + /* printf("Failed to get counter name for %d: empty string", index); */ + return -1; + } + + // windows vista does not null-terminate the string (allthough the docs says it will) + buf[size - 1] = '\0'; + return CONFIG_SUCCESSFUL; +} + +/** + * Sets up the supplied SingleCounterQuery to listen for the specified counter. + * initPDH() must have been run prior to calling this function! + * + * @param counterQuery the counter query to set up. + * @param counterString the string specifying the path to the counter. + * @param ebuf the error buffer. + * @param elen the length of the error buffer. + * @returns CONFIG_SUCCESSFUL if successful, negative on failure. + */ +static int +initSingleCounterQuery(SingleCounterQueryP counterQuery, char *counterString) { + if (PdhOpenQuery_i(NULL, 0, &counterQuery->query.query) != ERROR_SUCCESS) { + /* printf("Could not open query for %s", counterString); */ + return -1; + } + if (PdhAddCounter_i(counterQuery->query.query, counterString, 0, &counterQuery->counter) != ERROR_SUCCESS) { + /* printf("Could not add counter %s for query", counterString); */ + if (counterQuery->counter != NULL) { + PdhRemoveCounter_i(counterQuery->counter); + } + if (counterQuery->query.query != NULL) { + PdhCloseQuery_i(counterQuery->query.query); + } + memset(counterQuery, 0, sizeof(SingleCounterQueryS)); + return -1; + } + return CONFIG_SUCCESSFUL; +} + +/** + * Sets up the supplied SingleCounterQuery to listen for the time spent + * by the HotSpot process. + * + * @param counterQuery the counter query to set up as a process counter. + * @param ebuf the error buffer. + * @param elen the length of the error buffer. + * @returns CONFIG_SUCCESSFUL if successful, negative on failure. + */ +static int +initProcLoadCounter(void) { + char time[COUNTER_BUF_SIZE]; + char counter[COUNTER_BUF_SIZE*2]; + + if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { + return -1; + } + _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); + return initSingleCounterQuery(&cntProcLoad, counter); +} + +static int +initProcSystemLoadCounter(void) { + char time[COUNTER_BUF_SIZE]; + char counter[COUNTER_BUF_SIZE*2]; + + if (find_name(PDH_PRIV_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { + return -1; + } + _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); + return initSingleCounterQuery(&cntProcSystemLoad, counter); +} + +/** + * Sets up the supplied MultipleCounterQuery to check on the processors. + * (Comment: Refactor and prettify as with the the SingleCounter queries + * if more MultipleCounterQueries are discovered.) + * + * initPDH() must have been run prior to calling this function. + * + * @param multiQuery a pointer to a MultipleCounterQueryS, will be filled in with + * the necessary info to check the PDH processor counters. + * @return CONFIG_SUCCESSFUL if successful, negative on failure. + */ +static int +initProcessorCounters(void) { + char processor[COUNTER_BUF_SIZE]; //'Processor' == #238 + char time[COUNTER_BUF_SIZE]; //'Time' == 6 + DWORD c_size, i_size; + HQUERY tmpQuery; + DWORD i, p_count; + BOOL error; + char *instances, *tmp; + PDH_STATUS pdhStat; + + c_size = i_size = 0; + tmpQuery = NULL; + error = false; + + // This __try / __except stuff is there since Windows 2000 beta (or so) sometimes triggered + // an access violation when the user had insufficient privileges to use the performance + // counters. This was previously guarded by a very ugly piece of code which disabled the + // global trap handling in JRockit. Don't know if this really is needed anymore, but otoh, + // if we keep it we don't crash on Win2k beta. /Ihse, 2005-05-30 + __try { + if (find_name(PDH_PROCESSOR_IDX, processor, sizeof(processor)-1) < 0) { + return -1; + } + } __except (EXCEPTION_EXECUTE_HANDLER) { // We'll catch all exceptions here. + /* printf("User does not have sufficient privileges to use performance counters"); */ + return -1; + } + + if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { + return -1; + } + //ok, now we have enough to enumerate all processors. + pdhStat = PdhEnumObjectItems_i ( + NULL, // reserved + NULL, // local machine + processor, // object to enumerate + NULL, // pass in NULL buffers + &c_size, // and 0 length to get + NULL, // required size + &i_size, // of the buffers in chars + PERF_DETAIL_WIZARD, // counter detail level + 0); + if (pdh_fail(pdhStat)) { + /* printf("could not enumerate processors (1) error=%d", pdhStat); */ + return -1; + } + + // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) + instances = calloc(i_size, 1); + if (instances == NULL) { + /* printf("could not allocate memory (1) %d bytes", i_size); */ + error = true; + goto end; + } + + c_size = 0; + pdhStat = PdhEnumObjectItems_i ( + NULL, // reserved + NULL, // local machine + processor, // object to enumerate + NULL, // pass in NULL buffers + &c_size, // and 0 length to get + instances, // required size + &i_size, // of the buffers in chars + PERF_DETAIL_WIZARD, // counter detail level + 0); + + if (pdh_fail(pdhStat)) { + /* printf("could not enumerate processors (2) error=%d", pdhStat); */ + error = true; + goto end; + } + //count perf count instances. + for (p_count = 0, tmp = instances; *tmp != 0; tmp = &tmp[lstrlen(tmp)+1], p_count++); + + //is this correct for HT? + assert(p_count == num_cpus+1); + + //ok, have number of perf counters. + multiCounterCPULoad.counters = calloc(p_count, sizeof(HCOUNTER)); + if (multiCounterCPULoad.counters == NULL) { + /* printf("could not allocate memory (2) count=%d", p_count); */ + error = true; + goto end; + } + + multiCounterCPULoad.noOfCounters = p_count; + + if (PdhOpenQuery_i(NULL, 0, &multiCounterCPULoad.query.query) != ERROR_SUCCESS) { + /* printf("could not create query"); */ + error = true; + goto end; + } + //now, fetch the counters. + for (i = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[lstrlen(tmp)+1], i++) { + char counter[2*COUNTER_BUF_SIZE]; + + _snprintf(counter, sizeof(counter)-1, "\\%s(%s)\\%s", processor, tmp, time); + + if (PdhAddCounter_i(multiCounterCPULoad.query.query, counter, 0, &multiCounterCPULoad.counters[i]) != ERROR_SUCCESS) { + /* printf("error adding processor counter %s", counter); */ + error = true; + goto end; + } + } + + free(instances); + instances = NULL; + + // Query once to initialize the counters needing at least two queries + // (like the % CPU usage) to calculate correctly. + if (PdhCollectQueryData_i(multiCounterCPULoad.query.query) != ERROR_SUCCESS) + error = true; + + end: + if (instances != NULL) { + free(instances); + } + if (tmpQuery != NULL) { + PdhCloseQuery_i(tmpQuery); + } + if (error) { + int i; + + if (multiCounterCPULoad.counters != NULL) { + for (i = 0; i < multiCounterCPULoad.noOfCounters; i++) { + if (multiCounterCPULoad.counters[i] != NULL) { + PdhRemoveCounter_i(multiCounterCPULoad.counters[i]); + } + } + free(multiCounterCPULoad.counters[i]); + } + if (multiCounterCPULoad.query.query != NULL) { + PdhCloseQuery_i(multiCounterCPULoad.query.query); + } + memset(&multiCounterCPULoad, 0, sizeof(MultipleCounterQueryS)); + return -1; + } + return CONFIG_SUCCESSFUL; +} + +/** + * Help function that initializes the PDH process header for the JRockit process. + * (You should probably use getProcessPDHHeader() instead!) + * + * initPDH() must have been run prior to calling this function. + * + * @param ebuf the error buffer. + * @param elen the length of the error buffer. + * + * @return the PDH instance description corresponding to the JVM process. + */ +static char* +initProcessPDHHeader(void) { + static char hotspotheader[2*COUNTER_BUF_SIZE]; + + char counter[2*COUNTER_BUF_SIZE]; + char processes[COUNTER_BUF_SIZE]; //'Process' == #230 + char pid[COUNTER_BUF_SIZE]; //'ID Process' == 784 + char module_name[MAX_PATH]; + PDH_STATUS pdhStat; + DWORD c_size = 0, i_size = 0; + HQUERY tmpQuery = NULL; + int i, myPid = _getpid(); + BOOL error = false; + char *instances, *tmp, *instance_name, *dot_pos; + + tmpQuery = NULL; + myPid = _getpid(); + error = false; + + if (find_name(PDH_PROCESS_IDX, processes, sizeof(processes) - 1) < 0) { + return NULL; + } + + if (find_name(PDH_ID_PROCESS_IDX, pid, sizeof(pid) - 1) < 0) { + return NULL; + } + //time is same. + + c_size = 0; + i_size = 0; + + pdhStat = PdhEnumObjectItems_i ( + NULL, // reserved + NULL, // local machine + processes, // object to enumerate + NULL, // pass in NULL buffers + &c_size, // and 0 length to get + NULL, // required size + &i_size, // of the buffers in chars + PERF_DETAIL_WIZARD, // counter detail level + 0); + + //ok, now we have enough to enumerate all processes + if (pdh_fail(pdhStat)) { + /* printf("Could not enumerate processes (1) error=%d", pdhStat); */ + return NULL; + } + + // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) + if ((instances = calloc(i_size, 1)) == NULL) { + /* printf("Could not allocate memory %d bytes", i_size); */ + error = true; + goto end; + } + + c_size = 0; + + pdhStat = PdhEnumObjectItems_i ( + NULL, // reserved + NULL, // local machine + processes, // object to enumerate + NULL, // pass in NULL buffers + &c_size, // and 0 length to get + instances, // required size + &i_size, // of the buffers in chars + PERF_DETAIL_WIZARD, // counter detail level + 0); + + // ok, now we have enough to enumerate all processes + if (pdh_fail(pdhStat)) { + /* printf("Could not enumerate processes (2) error=%d", pdhStat); */ + error = true; + goto end; + } + + if (PdhOpenQuery_i(NULL, 0, &tmpQuery) != ERROR_SUCCESS) { + /* printf("Could not create temporary query"); */ + error = true; + goto end; + } + + // Find our module name and use it to extract the instance name used by PDH + if (GetModuleFileName(NULL, module_name, MAX_PATH) >= MAX_PATH-1) { + /* printf("Module name truncated"); */ + error = true; + goto end; + } + instance_name = strrchr(module_name, '\\'); //drop path + instance_name++; //skip slash + dot_pos = strchr(instance_name, '.'); //drop .exe + dot_pos[0] = '\0'; + + //now, fetch the counters. + for (tmp = instances; *tmp != 0 && !error; tmp = &tmp[lstrlen(tmp)+1]) { + HCOUNTER hc = NULL; + BOOL done = false; + + // Skip until we find our own process name + if (strcmp(tmp, instance_name) != 0) { + continue; + } + + // iterate over all instance indexes and try to find our own pid + for (i = 0; !done && !error; i++){ + PDH_STATUS res; + _snprintf(counter, sizeof(counter)-1, "\\%s(%s#%d)\\%s", processes, tmp, i, pid); + + if (PdhAddCounter_i(tmpQuery, counter, 0, &hc) != ERROR_SUCCESS) { + /* printf("Failed to create process id query"); */ + error = true; + goto end; + } + + res = PdhCollectQueryData_i(tmpQuery); + + if (res == PDH_INVALID_HANDLE) { + /* printf("Failed to query process id"); */ + res = -1; + done = true; + } else if (res == PDH_NO_DATA) { + done = true; + } else { + PDH_FMT_COUNTERVALUE cv; + + PdhGetFormattedCounterValue_i(hc, PDH_FMT_LONG, NULL, &cv); + /* + * This check seems to be needed for Win2k SMP boxes, since + * they for some reason don't return PDH_NO_DATA for non existing + * counters. + */ + if (cv.CStatus != PDH_CSTATUS_VALID_DATA) { + done = true; + } else if (cv.longValue == myPid) { + _snprintf(hotspotheader, sizeof(hotspotheader)-1, "\\%s(%s#%d)\0", processes, tmp, i); + PdhRemoveCounter_i(hc); + goto end; + } + } + PdhRemoveCounter_i(hc); + } + } + end: + if (instances != NULL) { + free(instances); + } + if (tmpQuery != NULL) { + PdhCloseQuery_i(tmpQuery); + } + if (error) { + return NULL; + } + return hotspotheader; +} + +/** + * Returns the PDH string prefix identifying the HotSpot process. Use this prefix when getting + * counters from the PDH process object representing HotSpot. + * + * Note: this call may take some time to complete. + * + * @param ebuf error buffer. + * @param elen error buffer length. + * + * @return the header to be used when retrieving PDH counters from the HotSpot process. + * Will return NULL if the call failed. + */ +static char * +getProcessPDHHeader(void) { + static char *processHeader = NULL; + + EnterCriticalSection(&processHeaderLock); { + if (processHeader == NULL) { + processHeader = initProcessPDHHeader(); + } + } LeaveCriticalSection(&processHeaderLock); + return processHeader; +} + +int perfInit(void); + +double +perfGetCPULoad(int which) +{ + PDH_FMT_COUNTERVALUE cv; + HCOUNTER c; + + if (perfInit() < 0) { + // warn? + return -1.0; + } + + if (multiCounterCPULoad.query.query == NULL) { + // warn? + return -1.0; + } + + if (which == -1) { + c = multiCounterCPULoad.counters[multiCounterCPULoad.noOfCounters - 1]; + } else { + if (which < multiCounterCPULoad.noOfCounters) { + c = multiCounterCPULoad.counters[which]; + } else { + return -1.0; + } + } + if (getPerformanceData(&multiCounterCPULoad.query, c, &cv, PDH_FMT_DOUBLE ) == CONFIG_SUCCESSFUL) { + return cv.doubleValue / 100; + } + return -1.0; +} + +double +perfGetProcessLoad(void) +{ + PDH_FMT_COUNTERVALUE cv; + + if (perfInit() < 0) { + // warn? + return -1.0; + } + + if (cntProcLoad.query.query == NULL) { + // warn? + return -1.0; + } + + if (getPerformanceData(&cntProcLoad.query, cntProcLoad.counter, &cv, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == CONFIG_SUCCESSFUL) { + double d = cv.doubleValue / cpuFactor; + d = min(1, d); + d = max(0, d); + return d; + } + return -1.0; +} + +/** + * Helper to initialize the PDH library. Loads the library and sets up the functions. + * Note that once loaded, we will never unload the PDH library. + * + * @return CONFIG_SUCCESSFUL if successful, negative on failure. + */ +int +perfInit(void) { + static HMODULE h; + static BOOL running, inited; + + int error; + + if (running) { + return CONFIG_SUCCESSFUL; + } + + error = CONFIG_SUCCESSFUL; + + // this is double checked locking again, but we try to bypass the worst by + // implicit membar at end of lock. + EnterCriticalSection(&initializationLock); { + if (!inited) { + char buf[64] = ""; + SYSTEM_INFO si; + + // CMH. But windows will not care about our affinity when giving + // us measurements. Need the real, raw num cpus. + + GetSystemInfo(&si); + num_cpus = si.dwNumberOfProcessors; + // Initialize the denominator for the jvm load calculations + cpuFactor = num_cpus * 100; + + /** + * Do this dynamically, so we don't fail to start on systems without pdh. + */ + if ((h = LoadLibrary("pdh.dll")) == NULL) { + /* printf("Could not load pdh.dll (%d)", GetLastError()); */ + error = -2; + } else if (get_functions(h, buf, sizeof(buf)) < 0) { + FreeLibrary(h); + h = NULL; + error = -2; + /* printf("Failed to init pdh functions: %s.\n", buf); */ + } else { + if (initProcessorCounters() != 0) { + /* printf("Failed to init system load counters.\n"); */ + } else if (initProcLoadCounter() != 0) { + /* printf("Failed to init process load counter.\n"); */ + } else if (initProcSystemLoadCounter() != 0) { + /* printf("Failed to init process system load counter.\n"); */ + } else { + inited = true; + } + } + } + } LeaveCriticalSection(&initializationLock); + + if (inited && error == CONFIG_SUCCESSFUL) { + running = true; + } + + return error; +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getSystemCpuLoad +(JNIEnv *env, jobject dummy) +{ + return perfGetCPULoad(-1); +} + +JNIEXPORT jdouble JNICALL +Java_sun_management_OperatingSystemImpl_getProcessCpuLoad +(JNIEnv *env, jobject dummy) +{ + return perfGetProcessLoad(); +} --- old/src/solaris/classes/com/sun/management/OSMBeanFactory.java Thu Nov 7 12:14:11 2013 +++ /dev/null Thu Nov 7 12:14:11 2013 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2003, 2004, 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.management; - -import java.lang.management.OperatingSystemMXBean; -import sun.management.VMManagement; - -/** - * Operating system dependent MBean factory. - *

- * WARNING: While this class is public, it should not be treated as - * public API and its API may change in incompatable ways between dot dot - * releases and even patch releases. You should not rely on this class. - */ -@jdk.Exported(false) -public class OSMBeanFactory { - /* static factory class */ - private OSMBeanFactory() {}; - - private static UnixOperatingSystem osMBean = null; - - public static synchronized OperatingSystemMXBean - getOperatingSystemMXBean(VMManagement jvm) { - - if (osMBean == null) { - osMBean = new UnixOperatingSystem(jvm); - } - return (OperatingSystemMXBean) osMBean; - } -} --- old/src/windows/classes/com/sun/management/OSMBeanFactory.java Thu Nov 7 12:14:12 2013 +++ /dev/null Thu Nov 7 12:14:12 2013 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2003, 2004, 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.management; - -import java.lang.management.OperatingSystemMXBean; -import sun.management.VMManagement; - -/** - * Operating system dependent MBean factory. - *

- * WARNING: While this class is public, it should not be treated as - * public API and its API may change in incompatable ways between dot dot - * releases and even patch releases. You should not rely on this class. - */ -public class OSMBeanFactory { - /* static factory class */ - private OSMBeanFactory() {}; - - private static OperatingSystem osMBean = null; - - public static synchronized OperatingSystemMXBean - getOperatingSystemMXBean(VMManagement jvm) { - - if (osMBean == null) { - osMBean = new OperatingSystem(jvm); - } - return (OperatingSystemMXBean) osMBean; - } -}