1.1 --- a/make/java/management/Makefile Wed May 11 14:12:50 2011 -0700
1.2 +++ b/make/java/management/Makefile Wed May 11 18:52:46 2011 -0700
1.3 @@ -63,6 +63,20 @@
1.4 FILES_c += UnixOperatingSystem_md.c
1.5
1.6 FILES_export += com/sun/management/UnixOperatingSystem.java
1.7 +
1.8 +ifeq ($(PLATFORM),solaris)
1.9 +
1.10 +FILES_c += SolarisOperatingSystem.c
1.11 +OTHER_LDLIBS += -lkstat
1.12 +
1.13 +endif # PLATFORM solaris
1.14 +
1.15 +ifeq ($(PLATFORM),linux)
1.16 +
1.17 +FILES_c += LinuxOperatingSystem.c
1.18 +
1.19 +endif # PLATFORM linux
1.20 +
1.21 endif # PLATFORM
1.22
1.23 #
2.1 --- a/make/java/management/mapfile-vers Wed May 11 14:12:50 2011 -0700
2.2 +++ b/make/java/management/mapfile-vers Wed May 11 18:52:46 2011 -0700
2.3 @@ -32,7 +32,9 @@
2.4 Java_com_sun_management_UnixOperatingSystem_getFreeSwapSpaceSize;
2.5 Java_com_sun_management_UnixOperatingSystem_getMaxFileDescriptorCount;
2.6 Java_com_sun_management_UnixOperatingSystem_getOpenFileDescriptorCount;
2.7 + Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad;
2.8 Java_com_sun_management_UnixOperatingSystem_getProcessCpuTime;
2.9 + Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad;
2.10 Java_com_sun_management_UnixOperatingSystem_getTotalPhysicalMemorySize;
2.11 Java_com_sun_management_UnixOperatingSystem_getTotalSwapSpaceSize;
2.12 Java_com_sun_management_UnixOperatingSystem_initialize;
3.1 --- a/src/share/classes/com/sun/management/OperatingSystemMXBean.java Wed May 11 14:12:50 2011 -0700
3.2 +++ b/src/share/classes/com/sun/management/OperatingSystemMXBean.java Wed May 11 18:52:46 2011 -0700
3.3 @@ -92,4 +92,39 @@
3.4 * @return the total amount of physical memory in bytes.
3.5 */
3.6 public long getTotalPhysicalMemorySize();
3.7 +
3.8 + /**
3.9 + * Returns the "recent cpu usage" for the whole system. This value is a
3.10 + * double in the [0.0,1.0] interval. A value of 0.0 means that all CPUs
3.11 + * were idle during the recent period of time observed, while a value
3.12 + * of 1.0 means that all CPUs were actively running 100% of the time
3.13 + * during the recent period being observed. All values betweens 0.0 and
3.14 + * 1.0 are possible depending of the activities going on in the system.
3.15 + * If the system recent cpu usage is not available, the method returns a
3.16 + * negative value.
3.17 + *
3.18 + * @return the "recent cpu usage" for the whole system; a negative
3.19 + * value if not available.
3.20 + * @since 1.7
3.21 + */
3.22 + public double getSystemCpuLoad();
3.23 +
3.24 + /**
3.25 + * Returns the "recent cpu usage" for the Java Virtual Machine process.
3.26 + * This value is a double in the [0.0,1.0] interval. A value of 0.0 means
3.27 + * that none of the CPUs were running threads from the JVM process during
3.28 + * the recent period of time observed, while a value of 1.0 means that all
3.29 + * CPUs were actively running threads from the JVM 100% of the time
3.30 + * during the recent period being observed. Threads from the JVM include
3.31 + * the application threads as well as the JVM internal threads. All values
3.32 + * betweens 0.0 and 1.0 are possible depending of the activities going on
3.33 + * in the JVM process and the whole system. If the Java Virtual Machine
3.34 + * recent CPU usage is not available, the method returns a negative value.
3.35 + *
3.36 + * @return the "recent cpu usage" for the Java Virtual Machine process;
3.37 + * a negative value if not available.
3.38 + * @since 1.7
3.39 + */
3.40 + public double getProcessCpuLoad();
3.41 +
3.42 }
4.1 --- a/src/solaris/classes/com/sun/management/UnixOperatingSystem.java Wed May 11 14:12:50 2011 -0700
4.2 +++ b/src/solaris/classes/com/sun/management/UnixOperatingSystem.java Wed May 11 18:52:46 2011 -0700
4.3 @@ -50,6 +50,8 @@
4.4 public native long getTotalPhysicalMemorySize();
4.5 public native long getOpenFileDescriptorCount();
4.6 public native long getMaxFileDescriptorCount();
4.7 + public native double getSystemCpuLoad();
4.8 + public native double getProcessCpuLoad();
4.9
4.10 static {
4.11 initialize();
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/src/solaris/native/com/sun/management/LinuxOperatingSystem.c Wed May 11 18:52:46 2011 -0700
5.3 @@ -0,0 +1,332 @@
5.4 +/*
5.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 + *
5.8 + * This code is free software; you can redistribute it and/or modify it
5.9 + * under the terms of the GNU General Public License version 2 only, as
5.10 + * published by the Free Software Foundation. Oracle designates this
5.11 + * particular file as subject to the "Classpath" exception as provided
5.12 + * by Oracle in the LICENSE file that accompanied this code.
5.13 + *
5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 + * version 2 for more details (a copy is included in the LICENSE file that
5.18 + * accompanied this code).
5.19 + *
5.20 + * You should have received a copy of the GNU General Public License version
5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 + *
5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5.25 + * or visit www.oracle.com if you need additional information or have any
5.26 + * questions.
5.27 + */
5.28 +
5.29 +#include <stdio.h>
5.30 +#include <stdint.h>
5.31 +#include <stdarg.h>
5.32 +#include <unistd.h>
5.33 +#include <errno.h>
5.34 +#include <string.h>
5.35 +#include <sys/resource.h>
5.36 +#include <sys/types.h>
5.37 +#include <dirent.h>
5.38 +#include <stdlib.h>
5.39 +#include <dlfcn.h>
5.40 +#include <pthread.h>
5.41 +#include "com_sun_management_UnixOperatingSystem.h"
5.42 +
5.43 +struct ticks {
5.44 + uint64_t used;
5.45 + uint64_t usedKernel;
5.46 + uint64_t total;
5.47 +};
5.48 +
5.49 +typedef struct ticks ticks;
5.50 +
5.51 +typedef enum {
5.52 + CPU_LOAD_VM_ONLY,
5.53 + CPU_LOAD_GLOBAL,
5.54 +} CpuLoadTarget;
5.55 +
5.56 +static struct perfbuf {
5.57 + int nProcs;
5.58 + ticks jvmTicks;
5.59 + ticks cpuTicks;
5.60 + ticks *cpus;
5.61 +} counters;
5.62 +
5.63 +#define DEC_64 "%lld"
5.64 +
5.65 +static void next_line(FILE *f) {
5.66 + while (fgetc(f) != '\n');
5.67 +}
5.68 +
5.69 +/**
5.70 + * Return the total number of ticks since the system was booted.
5.71 + * If the usedTicks parameter is not NULL, it will be filled with
5.72 + * the number of ticks spent on actual processes (user, system or
5.73 + * nice processes) since system boot. Note that this is the total number
5.74 + * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
5.75 + * n times the number of ticks that has passed in clock time.
5.76 + *
5.77 + * Returns a negative value if the reading of the ticks failed.
5.78 + */
5.79 +static int get_totalticks(int which, ticks *pticks) {
5.80 + FILE *fh;
5.81 + uint64_t userTicks, niceTicks, systemTicks, idleTicks;
5.82 + int n;
5.83 +
5.84 + if((fh = fopen("/proc/stat", "r")) == NULL) {
5.85 + return -1;
5.86 + }
5.87 +
5.88 + n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64,
5.89 + &userTicks, &niceTicks, &systemTicks, &idleTicks);
5.90 +
5.91 + // Move to next line
5.92 + next_line(fh);
5.93 +
5.94 + //find the line for requested cpu faster to just iterate linefeeds?
5.95 + if (which != -1) {
5.96 + int i;
5.97 + for (i = 0; i < which; i++) {
5.98 + if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, &userTicks, &niceTicks, &systemTicks, &idleTicks) != 4) {
5.99 + fclose(fh);
5.100 + return -2;
5.101 + }
5.102 + next_line(fh);
5.103 + }
5.104 + n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 "\n",
5.105 + &userTicks, &niceTicks, &systemTicks, &idleTicks);
5.106 + }
5.107 +
5.108 + fclose(fh);
5.109 + if (n != 4) {
5.110 + return -2;
5.111 + }
5.112 +
5.113 + pticks->used = userTicks + niceTicks;
5.114 + pticks->usedKernel = systemTicks;
5.115 + pticks->total = userTicks + niceTicks + systemTicks + idleTicks;
5.116 +
5.117 + return 0;
5.118 +}
5.119 +
5.120 +static int vread_statdata(const char *procfile, const char *fmt, va_list args) {
5.121 + FILE *f;
5.122 + int n;
5.123 + char buf[2048];
5.124 +
5.125 + if ((f = fopen(procfile, "r")) == NULL) {
5.126 + return -1;
5.127 + }
5.128 +
5.129 + if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
5.130 + char *tmp;
5.131 +
5.132 + buf[n-1] = '\0';
5.133 + /** skip through pid and exec name. the exec name _could be wacky_ (renamed) and
5.134 + * make scanf go mupp.
5.135 + */
5.136 + if ((tmp = strrchr(buf, ')')) != NULL) {
5.137 + // skip the ')' and the following space but check that the buffer is long enough
5.138 + tmp += 2;
5.139 + if (tmp < buf + n) {
5.140 + n = vsscanf(tmp, fmt, args);
5.141 + }
5.142 + }
5.143 + }
5.144 +
5.145 + fclose(f);
5.146 +
5.147 + return n;
5.148 +}
5.149 +
5.150 +static int read_statdata(const char *procfile, const char *fmt, ...) {
5.151 + int n;
5.152 + va_list args;
5.153 +
5.154 + va_start(args, fmt);
5.155 + n = vread_statdata(procfile, fmt, args);
5.156 + va_end(args);
5.157 + return n;
5.158 +}
5.159 +
5.160 +/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
5.161 +static int read_ticks(const char *procfile, uint64_t *userTicks, uint64_t *systemTicks) {
5.162 + return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "DEC_64" "DEC_64,
5.163 + userTicks, systemTicks
5.164 + );
5.165 +}
5.166 +
5.167 +/**
5.168 + * Return the number of ticks spent in any of the processes belonging
5.169 + * to the JVM on any CPU.
5.170 + */
5.171 +static int get_jvmticks(ticks *pticks) {
5.172 + uint64_t userTicks;
5.173 + uint64_t systemTicks;
5.174 +
5.175 + if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) {
5.176 + return -1;
5.177 + }
5.178 +
5.179 + // get the total
5.180 + if (get_totalticks(-1, pticks) < 0) {
5.181 + return -1;
5.182 + }
5.183 +
5.184 + pticks->used = userTicks;
5.185 + pticks->usedKernel = systemTicks;
5.186 +
5.187 + return 0;
5.188 +}
5.189 +
5.190 +/**
5.191 + * This method must be called first, before any data can be gathererd.
5.192 + */
5.193 +int perfInit() {
5.194 + static int initialized=1;
5.195 +
5.196 + if (!initialized) {
5.197 + int i;
5.198 +
5.199 + int n = sysconf(_SC_NPROCESSORS_ONLN);
5.200 + if (n <= 0) {
5.201 + n = 1;
5.202 + }
5.203 +
5.204 + counters.cpus = calloc(n,sizeof(ticks));
5.205 + if (counters.cpus != NULL) {
5.206 + // For the CPU load
5.207 + get_totalticks(-1, &counters.cpuTicks);
5.208 +
5.209 + for (i = 0; i < n; i++) {
5.210 + get_totalticks(i, &counters.cpus[i]);
5.211 + }
5.212 + // For JVM load
5.213 + get_jvmticks(&counters.jvmTicks);
5.214 + initialized = 1;
5.215 + }
5.216 + }
5.217 +
5.218 + return initialized ? 0 : -1;
5.219 +}
5.220 +
5.221 +#define MAX(a,b) (a>b?a:b)
5.222 +#define MIN(a,b) (a<b?a:b)
5.223 +
5.224 +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
5.225 +
5.226 +/**
5.227 + * Return the load of the CPU as a double. 1.0 means the CPU process uses all
5.228 + * available time for user or system processes, 0.0 means the CPU uses all time
5.229 + * being idle.
5.230 + *
5.231 + * Returns a negative value if there is a problem in determining the CPU load.
5.232 + */
5.233 +
5.234 +static double get_cpuload_internal(int which, double *pkernelLoad, CpuLoadTarget target) {
5.235 + uint64_t udiff, kdiff, tdiff;
5.236 + ticks *pticks, tmp;
5.237 + double user_load = -1.0;
5.238 + int failed = 0;
5.239 +
5.240 + *pkernelLoad = 0.0;
5.241 +
5.242 + pthread_mutex_lock(&lock);
5.243 +
5.244 + if(perfInit() == 0) {
5.245 +
5.246 + if (target == CPU_LOAD_VM_ONLY) {
5.247 + pticks = &counters.jvmTicks;
5.248 + } else if (which == -1) {
5.249 + pticks = &counters.cpuTicks;
5.250 + } else {
5.251 + pticks = &counters.cpus[which];
5.252 + }
5.253 +
5.254 + tmp = *pticks;
5.255 +
5.256 + if (target == CPU_LOAD_VM_ONLY) {
5.257 + if (get_jvmticks(pticks) != 0) {
5.258 + failed = 1;
5.259 + }
5.260 + } else if (get_totalticks(which, pticks) < 0) {
5.261 + failed = 1;
5.262 + }
5.263 +
5.264 + if(!failed) {
5.265 + // seems like we sometimes end up with less kernel ticks when
5.266 + // reading /proc/self/stat a second time, timing issue between cpus?
5.267 + if (pticks->usedKernel < tmp.usedKernel) {
5.268 + kdiff = 0;
5.269 + } else {
5.270 + kdiff = pticks->usedKernel - tmp.usedKernel;
5.271 + }
5.272 + tdiff = pticks->total - tmp.total;
5.273 + udiff = pticks->used - tmp.used;
5.274 +
5.275 + if (tdiff == 0) {
5.276 + user_load = 0;
5.277 + } else {
5.278 + if (tdiff < (udiff + kdiff)) {
5.279 + tdiff = udiff + kdiff;
5.280 + }
5.281 + *pkernelLoad = (kdiff / (double)tdiff);
5.282 + // BUG9044876, normalize return values to sane values
5.283 + *pkernelLoad = MAX(*pkernelLoad, 0.0);
5.284 + *pkernelLoad = MIN(*pkernelLoad, 1.0);
5.285 +
5.286 + user_load = (udiff / (double)tdiff);
5.287 + user_load = MAX(user_load, 0.0);
5.288 + user_load = MIN(user_load, 1.0);
5.289 + }
5.290 + }
5.291 + }
5.292 + pthread_mutex_unlock(&lock);
5.293 + return user_load;
5.294 +}
5.295 +
5.296 +double get_cpu_load(int which) {
5.297 + double u, s;
5.298 + u = get_cpuload_internal(which, &s, CPU_LOAD_GLOBAL);
5.299 + if (u < 0) {
5.300 + return -1.0;
5.301 + }
5.302 + // Cap total systemload to 1.0
5.303 + return MIN((u + s), 1.0);
5.304 +}
5.305 +
5.306 +double get_process_load() {
5.307 + double u, s;
5.308 + u = get_cpuload_internal(-1, &s, CPU_LOAD_VM_ONLY);
5.309 + if (u < 0) {
5.310 + return -1.0;
5.311 + }
5.312 + return u + s;
5.313 +}
5.314 +
5.315 +JNIEXPORT jdouble JNICALL
5.316 +Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad
5.317 +(JNIEnv *env, jobject dummy)
5.318 +{
5.319 + if(perfInit() == 0) {
5.320 + return get_cpu_load(-1);
5.321 + } else {
5.322 + return -1.0;
5.323 + }
5.324 +}
5.325 +
5.326 +JNIEXPORT jdouble JNICALL
5.327 +Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad
5.328 +(JNIEnv *env, jobject dummy)
5.329 +{
5.330 + if(perfInit() == 0) {
5.331 + return get_process_load();
5.332 + } else {
5.333 + return -1.0;
5.334 + }
5.335 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/src/solaris/native/com/sun/management/SolarisOperatingSystem.c Wed May 11 18:52:46 2011 -0700
6.3 @@ -0,0 +1,241 @@
6.4 +/*
6.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6.7 + *
6.8 + * This code is free software; you can redistribute it and/or modify it
6.9 + * under the terms of the GNU General Public License version 2 only, as
6.10 + * published by the Free Software Foundation. Oracle designates this
6.11 + * particular file as subject to the "Classpath" exception as provided
6.12 + * by Oracle in the LICENSE file that accompanied this code.
6.13 + *
6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6.17 + * version 2 for more details (a copy is included in the LICENSE file that
6.18 + * accompanied this code).
6.19 + *
6.20 + * You should have received a copy of the GNU General Public License version
6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6.23 + *
6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
6.25 + * or visit www.oracle.com if you need additional information or have any
6.26 + * questions.
6.27 + */
6.28 +
6.29 +#include <fcntl.h>
6.30 +#include <kstat.h>
6.31 +#include <procfs.h>
6.32 +#include <unistd.h>
6.33 +#include <stdlib.h>
6.34 +#include <stdio.h>
6.35 +#include <string.h>
6.36 +#include <sys/sysinfo.h>
6.37 +#include <sys/lwp.h>
6.38 +#include <pthread.h>
6.39 +#include <utmpx.h>
6.40 +#include <dlfcn.h>
6.41 +#include <sys/loadavg.h>
6.42 +#include <jni.h>
6.43 +#include "jvm.h"
6.44 +#include "com_sun_management_UnixOperatingSystem.h"
6.45 +
6.46 +typedef struct {
6.47 + kstat_t *kstat;
6.48 + uint64_t last_idle;
6.49 + uint64_t last_total;
6.50 + double last_ratio;
6.51 +} cpuload_t;
6.52 +
6.53 +static cpuload_t *cpu_loads = NULL;
6.54 +static unsigned int num_cpus;
6.55 +static kstat_ctl_t *kstat_ctrl = NULL;
6.56 +
6.57 +static void map_cpu_kstat_counters() {
6.58 + kstat_t *kstat;
6.59 + int i;
6.60 +
6.61 + // Get number of CPU(s)
6.62 + if ((num_cpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
6.63 + num_cpus = 1;
6.64 + }
6.65 +
6.66 + // Data structure for saving CPU load
6.67 + if ((cpu_loads = calloc(num_cpus,sizeof(cpuload_t))) == NULL) {
6.68 + return;
6.69 + }
6.70 +
6.71 + // Get kstat cpu_stat counters for every CPU
6.72 + // (loop over kstat to find our cpu_stat(s)
6.73 + i = 0;
6.74 + for (kstat = kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
6.75 + if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
6.76 +
6.77 + if (kstat_read(kstat_ctrl, kstat, NULL) == -1) {
6.78 + // Failed to initialize kstat for this CPU so ignore it
6.79 + continue;
6.80 + }
6.81 +
6.82 + if (i == num_cpus) {
6.83 + // Found more cpu_stats than reported CPUs
6.84 + break;
6.85 + }
6.86 +
6.87 + cpu_loads[i++].kstat = kstat;
6.88 + }
6.89 + }
6.90 +}
6.91 +
6.92 +static int init_cpu_kstat_counters() {
6.93 + static int initialized = 0;
6.94 +
6.95 + // Concurrence in this method is prevented by the lock in
6.96 + // the calling method get_cpu_load();
6.97 + if(!initialized) {
6.98 + if ((kstat_ctrl = kstat_open()) != NULL) {
6.99 + map_cpu_kstat_counters();
6.100 + initialized = 1;
6.101 + }
6.102 + }
6.103 + return initialized ? 0 : -1;
6.104 +}
6.105 +
6.106 +static void update_cpu_kstat_counters() {
6.107 + if(kstat_chain_update(kstat_ctrl) != 0) {
6.108 + free(cpu_loads);
6.109 + map_cpu_kstat_counters();
6.110 + }
6.111 +}
6.112 +
6.113 +int read_cpustat(cpuload_t *load, cpu_stat_t *cpu_stat) {
6.114 + if (load->kstat == NULL) {
6.115 + // no handle.
6.116 + return -1;
6.117 + }
6.118 + if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == -1) {
6.119 + // disabling for now, a kstat chain update is likely to happen next time
6.120 + load->kstat = NULL;
6.121 + return -1;
6.122 + }
6.123 + return 0;
6.124 +}
6.125 +
6.126 +double get_single_cpu_load(unsigned int n) {
6.127 + cpuload_t *load;
6.128 + cpu_stat_t cpu_stat;
6.129 + uint_t *usage;
6.130 + uint64_t c_idle;
6.131 + uint64_t c_total;
6.132 + uint64_t d_idle;
6.133 + uint64_t d_total;
6.134 + int i;
6.135 +
6.136 + if (n >= num_cpus) {
6.137 + return -1.0;
6.138 + }
6.139 +
6.140 + load = &cpu_loads[n];
6.141 + if (read_cpustat(load, &cpu_stat) < 0) {
6.142 + return -1.0;
6.143 + }
6.144 +
6.145 + usage = cpu_stat.cpu_sysinfo.cpu;
6.146 + c_idle = usage[CPU_IDLE];
6.147 +
6.148 + for (c_total = 0, i = 0; i < CPU_STATES; i++) {
6.149 + c_total += usage[i];
6.150 + }
6.151 +
6.152 + // Calculate diff against previous snapshot
6.153 + d_idle = c_idle - load->last_idle;
6.154 + d_total = c_total - load->last_total;
6.155 +
6.156 + /** update if weve moved */
6.157 + if (d_total > 0) {
6.158 + // Save current values for next time around
6.159 + load->last_idle = c_idle;
6.160 + load->last_total = c_total;
6.161 + load->last_ratio = (double) (d_total - d_idle) / d_total;
6.162 + }
6.163 +
6.164 + return load->last_ratio;
6.165 +}
6.166 +
6.167 +int get_info(const char *path, void *info, size_t s, off_t o) {
6.168 + int fd;
6.169 + int ret = 0;
6.170 + if ((fd = open(path, O_RDONLY)) < 0) {
6.171 + return -1;
6.172 + }
6.173 + if (pread(fd, info, s, o) != s) {
6.174 + ret = -1;
6.175 + }
6.176 + close(fd);
6.177 + return ret;
6.178 +}
6.179 +
6.180 +#define MIN(a, b) ((a < b) ? a : b)
6.181 +
6.182 +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
6.183 +
6.184 +/**
6.185 + * Return the cpu load (0-1) for proc number 'which' (or average all if which == -1)
6.186 + */
6.187 +double get_cpu_load(int which) {
6.188 + double load =.0;
6.189 +
6.190 + pthread_mutex_lock(&lock);
6.191 + if(init_cpu_kstat_counters()==0) {
6.192 +
6.193 + update_cpu_kstat_counters();
6.194 +
6.195 + if (which == -1) {
6.196 + unsigned int i;
6.197 + double t;
6.198 +
6.199 + for (t = .0, i = 0; i < num_cpus; i++) {
6.200 + t += get_single_cpu_load(i);
6.201 + }
6.202 +
6.203 + // Cap total systemload to 1.0
6.204 + load = MIN((t / num_cpus), 1.0);
6.205 + } else {
6.206 + load = MIN(get_single_cpu_load(which), 1.0);
6.207 + }
6.208 + } else {
6.209 + load = -1.0;
6.210 + }
6.211 + pthread_mutex_unlock(&lock);
6.212 +
6.213 + return load;
6.214 +}
6.215 +
6.216 +/**
6.217 + * Return the cpu load (0-1) for the current process (i.e the JVM)
6.218 + * or -1.0 if the get_info() call failed
6.219 + */
6.220 +double get_process_load(void) {
6.221 + psinfo_t info;
6.222 +
6.223 + // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
6.224 + // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
6.225 + if (get_info("/proc/self/psinfo",&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) == 0) {
6.226 + return (double) info.pr_pctcpu / 0x8000;
6.227 + }
6.228 + return -1.0;
6.229 +}
6.230 +
6.231 +JNIEXPORT jdouble JNICALL
6.232 +Java_com_sun_management_UnixOperatingSystem_getSystemCpuLoad
6.233 +(JNIEnv *env, jobject dummy)
6.234 +{
6.235 + return get_cpu_load(-1);
6.236 +}
6.237 +
6.238 +JNIEXPORT jdouble JNICALL
6.239 +Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad
6.240 +(JNIEnv *env, jobject dummy)
6.241 +{
6.242 + return get_process_load();
6.243 +}
6.244 +
7.1 --- a/src/windows/classes/com/sun/management/OperatingSystem.java Wed May 11 14:12:50 2011 -0700
7.2 +++ b/src/windows/classes/com/sun/management/OperatingSystem.java Wed May 11 18:52:46 2011 -0700
7.3 @@ -58,6 +58,8 @@
7.4 public native long getProcessCpuTime();
7.5 public native long getFreePhysicalMemorySize();
7.6 public native long getTotalPhysicalMemorySize();
7.7 + public native double getSystemCpuLoad();
7.8 + public native double getProcessCpuLoad();
7.9
7.10 static {
7.11 initialize();
8.1 --- a/src/windows/native/com/sun/management/OperatingSystem_md.c Wed May 11 14:12:50 2011 -0700
8.2 +++ b/src/windows/native/com/sun/management/OperatingSystem_md.c Wed May 11 18:52:46 2011 -0700
8.3 @@ -1,5 +1,5 @@
8.4 /*
8.5 - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
8.6 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
8.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8.8 *
8.9 * This code is free software; you can redistribute it and/or modify it
8.10 @@ -34,9 +34,27 @@
8.11 #include <errno.h>
8.12 #include <stdlib.h>
8.13
8.14 +#include <malloc.h>
8.15 +#pragma warning (push,0)
8.16 +#include <windows.h>
8.17 +#pragma warning (pop)
8.18 +#include <stdio.h>
8.19 +#include <time.h>
8.20 +#include <stdint.h>
8.21 +#include <assert.h>
8.22 +
8.23 +/* Disable warnings due to broken header files from Microsoft... */
8.24 +#pragma warning(push, 3)
8.25 +#include <pdh.h>
8.26 +#include <pdhmsg.h>
8.27 +#include <process.h>
8.28 +#pragma warning(pop)
8.29 +
8.30 typedef unsigned __int32 juint;
8.31 typedef unsigned __int64 julong;
8.32
8.33 +typedef enum boolean_values { false=0, true=1};
8.34 +
8.35 static void set_low(jlong* value, jint low) {
8.36 *value &= (jlong)0xffffffff << 32;
8.37 *value |= (jlong)(julong)(juint)low;
8.38 @@ -56,11 +74,14 @@
8.39
8.40 static HANDLE main_process;
8.41
8.42 +int perfiInit(void);
8.43 +
8.44 JNIEXPORT void JNICALL
8.45 Java_com_sun_management_OperatingSystem_initialize
8.46 (JNIEnv *env, jclass cls)
8.47 {
8.48 main_process = GetCurrentProcess();
8.49 + perfiInit();
8.50 }
8.51
8.52 JNIEXPORT jlong JNICALL
8.53 @@ -132,3 +153,788 @@
8.54 GlobalMemoryStatus(&ms);
8.55 return ms.dwTotalPhys;
8.56 }
8.57 +
8.58 +// Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.
8.59 +// Let's just ignore it, since we make sure we have enough buffer anyway.
8.60 +static int
8.61 +pdh_fail(PDH_STATUS pdhStat) {
8.62 + return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
8.63 +}
8.64 +
8.65 +// INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
8.66 +// http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
8.67 +// The index value for the base system counters and objects like processor,
8.68 +// process, thread, memory, and so forth are always the same irrespective
8.69 +// of the localized version of the operating system or service pack installed.
8.70 +#define PDH_PROCESSOR_IDX ((DWORD) 238)
8.71 +#define PDH_PROCESSOR_TIME_IDX ((DWORD) 6)
8.72 +#define PDH_PRIV_PROCESSOR_TIME_IDX ((DWORD) 144)
8.73 +#define PDH_PROCESS_IDX ((DWORD) 230)
8.74 +#define PDH_ID_PROCESS_IDX ((DWORD) 784)
8.75 +#define PDH_CONTEXT_SWITCH_RATE_IDX ((DWORD) 146)
8.76 +#define PDH_SYSTEM_IDX ((DWORD) 2)
8.77 +#define PDH_VIRTUAL_BYTES_IDX ((DWORD) 174)
8.78 +
8.79 +typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(
8.80 + HQUERY hQuery,
8.81 + LPCSTR szFullCounterPath,
8.82 + DWORD dwUserData,
8.83 + HCOUNTER *phCounter
8.84 + );
8.85 +typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(
8.86 + LPCWSTR szDataSource,
8.87 + DWORD dwUserData,
8.88 + HQUERY *phQuery
8.89 + );
8.90 +typedef DWORD (WINAPI *PdhCloseQueryFunc)(
8.91 + HQUERY hQuery
8.92 + );
8.93 +typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(
8.94 + HQUERY hQuery
8.95 + );
8.96 +typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(
8.97 + HCOUNTER hCounter,
8.98 + DWORD dwFormat,
8.99 + LPDWORD lpdwType,
8.100 + PPDH_FMT_COUNTERVALUE pValue
8.101 + );
8.102 +typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(
8.103 + LPCTSTR szDataSource,
8.104 + LPCTSTR szMachineName,
8.105 + LPCTSTR szObjectName,
8.106 + LPTSTR mszCounterList,
8.107 + LPDWORD pcchCounterListLength,
8.108 + LPTSTR mszInstanceList,
8.109 + LPDWORD pcchInstanceListLength,
8.110 + DWORD dwDetailLevel,
8.111 + DWORD dwFlags
8.112 + );
8.113 +typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(
8.114 + HCOUNTER hCounter
8.115 + );
8.116 +typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(
8.117 + LPCSTR szMachineName,
8.118 + DWORD dwNameIndex,
8.119 + LPSTR szNameBuffer,
8.120 + LPDWORD pcchNameBufferSize
8.121 + );
8.122 +typedef PDH_STATUS (WINAPI *PdhMakeCounterPathFunc)(
8.123 + PDH_COUNTER_PATH_ELEMENTS *pCounterPathElements,
8.124 + LPTSTR szFullPathBuffer,
8.125 + LPDWORD pcchBufferSize,
8.126 + DWORD dwFlags
8.127 + );
8.128 +
8.129 +static PdhAddCounterFunc PdhAddCounter_i;
8.130 +static PdhOpenQueryFunc PdhOpenQuery_i;
8.131 +static PdhCloseQueryFunc PdhCloseQuery_i;
8.132 +static PdhCollectQueryDataFunc PdhCollectQueryData_i;
8.133 +static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;
8.134 +static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;
8.135 +static PdhRemoveCounterFunc PdhRemoveCounter_i;
8.136 +static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;
8.137 +static PdhMakeCounterPathFunc PdhMakeCounterPath_i;
8.138 +
8.139 +static HANDLE thisProcess;
8.140 +static double cpuFactor;
8.141 +static DWORD num_cpus;
8.142 +
8.143 +#define FT2JLONG(X) ((((jlong)X.dwHighDateTime) << 32) | ((jlong)X.dwLowDateTime))
8.144 +#define COUNTER_BUF_SIZE 256
8.145 +// Min time between query updates.
8.146 +#define MIN_UPDATE_INTERVAL 500
8.147 +#define CONFIG_SUCCESSFUL 0
8.148 +
8.149 +/**
8.150 + * Struct for PDH queries.
8.151 + */
8.152 +typedef struct {
8.153 + HQUERY query;
8.154 + uint64_t lastUpdate; // Last time query was updated (current millis).
8.155 +} UpdateQueryS, *UpdateQueryP;
8.156 +
8.157 +/**
8.158 + * Struct for the processor load counters.
8.159 + */
8.160 +typedef struct {
8.161 + UpdateQueryS query;
8.162 + HCOUNTER* counters;
8.163 + int noOfCounters;
8.164 +} MultipleCounterQueryS, *MultipleCounterQueryP;
8.165 +
8.166 +/**
8.167 + * Struct for the jvm process load counter.
8.168 + */
8.169 +typedef struct {
8.170 + UpdateQueryS query;
8.171 + HCOUNTER counter;
8.172 +} SingleCounterQueryS, *SingleCounterQueryP;
8.173 +
8.174 +static char* getProcessPDHHeader(void);
8.175 +
8.176 +/**
8.177 + * Currently available counters.
8.178 + */
8.179 +static SingleCounterQueryS cntCtxtSwitchRate;
8.180 +static SingleCounterQueryS cntVirtualSize;
8.181 +static SingleCounterQueryS cntProcLoad;
8.182 +static SingleCounterQueryS cntProcSystemLoad;
8.183 +static MultipleCounterQueryS multiCounterCPULoad;
8.184 +
8.185 +static CRITICAL_SECTION processHeaderLock;
8.186 +static CRITICAL_SECTION initializationLock;
8.187 +
8.188 +/**
8.189 + * Initialize the perf module at startup.
8.190 + */
8.191 +int
8.192 +perfiInit(void)
8.193 +{
8.194 + InitializeCriticalSection(&processHeaderLock);
8.195 + InitializeCriticalSection(&initializationLock);
8.196 + return 0;
8.197 +}
8.198 +
8.199 +/**
8.200 + * Dynamically sets up function pointers to the PDH library.
8.201 + *
8.202 + * @return CONFIG_SUCCESSFUL on success, negative on failure.
8.203 + */
8.204 +static int
8.205 +get_functions(HMODULE h, char *ebuf, size_t elen) {
8.206 + // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods
8.207 + PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");
8.208 + PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");
8.209 + PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");
8.210 + PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");
8.211 + PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");
8.212 + PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");
8.213 + PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");
8.214 + PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");
8.215 + PdhMakeCounterPath_i = (PdhMakeCounterPathFunc)GetProcAddress(h, "PdhMakeCounterPathA");
8.216 +
8.217 + if (PdhAddCounter_i == NULL || PdhOpenQuery_i == NULL ||
8.218 + PdhCloseQuery_i == NULL || PdhCollectQueryData_i == NULL ||
8.219 + PdhGetFormattedCounterValue_i == NULL || PdhEnumObjectItems_i == NULL ||
8.220 + PdhRemoveCounter_i == NULL || PdhLookupPerfNameByIndex_i == NULL || PdhMakeCounterPath_i == NULL)
8.221 + {
8.222 + _snprintf(ebuf, elen, "Required method could not be found.");
8.223 + return -1;
8.224 + }
8.225 + return CONFIG_SUCCESSFUL;
8.226 +}
8.227 +
8.228 +/**
8.229 + * Returns the counter value as a double for the specified query.
8.230 + * Will collect the query data and update the counter values as necessary.
8.231 + *
8.232 + * @param query the query to update (if needed).
8.233 + * @param c the counter to read.
8.234 + * @param value where to store the formatted value.
8.235 + * @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)
8.236 + * @return CONFIG_SUCCESSFUL if no error
8.237 + * -1 if PdhCollectQueryData fails
8.238 + * -2 if PdhGetFormattedCounterValue fails
8.239 + */
8.240 +static int
8.241 +getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {
8.242 + clock_t now;
8.243 + now = clock();
8.244 +
8.245 + // Need to limit how often we update the query
8.246 + // to mimise the heisenberg effect.
8.247 + // (PDH behaves erratically if the counters are
8.248 + // queried too often, especially counters that
8.249 + // store and use values from two consecutive updates,
8.250 + // like cpu load.)
8.251 + if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {
8.252 + if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {
8.253 + return -1;
8.254 + }
8.255 + query->lastUpdate = now;
8.256 + }
8.257 +
8.258 + if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {
8.259 + return -2;
8.260 + }
8.261 + return CONFIG_SUCCESSFUL;
8.262 +}
8.263 +
8.264 +/**
8.265 + * Places the resolved counter name of the counter at the specified index in the
8.266 + * supplied buffer. There must be enough space in the buffer to hold the counter name.
8.267 + *
8.268 + * @param index the counter index as specified in the registry.
8.269 + * @param buf the buffer in which to place the counter name.
8.270 + * @param size the size of the counter name buffer.
8.271 + * @param ebuf the error message buffer.
8.272 + * @param elen the length of the error buffer.
8.273 + * @return CONFIG_SUCCESSFUL if successful, negative on failure.
8.274 + */
8.275 +static int
8.276 +find_name(DWORD index, char *buf, DWORD size) {
8.277 + PDH_STATUS res;
8.278 +
8.279 + if ((res = PdhLookupPerfNameByIndex_i(NULL, index, buf, &size)) != ERROR_SUCCESS) {
8.280 +
8.281 + /* printf("Could not open counter %d: error=0x%08x", index, res); */
8.282 + /* if (res == PDH_CSTATUS_NO_MACHINE) { */
8.283 + /* printf("User probably does not have sufficient privileges to use"); */
8.284 + /* printf("performance counters. If you are running on Windows 2003"); */
8.285 + /* printf("or Windows Vista, make sure the user is in the"); */
8.286 + /* printf("Performance Logs user group."); */
8.287 + /* } */
8.288 + return -1;
8.289 + }
8.290 +
8.291 + if (size == 0) {
8.292 + /* printf("Failed to get counter name for %d: empty string", index); */
8.293 + return -1;
8.294 + }
8.295 +
8.296 + // windows vista does not null-terminate the string (allthough the docs says it will)
8.297 + buf[size - 1] = '\0';
8.298 + return CONFIG_SUCCESSFUL;
8.299 +}
8.300 +
8.301 +/**
8.302 + * Sets up the supplied SingleCounterQuery to listen for the specified counter.
8.303 + * initPDH() must have been run prior to calling this function!
8.304 + *
8.305 + * @param counterQuery the counter query to set up.
8.306 + * @param counterString the string specifying the path to the counter.
8.307 + * @param ebuf the error buffer.
8.308 + * @param elen the length of the error buffer.
8.309 + * @returns CONFIG_SUCCESSFUL if successful, negative on failure.
8.310 + */
8.311 +static int
8.312 +initSingleCounterQuery(SingleCounterQueryP counterQuery, char *counterString) {
8.313 + if (PdhOpenQuery_i(NULL, 0, &counterQuery->query.query) != ERROR_SUCCESS) {
8.314 + /* printf("Could not open query for %s", counterString); */
8.315 + return -1;
8.316 + }
8.317 + if (PdhAddCounter_i(counterQuery->query.query, counterString, 0, &counterQuery->counter) != ERROR_SUCCESS) {
8.318 + /* printf("Could not add counter %s for query", counterString); */
8.319 + if (counterQuery->counter != NULL) {
8.320 + PdhRemoveCounter_i(counterQuery->counter);
8.321 + }
8.322 + if (counterQuery->query.query != NULL) {
8.323 + PdhCloseQuery_i(counterQuery->query.query);
8.324 + }
8.325 + memset(counterQuery, 0, sizeof(SingleCounterQueryS));
8.326 + return -1;
8.327 + }
8.328 + return CONFIG_SUCCESSFUL;
8.329 +}
8.330 +
8.331 +/**
8.332 + * Sets up the supplied SingleCounterQuery to listen for the time spent
8.333 + * by the HotSpot process.
8.334 + *
8.335 + * @param counterQuery the counter query to set up as a process counter.
8.336 + * @param ebuf the error buffer.
8.337 + * @param elen the length of the error buffer.
8.338 + * @returns CONFIG_SUCCESSFUL if successful, negative on failure.
8.339 + */
8.340 +static int
8.341 +initProcLoadCounter(void) {
8.342 + char time[COUNTER_BUF_SIZE];
8.343 + char counter[COUNTER_BUF_SIZE*2];
8.344 +
8.345 + if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) {
8.346 + return -1;
8.347 + }
8.348 + _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time);
8.349 + return initSingleCounterQuery(&cntProcLoad, counter);
8.350 +}
8.351 +
8.352 +static int
8.353 +initProcSystemLoadCounter(void) {
8.354 + char time[COUNTER_BUF_SIZE];
8.355 + char counter[COUNTER_BUF_SIZE*2];
8.356 +
8.357 + if (find_name(PDH_PRIV_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) {
8.358 + return -1;
8.359 + }
8.360 + _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time);
8.361 + return initSingleCounterQuery(&cntProcSystemLoad, counter);
8.362 +}
8.363 +
8.364 +/**
8.365 + * Sets up the supplied MultipleCounterQuery to check on the processors.
8.366 + * (Comment: Refactor and prettify as with the the SingleCounter queries
8.367 + * if more MultipleCounterQueries are discovered.)
8.368 + *
8.369 + * initPDH() must have been run prior to calling this function.
8.370 + *
8.371 + * @param multiQuery a pointer to a MultipleCounterQueryS, will be filled in with
8.372 + * the necessary info to check the PDH processor counters.
8.373 + * @return CONFIG_SUCCESSFUL if successful, negative on failure.
8.374 + */
8.375 +static int
8.376 +initProcessorCounters(void) {
8.377 + char processor[COUNTER_BUF_SIZE]; //'Processor' == #238
8.378 + char time[COUNTER_BUF_SIZE]; //'Time' == 6
8.379 + DWORD c_size, i_size;
8.380 + HQUERY tmpQuery;
8.381 + DWORD i, p_count;
8.382 + BOOL error;
8.383 + char *instances, *tmp;
8.384 + PDH_STATUS pdhStat;
8.385 +
8.386 + c_size = i_size = 0;
8.387 + tmpQuery = NULL;
8.388 + error = false;
8.389 +
8.390 + // This __try / __except stuff is there since Windows 2000 beta (or so) sometimes triggered
8.391 + // an access violation when the user had insufficient privileges to use the performance
8.392 + // counters. This was previously guarded by a very ugly piece of code which disabled the
8.393 + // global trap handling in JRockit. Don't know if this really is needed anymore, but otoh,
8.394 + // if we keep it we don't crash on Win2k beta. /Ihse, 2005-05-30
8.395 + __try {
8.396 + if (find_name(PDH_PROCESSOR_IDX, processor, sizeof(processor)-1) < 0) {
8.397 + return -1;
8.398 + }
8.399 + } __except (EXCEPTION_EXECUTE_HANDLER) { // We'll catch all exceptions here.
8.400 + /* printf("User does not have sufficient privileges to use performance counters"); */
8.401 + return -1;
8.402 + }
8.403 +
8.404 + if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) {
8.405 + return -1;
8.406 + }
8.407 + //ok, now we have enough to enumerate all processors.
8.408 + pdhStat = PdhEnumObjectItems_i (
8.409 + NULL, // reserved
8.410 + NULL, // local machine
8.411 + processor, // object to enumerate
8.412 + NULL, // pass in NULL buffers
8.413 + &c_size, // and 0 length to get
8.414 + NULL, // required size
8.415 + &i_size, // of the buffers in chars
8.416 + PERF_DETAIL_WIZARD, // counter detail level
8.417 + 0);
8.418 + if (pdh_fail(pdhStat)) {
8.419 + /* printf("could not enumerate processors (1) error=%d", pdhStat); */
8.420 + return -1;
8.421 + }
8.422 +
8.423 + // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will)
8.424 + instances = calloc(i_size, 1);
8.425 + if (instances == NULL) {
8.426 + /* printf("could not allocate memory (1) %d bytes", i_size); */
8.427 + error = true;
8.428 + goto end;
8.429 + }
8.430 +
8.431 + c_size = 0;
8.432 + pdhStat = PdhEnumObjectItems_i (
8.433 + NULL, // reserved
8.434 + NULL, // local machine
8.435 + processor, // object to enumerate
8.436 + NULL, // pass in NULL buffers
8.437 + &c_size, // and 0 length to get
8.438 + instances, // required size
8.439 + &i_size, // of the buffers in chars
8.440 + PERF_DETAIL_WIZARD, // counter detail level
8.441 + 0);
8.442 +
8.443 + if (pdh_fail(pdhStat)) {
8.444 + /* printf("could not enumerate processors (2) error=%d", pdhStat); */
8.445 + error = true;
8.446 + goto end;
8.447 + }
8.448 + //count perf count instances.
8.449 + for (p_count = 0, tmp = instances; *tmp != 0; tmp = &tmp[lstrlen(tmp)+1], p_count++);
8.450 +
8.451 + //is this correct for HT?
8.452 + assert(p_count == num_cpus+1);
8.453 +
8.454 + //ok, have number of perf counters.
8.455 + multiCounterCPULoad.counters = calloc(p_count, sizeof(HCOUNTER));
8.456 + if (multiCounterCPULoad.counters == NULL) {
8.457 + /* printf("could not allocate memory (2) count=%d", p_count); */
8.458 + error = true;
8.459 + goto end;
8.460 + }
8.461 +
8.462 + multiCounterCPULoad.noOfCounters = p_count;
8.463 +
8.464 + if (PdhOpenQuery_i(NULL, 0, &multiCounterCPULoad.query.query) != ERROR_SUCCESS) {
8.465 + /* printf("could not create query"); */
8.466 + error = true;
8.467 + goto end;
8.468 + }
8.469 + //now, fetch the counters.
8.470 + for (i = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[lstrlen(tmp)+1], i++) {
8.471 + char counter[2*COUNTER_BUF_SIZE];
8.472 +
8.473 + _snprintf(counter, sizeof(counter)-1, "\\%s(%s)\\%s", processor, tmp, time);
8.474 +
8.475 + if (PdhAddCounter_i(multiCounterCPULoad.query.query, counter, 0, &multiCounterCPULoad.counters[i]) != ERROR_SUCCESS) {
8.476 + /* printf("error adding processor counter %s", counter); */
8.477 + error = true;
8.478 + goto end;
8.479 + }
8.480 + }
8.481 +
8.482 + free(instances);
8.483 + instances = NULL;
8.484 +
8.485 + // Query once to initialize the counters needing at least two queries
8.486 + // (like the % CPU usage) to calculate correctly.
8.487 + if (PdhCollectQueryData_i(multiCounterCPULoad.query.query) != ERROR_SUCCESS)
8.488 + error = true;
8.489 +
8.490 + end:
8.491 + if (instances != NULL) {
8.492 + free(instances);
8.493 + }
8.494 + if (tmpQuery != NULL) {
8.495 + PdhCloseQuery_i(tmpQuery);
8.496 + }
8.497 + if (error) {
8.498 + int i;
8.499 +
8.500 + if (multiCounterCPULoad.counters != NULL) {
8.501 + for (i = 0; i < multiCounterCPULoad.noOfCounters; i++) {
8.502 + if (multiCounterCPULoad.counters[i] != NULL) {
8.503 + PdhRemoveCounter_i(multiCounterCPULoad.counters[i]);
8.504 + }
8.505 + }
8.506 + free(multiCounterCPULoad.counters[i]);
8.507 + }
8.508 + if (multiCounterCPULoad.query.query != NULL) {
8.509 + PdhCloseQuery_i(multiCounterCPULoad.query.query);
8.510 + }
8.511 + memset(&multiCounterCPULoad, 0, sizeof(MultipleCounterQueryS));
8.512 + return -1;
8.513 + }
8.514 + return CONFIG_SUCCESSFUL;
8.515 +}
8.516 +
8.517 +/**
8.518 + * Help function that initializes the PDH process header for the JRockit process.
8.519 + * (You should probably use getProcessPDHHeader() instead!)
8.520 + *
8.521 + * initPDH() must have been run prior to calling this function.
8.522 + *
8.523 + * @param ebuf the error buffer.
8.524 + * @param elen the length of the error buffer.
8.525 + *
8.526 + * @return the PDH instance description corresponding to the JVM process.
8.527 + */
8.528 +static char*
8.529 +initProcessPDHHeader(void) {
8.530 + static char hotspotheader[2*COUNTER_BUF_SIZE];
8.531 +
8.532 + char counter[2*COUNTER_BUF_SIZE];
8.533 + char processes[COUNTER_BUF_SIZE]; //'Process' == #230
8.534 + char pid[COUNTER_BUF_SIZE]; //'ID Process' == 784
8.535 + char module_name[MAX_PATH];
8.536 + PDH_STATUS pdhStat;
8.537 + DWORD c_size = 0, i_size = 0;
8.538 + HQUERY tmpQuery = NULL;
8.539 + int i, myPid = _getpid();
8.540 + BOOL error = false;
8.541 + char *instances, *tmp, *instance_name, *dot_pos;
8.542 +
8.543 + tmpQuery = NULL;
8.544 + myPid = _getpid();
8.545 + error = false;
8.546 +
8.547 + if (find_name(PDH_PROCESS_IDX, processes, sizeof(processes) - 1) < 0) {
8.548 + return NULL;
8.549 + }
8.550 +
8.551 + if (find_name(PDH_ID_PROCESS_IDX, pid, sizeof(pid) - 1) < 0) {
8.552 + return NULL;
8.553 + }
8.554 + //time is same.
8.555 +
8.556 + c_size = 0;
8.557 + i_size = 0;
8.558 +
8.559 + pdhStat = PdhEnumObjectItems_i (
8.560 + NULL, // reserved
8.561 + NULL, // local machine
8.562 + processes, // object to enumerate
8.563 + NULL, // pass in NULL buffers
8.564 + &c_size, // and 0 length to get
8.565 + NULL, // required size
8.566 + &i_size, // of the buffers in chars
8.567 + PERF_DETAIL_WIZARD, // counter detail level
8.568 + 0);
8.569 +
8.570 + //ok, now we have enough to enumerate all processes
8.571 + if (pdh_fail(pdhStat)) {
8.572 + /* printf("Could not enumerate processes (1) error=%d", pdhStat); */
8.573 + return NULL;
8.574 + }
8.575 +
8.576 + // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will)
8.577 + if ((instances = calloc(i_size, 1)) == NULL) {
8.578 + /* printf("Could not allocate memory %d bytes", i_size); */
8.579 + error = true;
8.580 + goto end;
8.581 + }
8.582 +
8.583 + c_size = 0;
8.584 +
8.585 + pdhStat = PdhEnumObjectItems_i (
8.586 + NULL, // reserved
8.587 + NULL, // local machine
8.588 + processes, // object to enumerate
8.589 + NULL, // pass in NULL buffers
8.590 + &c_size, // and 0 length to get
8.591 + instances, // required size
8.592 + &i_size, // of the buffers in chars
8.593 + PERF_DETAIL_WIZARD, // counter detail level
8.594 + 0);
8.595 +
8.596 + // ok, now we have enough to enumerate all processes
8.597 + if (pdh_fail(pdhStat)) {
8.598 + /* printf("Could not enumerate processes (2) error=%d", pdhStat); */
8.599 + error = true;
8.600 + goto end;
8.601 + }
8.602 +
8.603 + if (PdhOpenQuery_i(NULL, 0, &tmpQuery) != ERROR_SUCCESS) {
8.604 + /* printf("Could not create temporary query"); */
8.605 + error = true;
8.606 + goto end;
8.607 + }
8.608 +
8.609 + // Find our module name and use it to extract the instance name used by PDH
8.610 + if (GetModuleFileName(NULL, module_name, MAX_PATH) >= MAX_PATH-1) {
8.611 + /* printf("Module name truncated"); */
8.612 + error = true;
8.613 + goto end;
8.614 + }
8.615 + instance_name = strrchr(module_name, '\\'); //drop path
8.616 + instance_name++; //skip slash
8.617 + dot_pos = strchr(instance_name, '.'); //drop .exe
8.618 + dot_pos[0] = '\0';
8.619 +
8.620 + //now, fetch the counters.
8.621 + for (tmp = instances; *tmp != 0 && !error; tmp = &tmp[lstrlen(tmp)+1]) {
8.622 + HCOUNTER hc = NULL;
8.623 + BOOL done = false;
8.624 +
8.625 + // Skip until we find our own process name
8.626 + if (strcmp(tmp, instance_name) != 0) {
8.627 + continue;
8.628 + }
8.629 +
8.630 + // iterate over all instance indexes and try to find our own pid
8.631 + for (i = 0; !done && !error; i++){
8.632 + PDH_STATUS res;
8.633 + _snprintf(counter, sizeof(counter)-1, "\\%s(%s#%d)\\%s", processes, tmp, i, pid);
8.634 +
8.635 + if (PdhAddCounter_i(tmpQuery, counter, 0, &hc) != ERROR_SUCCESS) {
8.636 + /* printf("Failed to create process id query"); */
8.637 + error = true;
8.638 + goto end;
8.639 + }
8.640 +
8.641 + res = PdhCollectQueryData_i(tmpQuery);
8.642 +
8.643 + if (res == PDH_INVALID_HANDLE) {
8.644 + /* printf("Failed to query process id"); */
8.645 + res = -1;
8.646 + done = true;
8.647 + } else if (res == PDH_NO_DATA) {
8.648 + done = true;
8.649 + } else {
8.650 + PDH_FMT_COUNTERVALUE cv;
8.651 +
8.652 + PdhGetFormattedCounterValue_i(hc, PDH_FMT_LONG, NULL, &cv);
8.653 + /*
8.654 + * This check seems to be needed for Win2k SMP boxes, since
8.655 + * they for some reason don't return PDH_NO_DATA for non existing
8.656 + * counters.
8.657 + */
8.658 + if (cv.CStatus != PDH_CSTATUS_VALID_DATA) {
8.659 + done = true;
8.660 + } else if (cv.longValue == myPid) {
8.661 + _snprintf(hotspotheader, sizeof(hotspotheader)-1, "\\%s(%s#%d)\0", processes, tmp, i);
8.662 + PdhRemoveCounter_i(hc);
8.663 + goto end;
8.664 + }
8.665 + }
8.666 + PdhRemoveCounter_i(hc);
8.667 + }
8.668 + }
8.669 + end:
8.670 + if (instances != NULL) {
8.671 + free(instances);
8.672 + }
8.673 + if (tmpQuery != NULL) {
8.674 + PdhCloseQuery_i(tmpQuery);
8.675 + }
8.676 + if (error) {
8.677 + return NULL;
8.678 + }
8.679 + return hotspotheader;
8.680 +}
8.681 +
8.682 +/**
8.683 + * Returns the PDH string prefix identifying the HotSpot process. Use this prefix when getting
8.684 + * counters from the PDH process object representing HotSpot.
8.685 + *
8.686 + * Note: this call may take some time to complete.
8.687 + *
8.688 + * @param ebuf error buffer.
8.689 + * @param elen error buffer length.
8.690 + *
8.691 + * @return the header to be used when retrieving PDH counters from the HotSpot process.
8.692 + * Will return NULL if the call failed.
8.693 + */
8.694 +static char *
8.695 +getProcessPDHHeader(void) {
8.696 + static char *processHeader = NULL;
8.697 +
8.698 + EnterCriticalSection(&processHeaderLock); {
8.699 + if (processHeader == NULL) {
8.700 + processHeader = initProcessPDHHeader();
8.701 + }
8.702 + } LeaveCriticalSection(&processHeaderLock);
8.703 + return processHeader;
8.704 +}
8.705 +
8.706 +int perfInit(void);
8.707 +
8.708 +double
8.709 +perfGetCPULoad(int which)
8.710 +{
8.711 + PDH_FMT_COUNTERVALUE cv;
8.712 + HCOUNTER c;
8.713 +
8.714 + if (perfInit() < 0) {
8.715 + // warn?
8.716 + return -1.0;
8.717 + }
8.718 +
8.719 + if (multiCounterCPULoad.query.query == NULL) {
8.720 + // warn?
8.721 + return -1.0;
8.722 + }
8.723 +
8.724 + if (which == -1) {
8.725 + c = multiCounterCPULoad.counters[multiCounterCPULoad.noOfCounters - 1];
8.726 + } else {
8.727 + if (which < multiCounterCPULoad.noOfCounters) {
8.728 + c = multiCounterCPULoad.counters[which];
8.729 + } else {
8.730 + return -1.0;
8.731 + }
8.732 + }
8.733 + if (getPerformanceData(&multiCounterCPULoad.query, c, &cv, PDH_FMT_DOUBLE ) == CONFIG_SUCCESSFUL) {
8.734 + return cv.doubleValue / 100;
8.735 + }
8.736 + return -1.0;
8.737 +}
8.738 +
8.739 +double
8.740 +perfGetProcessLoad(void)
8.741 +{
8.742 + PDH_FMT_COUNTERVALUE cv;
8.743 +
8.744 + if (perfInit() < 0) {
8.745 + // warn?
8.746 + return -1.0;
8.747 + }
8.748 +
8.749 + if (cntProcLoad.query.query == NULL) {
8.750 + // warn?
8.751 + return -1.0;
8.752 + }
8.753 +
8.754 + if (getPerformanceData(&cntProcLoad.query, cntProcLoad.counter, &cv, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == CONFIG_SUCCESSFUL) {
8.755 + double d = cv.doubleValue / cpuFactor;
8.756 + d = min(1, d);
8.757 + d = max(0, d);
8.758 + return d;
8.759 + }
8.760 + return -1.0;
8.761 +}
8.762 +
8.763 +/**
8.764 + * Helper to initialize the PDH library. Loads the library and sets up the functions.
8.765 + * Note that once loaded, we will never unload the PDH library.
8.766 + *
8.767 + * @return CONFIG_SUCCESSFUL if successful, negative on failure.
8.768 + */
8.769 +int
8.770 +perfInit(void) {
8.771 + static HMODULE h;
8.772 + static BOOL running, inited;
8.773 +
8.774 + int error;
8.775 +
8.776 + if (running) {
8.777 + return CONFIG_SUCCESSFUL;
8.778 + }
8.779 +
8.780 + error = CONFIG_SUCCESSFUL;
8.781 +
8.782 + // this is double checked locking again, but we try to bypass the worst by
8.783 + // implicit membar at end of lock.
8.784 + EnterCriticalSection(&initializationLock); {
8.785 + if (!inited) {
8.786 + char buf[64] = "";
8.787 + SYSTEM_INFO si;
8.788 +
8.789 + // CMH. But windows will not care about our affinity when giving
8.790 + // us measurements. Need the real, raw num cpus.
8.791 +
8.792 + GetSystemInfo(&si);
8.793 + num_cpus = si.dwNumberOfProcessors;
8.794 + // Initialize the denominator for the jvm load calculations
8.795 + cpuFactor = num_cpus * 100;
8.796 +
8.797 + /**
8.798 + * Do this dynamically, so we don't fail to start on systems without pdh.
8.799 + */
8.800 + if ((h = LoadLibrary("pdh.dll")) == NULL) {
8.801 + /* printf("Could not load pdh.dll (%d)", GetLastError()); */
8.802 + error = -2;
8.803 + } else if (get_functions(h, buf, sizeof(buf)) < 0) {
8.804 + FreeLibrary(h);
8.805 + h = NULL;
8.806 + error = -2;
8.807 + /* printf("Failed to init pdh functions: %s.\n", buf); */
8.808 + } else {
8.809 + if (initProcessorCounters() != 0) {
8.810 + /* printf("Failed to init system load counters.\n"); */
8.811 + } else if (initProcLoadCounter() != 0) {
8.812 + /* printf("Failed to init process load counter.\n"); */
8.813 + } else if (initProcSystemLoadCounter() != 0) {
8.814 + /* printf("Failed to init process system load counter.\n"); */
8.815 + } else {
8.816 + inited = true;
8.817 + }
8.818 + }
8.819 + }
8.820 + } LeaveCriticalSection(&initializationLock);
8.821 +
8.822 + if (inited && error == CONFIG_SUCCESSFUL) {
8.823 + running = true;
8.824 + }
8.825 +
8.826 + return error;
8.827 +}
8.828 +
8.829 +JNIEXPORT jdouble JNICALL
8.830 +Java_com_sun_management_OperatingSystem_getSystemCpuLoad
8.831 +(JNIEnv *env, jobject dummy)
8.832 +{
8.833 + return perfGetCPULoad(-1);
8.834 +}
8.835 +
8.836 +JNIEXPORT jdouble JNICALL
8.837 +Java_com_sun_management_OperatingSystem_getProcessCpuLoad
8.838 +(JNIEnv *env, jobject dummy)
8.839 +{
8.840 + return perfGetProcessLoad();
8.841 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/test/com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java Wed May 11 18:52:46 2011 -0700
9.3 @@ -0,0 +1,53 @@
9.4 +/*
9.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9.7 + *
9.8 + * This code is free software; you can redistribute it and/or modify it
9.9 + * under the terms of the GNU General Public License version 2 only, as
9.10 + * published by the Free Software Foundation.
9.11 + *
9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9.15 + * version 2 for more details (a copy is included in the LICENSE file that
9.16 + * accompanied this code).
9.17 + *
9.18 + * You should have received a copy of the GNU General Public License version
9.19 + * 2 along with this work; if not, write to the Free Software Foundation,
9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
9.21 + *
9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
9.23 + * or visit www.oracle.com if you need additional information or have any
9.24 + * questions.
9.25 + */
9.26 +
9.27 +/*
9.28 + * @test
9.29 + * @bug 7028071
9.30 + * @summary Basic unit test of OperatingSystemMXBean.getProcessCpuLoad()
9.31 + *
9.32 + * @run main GetProcessCpuLoad
9.33 + */
9.34 +
9.35 +import java.lang.management.*;
9.36 +import com.sun.management.OperatingSystemMXBean;
9.37 +
9.38 +public class GetProcessCpuLoad {
9.39 + public static void main(String[] argv) throws Exception {
9.40 + OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
9.41 + ManagementFactory.getOperatingSystemMXBean();
9.42 + double load;
9.43 + for(int i=0; i<10; i++) {
9.44 + load = mbean.getProcessCpuLoad();
9.45 + if((load<0.0 || load>1.0) && load != -1.0) {
9.46 + throw new RuntimeException("getProcessCpuLoad() returns " + load
9.47 + + " which is not in the [0.0,1.0] interval");
9.48 + }
9.49 + try {
9.50 + Thread.sleep(200);
9.51 + } catch(InterruptedException e) {
9.52 + e.printStackTrace();
9.53 + }
9.54 + }
9.55 + }
9.56 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/test/com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java Wed May 11 18:52:46 2011 -0700
10.3 @@ -0,0 +1,53 @@
10.4 +/*
10.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10.7 + *
10.8 + * This code is free software; you can redistribute it and/or modify it
10.9 + * under the terms of the GNU General Public License version 2 only, as
10.10 + * published by the Free Software Foundation.
10.11 + *
10.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10.15 + * version 2 for more details (a copy is included in the LICENSE file that
10.16 + * accompanied this code).
10.17 + *
10.18 + * You should have received a copy of the GNU General Public License version
10.19 + * 2 along with this work; if not, write to the Free Software Foundation,
10.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
10.21 + *
10.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
10.23 + * or visit www.oracle.com if you need additional information or have any
10.24 + * questions.
10.25 + */
10.26 +
10.27 +/*
10.28 + * @test
10.29 + * @bug 7028071
10.30 + * @summary Basic unit test of OperatingSystemMXBean.getProcessCpuLoad()
10.31 + *
10.32 + * @run main GetSystemCpuLoad
10.33 + */
10.34 +
10.35 +import java.lang.management.*;
10.36 +import com.sun.management.OperatingSystemMXBean;
10.37 +
10.38 +public class GetSystemCpuLoad {
10.39 + public static void main(String[] argv) throws Exception {
10.40 + OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
10.41 + ManagementFactory.getOperatingSystemMXBean();
10.42 + double load;
10.43 + for(int i=0; i<10; i++) {
10.44 + load = mbean.getSystemCpuLoad();
10.45 + if((load<0.0 || load>1.0) && load != -1.0) {
10.46 + throw new RuntimeException("getSystemCpuLoad() returns " + load
10.47 + + " which is not in the [0.0,1.0] interval");
10.48 + }
10.49 + try {
10.50 + Thread.sleep(200);
10.51 + } catch(InterruptedException e) {
10.52 + e.printStackTrace();
10.53 + }
10.54 + }
10.55 + }
10.56 +}