1 /*
   2  * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "sun_management_OperatingSystemImpl.h"
  27 
  28 #include <sys/time.h>
  29 #include <mach/mach.h>
  30 #include <mach/task_info.h>
  31 
  32 
  33 JNIEXPORT jdouble JNICALL
  34 Java_sun_management_OperatingSystemImpl_getSystemCpuLoad
  35 (JNIEnv *env, jobject dummy)
  36 {
  37     // This code is influenced by the darwin top source
  38 
  39     kern_return_t kr;
  40     mach_msg_type_number_t count;
  41     host_cpu_load_info_data_t load;
  42 
  43     static jlong last_used  = 0;
  44     static jlong last_total = 0;
  45 
  46     count = HOST_CPU_LOAD_INFO_COUNT;
  47     kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&load, &count);
  48     if (kr != KERN_SUCCESS) {
  49         return -1;
  50     }
  51 
  52     jlong used  = load.cpu_ticks[CPU_STATE_USER] + load.cpu_ticks[CPU_STATE_NICE] + load.cpu_ticks[CPU_STATE_SYSTEM];
  53     jlong total = used + load.cpu_ticks[CPU_STATE_IDLE];
  54 
  55     if (last_used == 0 || last_total == 0) {
  56         // First call, just set the last values
  57         last_used  = used;
  58         last_total = total;
  59         // return 0 since we have no data, not -1 which indicates error
  60         return 0;
  61     }
  62 
  63     jlong used_delta  = used - last_used;
  64     jlong total_delta = total - last_total;
  65 
  66     jdouble cpu = (jdouble) used_delta / total_delta;
  67 
  68     last_used  = used;
  69     last_total = total;
  70 
  71     return cpu;
  72 }
  73 
  74 
  75 #define TIME_VALUE_TO_TIMEVAL(a, r) do {  \
  76      (r)->tv_sec = (a)->seconds;          \
  77      (r)->tv_usec = (a)->microseconds;    \
  78 } while (0)
  79 
  80 
  81 #define TIME_VALUE_TO_MICROSECONDS(TV) \
  82      ((TV).tv_sec * 1000 * 1000 + (TV).tv_usec)
  83 
  84 
  85 JNIEXPORT jdouble JNICALL
  86 Java_sun_management_OperatingSystemImpl_getProcessCpuLoad
  87 (JNIEnv *env, jobject dummy)
  88 {
  89     // This code is influenced by the darwin top source
  90 
  91     struct task_basic_info_64 task_info_data;
  92     struct task_thread_times_info thread_info_data;
  93     struct timeval user_timeval, system_timeval, task_timeval;
  94     struct timeval now;
  95     mach_port_t task = mach_task_self();
  96     kern_return_t kr;
  97 
  98     static jlong last_task_time = 0;
  99     static jlong last_time      = 0;
 100 
 101     mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
 102     kr = task_info(task,
 103             TASK_THREAD_TIMES_INFO,
 104             (task_info_t)&thread_info_data,
 105             &thread_info_count);
 106     if (kr != KERN_SUCCESS) {
 107         // Most likely cause: |task| is a zombie.
 108         return -1;
 109     }
 110 
 111     mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
 112     kr = task_info(task,
 113             TASK_BASIC_INFO_64,
 114             (task_info_t)&task_info_data,
 115             &count);
 116     if (kr != KERN_SUCCESS) {
 117         // Most likely cause: |task| is a zombie.
 118         return -1;
 119     }
 120 
 121     /* Set total_time. */
 122     // thread info contains live time...
 123     TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
 124     TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
 125     timeradd(&user_timeval, &system_timeval, &task_timeval);
 126 
 127     // ... task info contains terminated time.
 128     TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
 129     TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
 130     timeradd(&user_timeval, &task_timeval, &task_timeval);
 131     timeradd(&system_timeval, &task_timeval, &task_timeval);
 132 
 133     if (gettimeofday(&now, NULL) < 0) {
 134        return -1;
 135     }
 136     jint ncpus      = JVM_ActiveProcessorCount();
 137     jlong time      = TIME_VALUE_TO_MICROSECONDS(now) * ncpus;
 138     jlong task_time = TIME_VALUE_TO_MICROSECONDS(task_timeval);
 139 
 140     if ((last_task_time == 0) || (last_time == 0)) {
 141         // First call, just set the last values.
 142         last_task_time = task_time;
 143         last_time      = time;
 144         // return 0 since we have no data, not -1 which indicates error
 145         return 0;
 146     }
 147 
 148     jlong task_time_delta = task_time - last_task_time;
 149     jlong time_delta      = time - last_time;
 150     if (time_delta == 0) {
 151         return -1;
 152     }
 153 
 154     jdouble cpu = (jdouble) task_time_delta / time_delta;
 155 
 156     last_task_time = task_time;
 157     last_time      = time;
 158 
 159     return cpu;
 160  }