1 /*
2 * Copyright (c) 2011, 2020, 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/resource.h>
29 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #include <sys/time.h>
32 #ifndef __NetBSD__
33 #include <sys/user.h>
34 #endif
35 #include <unistd.h>
36 #ifdef __FreeBSD__
37 #include <stdlib.h>
38 #include <malloc_np.h>
39 #endif
40
41 #include "jvm.h"
42
43 struct ticks {
44 jlong used;
45 jlong total;
46 };
47
48 typedef struct ticks ticks;
49
50 static struct perfbuf {
51 int nProcs;
52 ticks jvmTicks;
53 ticks cpuTicks;
54 ticks *cpus;
55 } counters;
56
57 /**
58 * This method must be called first, before any data can be gathererd.
59 */
perfInit()60 int perfInit() {
61 static int initialized = 0;
62
63 if (!initialized) {
64 int mib[2];
65 size_t len;
66 int cpu_val;
67
68 mib[0] = CTL_HW;
69 mib[1] = HW_NCPU;
70 len = sizeof(cpu_val);
71 if (sysctl(mib, 2, &cpu_val, &len, NULL, 0) == -1 || cpu_val < 1) {
72 cpu_val = 1;
73 }
74
75 counters.nProcs = cpu_val;
76 #ifdef __FreeBSD__
77 // Initialise JVM
78 counters.jvmTicks.used = 0;
79 counters.jvmTicks.total = 0;
80
81 // Initialise CPU
82 counters.cpuTicks.used = 0;
83 counters.cpuTicks.total = 0;
84
85 counters.cpus = calloc(cpu_val, sizeof(ticks));
86 if (counters.cpus != NULL) {
87 // Initialise per CPU
88 for (int i = 0; i < counters.nProcs; i++) {
89 counters.cpus[i].used = 0;
90 counters.cpus[i].total = 0;
91 }
92 }
93 #endif
94 initialized = 1;
95 }
96
97 return initialized ? 0 : -1;
98 }
99
100 JNIEXPORT jdouble JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getSystemCpuLoad0(JNIEnv * env,jobject dummy)101 Java_com_sun_management_internal_OperatingSystemImpl_getSystemCpuLoad0
102 (JNIEnv *env, jobject dummy)
103 {
104 #if defined(__FreeBSD__) || defined(__DragonFly__)
105 if (perfInit() == 0) {
106 /* This is based on the MacOS X implementation */
107
108 /* Load CPU times */
109 long cp_time[CPUSTATES];
110 size_t len = sizeof(cp_time);
111 if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) == -1) {
112 return -1.;
113 }
114
115 jlong used = cp_time[CP_USER] + cp_time[CP_NICE] + cp_time[CP_SYS] + cp_time[CP_INTR];
116 jlong total = used + cp_time[CP_IDLE];
117
118 if (counters.cpuTicks.used == 0 || counters.cpuTicks.total == 0) {
119 // First call, just set the last values
120 counters.cpuTicks.used = used;
121 counters.cpuTicks.total = total;
122 // return 0 since we have no data, not -1 which indicates error
123 return 0.;
124 }
125
126 jlong used_delta = used - counters.cpuTicks.used;
127 jlong total_delta = total - counters.cpuTicks.total;
128
129 jdouble cpu = (jdouble) used_delta / total_delta;
130
131 counters.cpuTicks.used = used;
132 counters.cpuTicks.total = total;
133
134 return cpu;
135 }
136 else {
137 #endif
138 // Not implemented yet
139 return -1.;
140 #if defined(__FreeBSD__) || defined(__DragonFly__)
141 }
142 #endif
143 }
144
145
146 #define TIME_VALUE_TO_TIMEVAL(a, r) do { \
147 (r)->tv_sec = (a)->seconds; \
148 (r)->tv_usec = (a)->microseconds; \
149 } while (0)
150
151
152 #define TIME_VALUE_TO_MICROSECONDS(TV) \
153 ((TV).tv_sec * 1000 * 1000 + (TV).tv_usec)
154
155
156 JNIEXPORT jdouble JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0(JNIEnv * env,jobject dummy)157 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0
158 (JNIEnv *env, jobject dummy)
159 {
160 #if defined(__FreeBSD__) || defined(__DragonFly__)
161 if (perfInit() == 0) {
162 /* This is based on the MacOS X implementation */
163
164 struct timeval now;
165 struct kinfo_proc kp;
166 int mib[4];
167 size_t len = sizeof(struct kinfo_proc);
168
169 mib[0] = CTL_KERN;
170 mib[1] = KERN_PROC;
171 mib[2] = KERN_PROC_PID;
172 mib[3] = getpid();
173
174 if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1) {
175 return -1.;
176 }
177
178 if (gettimeofday(&now, NULL) == -1) {
179 return -1.;
180 }
181
182 jint ncpus = JVM_ActiveProcessorCount();
183 jlong time = TIME_VALUE_TO_MICROSECONDS(now) * ncpus;
184 #ifdef __DragonFly__
185 jlong task_time = TIME_VALUE_TO_MICROSECONDS(kp.kp_ru.ru_utime) +
186 TIME_VALUE_TO_MICROSECONDS(kp.kp_ru.ru_stime);
187 #else
188 jlong task_time = TIME_VALUE_TO_MICROSECONDS(kp.ki_rusage.ru_utime) +
189 TIME_VALUE_TO_MICROSECONDS(kp.ki_rusage.ru_stime);
190 #endif
191
192 if (counters.jvmTicks.used == 0 || counters.jvmTicks.total == 0) {
193 // First call, just set the last values.
194 counters.jvmTicks.used = task_time;
195 counters.jvmTicks.total = time;
196 // return 0 since we have no data, not -1 which indicates error
197 return 0.;
198 }
199
200 jlong task_time_delta = task_time - counters.jvmTicks.used;
201 jlong time_delta = time - counters.jvmTicks.total;
202 if (time_delta == 0) {
203 return -1.;
204 }
205
206 jdouble cpu = (jdouble) task_time_delta / time_delta;
207
208 counters.jvmTicks.used = task_time;
209 counters.jvmTicks.total = time;
210
211 return cpu;
212 }
213 else {
214 #endif
215 // Not implemented yet
216 return -1.0;
217 #if defined(__FreeBSD__) || defined(__DragonFly__)
218 }
219 #endif
220 }
221
222 JNIEXPORT jdouble JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getSingleCpuLoad0(JNIEnv * env,jobject dummy,jint cpu_number)223 Java_com_sun_management_internal_OperatingSystemImpl_getSingleCpuLoad0
224 (JNIEnv *env, jobject dummy, jint cpu_number)
225 {
226 #ifdef __FreeBSD__
227 if (perfInit() == 0 && 0 <= cpu_number && cpu_number < counters.nProcs) {
228 /* Load CPU times */
229 long cp_times[CPUSTATES * counters.nProcs];
230 size_t len = sizeof(cp_times);
231 if (sysctlbyname("kern.cp_times", &cp_times, &len, NULL, 0) == -1) {
232 return -1.;
233 }
234
235 size_t offset = cpu_number * CPUSTATES;
236 jlong used = cp_times[offset + CP_USER] + cp_times[offset + CP_NICE] + cp_times[offset + CP_SYS] + cp_times[offset + CP_INTR];
237 jlong total = used + cp_times[offset + CP_IDLE];
238
239 if (counters.cpus[cpu_number].used == 0 || counters.cpus[cpu_number].total == 0) {
240 // First call, just set the last values
241 counters.cpus[cpu_number].used = used;
242 counters.cpus[cpu_number].total = total;
243 // return 0 since we have no data, not -1 which indicates error
244 return 0.;
245 }
246
247 jlong used_delta = used - counters.cpus[cpu_number].used;
248 jlong total_delta = total - counters.cpus[cpu_number].total;
249
250 jdouble cpu = (jdouble) used_delta / total_delta;
251
252 counters.cpus[cpu_number].used = used;
253 counters.cpus[cpu_number].total = total;
254
255 return cpu;
256 }
257 else {
258 #endif
259 return -1.0;
260 #ifdef __FreeBSD__
261 }
262 #endif
263 }
264
265 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getHostTotalCpuTicks0(JNIEnv * env,jobject mbean)266 Java_com_sun_management_internal_OperatingSystemImpl_getHostTotalCpuTicks0
267 (JNIEnv *env, jobject mbean)
268 {
269 return -1;
270 }
271
272 JNIEXPORT jint JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getHostConfiguredCpuCount0(JNIEnv * env,jobject mbean)273 Java_com_sun_management_internal_OperatingSystemImpl_getHostConfiguredCpuCount0
274 (JNIEnv *env, jobject mbean)
275 {
276 if (perfInit() == 0) {
277 return counters.nProcs;
278 }
279 else {
280 return -1;
281 }
282 }
283
284 JNIEXPORT jint JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getHostOnlineCpuCount0(JNIEnv * env,jobject mbean)285 Java_com_sun_management_internal_OperatingSystemImpl_getHostOnlineCpuCount0
286 (JNIEnv *env, jobject mbean)
287 {
288 #ifdef __FreeBSD__
289 int n = sysconf(_SC_NPROCESSORS_ONLN);
290 if (n <= 0) {
291 n = 1;
292 }
293 return n;
294 #else
295 return -1;
296 #endif
297 }
298