1/*
2 * Copyright (c) 2011, 2015, 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 "com_sun_management_internal_OperatingSystemImpl.h"
27
28#include <sys/time.h>
29#include <mach/mach.h>
30#include <mach/task_info.h>
31
32#include "jvm.h"
33
34JNIEXPORT jdouble JNICALL
35Java_com_sun_management_internal_OperatingSystemImpl_getSystemCpuLoad0
36(JNIEnv *env, jobject dummy)
37{
38    // This code is influenced by the darwin top source
39
40    kern_return_t kr;
41    mach_msg_type_number_t count;
42    host_cpu_load_info_data_t load;
43
44    static jlong last_used  = 0;
45    static jlong last_total = 0;
46
47    count = HOST_CPU_LOAD_INFO_COUNT;
48    kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&load, &count);
49    if (kr != KERN_SUCCESS) {
50        return -1;
51    }
52
53    jlong used  = load.cpu_ticks[CPU_STATE_USER] + load.cpu_ticks[CPU_STATE_NICE] + load.cpu_ticks[CPU_STATE_SYSTEM];
54    jlong total = used + load.cpu_ticks[CPU_STATE_IDLE];
55
56    if (last_used == 0 || last_total == 0) {
57        // First call, just set the last values
58        last_used  = used;
59        last_total = total;
60        // return 0 since we have no data, not -1 which indicates error
61        return 0;
62    }
63
64    jlong used_delta  = used - last_used;
65    jlong total_delta = total - last_total;
66
67    jdouble cpu = (jdouble) used_delta / total_delta;
68
69    last_used  = used;
70    last_total = total;
71
72    return cpu;
73}
74
75
76#define TIME_VALUE_TO_TIMEVAL(a, r) do {  \
77     (r)->tv_sec = (a)->seconds;          \
78     (r)->tv_usec = (a)->microseconds;    \
79} while (0)
80
81
82#define TIME_VALUE_TO_MICROSECONDS(TV) \
83     ((TV).tv_sec * 1000 * 1000 + (TV).tv_usec)
84
85
86JNIEXPORT jdouble JNICALL
87Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0
88(JNIEnv *env, jobject dummy)
89{
90    // This code is influenced by the darwin top source
91
92    struct task_basic_info_64 task_info_data;
93    struct task_thread_times_info thread_info_data;
94    struct timeval user_timeval, system_timeval, task_timeval;
95    struct timeval now;
96    mach_port_t task = mach_task_self();
97    kern_return_t kr;
98
99    static jlong last_task_time = 0;
100    static jlong last_time      = 0;
101
102    mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
103    kr = task_info(task,
104            TASK_THREAD_TIMES_INFO,
105            (task_info_t)&thread_info_data,
106            &thread_info_count);
107    if (kr != KERN_SUCCESS) {
108        // Most likely cause: |task| is a zombie.
109        return -1;
110    }
111
112    mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
113    kr = task_info(task,
114            TASK_BASIC_INFO_64,
115            (task_info_t)&task_info_data,
116            &count);
117    if (kr != KERN_SUCCESS) {
118        // Most likely cause: |task| is a zombie.
119        return -1;
120    }
121
122    /* Set total_time. */
123    // thread info contains live time...
124    TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
125    TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
126    timeradd(&user_timeval, &system_timeval, &task_timeval);
127
128    // ... task info contains terminated time.
129    TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
130    TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
131    timeradd(&user_timeval, &task_timeval, &task_timeval);
132    timeradd(&system_timeval, &task_timeval, &task_timeval);
133
134    if (gettimeofday(&now, NULL) < 0) {
135       return -1;
136    }
137    jint ncpus      = JVM_ActiveProcessorCount();
138    jlong time      = TIME_VALUE_TO_MICROSECONDS(now) * ncpus;
139    jlong task_time = TIME_VALUE_TO_MICROSECONDS(task_timeval);
140
141    if ((last_task_time == 0) || (last_time == 0)) {
142        // First call, just set the last values.
143        last_task_time = task_time;
144        last_time      = time;
145        // return 0 since we have no data, not -1 which indicates error
146        return 0;
147    }
148
149    jlong task_time_delta = task_time - last_task_time;
150    jlong time_delta      = time - last_time;
151    if (time_delta == 0) {
152        return -1;
153    }
154
155    jdouble cpu = (jdouble) task_time_delta / time_delta;
156
157    last_task_time = task_time;
158    last_time      = time;
159
160    return cpu;
161 }
162