Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c
32287 views
1
/*
2
* Copyright (c) 2011, 2019, 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 <stdio.h>
27
#include <stdint.h>
28
#include <stdarg.h>
29
#include <unistd.h>
30
#include <errno.h>
31
#include <string.h>
32
#include <sys/resource.h>
33
#include <sys/types.h>
34
#include <dirent.h>
35
#include <stdlib.h>
36
#include <dlfcn.h>
37
#include <pthread.h>
38
#include "sun_management_OperatingSystemImpl.h"
39
40
struct ticks {
41
uint64_t used;
42
uint64_t usedKernel;
43
uint64_t total;
44
};
45
46
typedef struct ticks ticks;
47
48
typedef enum {
49
CPU_LOAD_VM_ONLY,
50
CPU_LOAD_GLOBAL,
51
} CpuLoadTarget;
52
53
static struct perfbuf {
54
int nProcs;
55
ticks jvmTicks;
56
ticks cpuTicks;
57
ticks *cpus;
58
} counters;
59
60
#define DEC_64 "%lld"
61
62
static void next_line(FILE *f) {
63
while (fgetc(f) != '\n');
64
}
65
66
/**
67
* Return the total number of ticks since the system was booted.
68
* If the usedTicks parameter is not NULL, it will be filled with
69
* the number of ticks spent on actual processes (user, system or
70
* nice processes) since system boot. Note that this is the total number
71
* of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
72
* n times the number of ticks that has passed in clock time.
73
*
74
* Returns a negative value if the reading of the ticks failed.
75
*/
76
static int get_totalticks(int which, ticks *pticks) {
77
FILE *fh;
78
uint64_t userTicks, niceTicks, systemTicks, idleTicks;
79
uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;
80
int n;
81
82
if((fh = fopen("/proc/stat", "r")) == NULL) {
83
return -1;
84
}
85
86
n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
87
DEC_64 " " DEC_64,
88
&userTicks, &niceTicks, &systemTicks, &idleTicks,
89
&iowTicks, &irqTicks, &sirqTicks);
90
91
// Move to next line
92
next_line(fh);
93
94
//find the line for requested cpu faster to just iterate linefeeds?
95
if (which != -1) {
96
int i;
97
for (i = 0; i < which; i++) {
98
if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
99
DEC_64 " " DEC_64 " " DEC_64,
100
&userTicks, &niceTicks, &systemTicks, &idleTicks,
101
&iowTicks, &irqTicks, &sirqTicks) < 4) {
102
fclose(fh);
103
return -2;
104
}
105
next_line(fh);
106
}
107
n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
108
DEC_64 " " DEC_64 " " DEC_64 "\n",
109
&userTicks, &niceTicks, &systemTicks, &idleTicks,
110
&iowTicks, &irqTicks, &sirqTicks);
111
}
112
113
fclose(fh);
114
if (n < 4) {
115
return -2;
116
}
117
118
pticks->used = userTicks + niceTicks;
119
pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
120
pticks->total = userTicks + niceTicks + systemTicks + idleTicks +
121
iowTicks + irqTicks + sirqTicks;
122
123
return 0;
124
}
125
126
static int vread_statdata(const char *procfile, const char *fmt, va_list args) {
127
FILE *f;
128
int n;
129
char buf[2048];
130
131
if ((f = fopen(procfile, "r")) == NULL) {
132
return -1;
133
}
134
135
if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
136
char *tmp;
137
138
buf[n-1] = '\0';
139
/** skip through pid and exec name. the exec name _could be wacky_ (renamed) and
140
* make scanf go mupp.
141
*/
142
if ((tmp = strrchr(buf, ')')) != NULL) {
143
// skip the ')' and the following space but check that the buffer is long enough
144
tmp += 2;
145
if (tmp < buf + n) {
146
n = vsscanf(tmp, fmt, args);
147
}
148
}
149
}
150
151
fclose(f);
152
153
return n;
154
}
155
156
static int read_statdata(const char *procfile, const char *fmt, ...) {
157
int n;
158
va_list args;
159
160
va_start(args, fmt);
161
n = vread_statdata(procfile, fmt, args);
162
va_end(args);
163
return n;
164
}
165
166
/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
167
static int read_ticks(const char *procfile, uint64_t *userTicks, uint64_t *systemTicks) {
168
return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "DEC_64" "DEC_64,
169
userTicks, systemTicks
170
);
171
}
172
173
/**
174
* Return the number of ticks spent in any of the processes belonging
175
* to the JVM on any CPU.
176
*/
177
static int get_jvmticks(ticks *pticks) {
178
uint64_t userTicks;
179
uint64_t systemTicks;
180
181
if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) {
182
return -1;
183
}
184
185
// get the total
186
if (get_totalticks(-1, pticks) < 0) {
187
return -1;
188
}
189
190
pticks->used = userTicks;
191
pticks->usedKernel = systemTicks;
192
193
return 0;
194
}
195
196
/**
197
* This method must be called first, before any data can be gathererd.
198
*/
199
int perfInit() {
200
static int initialized = 0;
201
202
if (!initialized) {
203
int i;
204
205
// We need to allocate counters for all CPUs, including ones that
206
// are currently offline as they could be turned online later.
207
int n = sysconf(_SC_NPROCESSORS_CONF);
208
if (n <= 0) {
209
n = 1;
210
}
211
212
counters.cpus = calloc(n,sizeof(ticks));
213
counters.nProcs = n;
214
if (counters.cpus != NULL) {
215
// For the CPU load
216
get_totalticks(-1, &counters.cpuTicks);
217
218
for (i = 0; i < n; i++) {
219
get_totalticks(i, &counters.cpus[i]);
220
}
221
// For JVM load
222
get_jvmticks(&counters.jvmTicks);
223
initialized = 1;
224
}
225
}
226
227
return initialized ? 0 : -1;
228
}
229
230
#define MAX(a,b) (a>b?a:b)
231
#define MIN(a,b) (a<b?a:b)
232
233
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
234
235
/**
236
* Return the load of the CPU as a double. 1.0 means the CPU process uses all
237
* available time for user or system processes, 0.0 means the CPU uses all time
238
* being idle.
239
*
240
* Returns a negative value if there is a problem in determining the CPU load.
241
*/
242
243
static double get_cpuload_internal(int which, double *pkernelLoad, CpuLoadTarget target) {
244
uint64_t udiff, kdiff, tdiff;
245
ticks *pticks, tmp;
246
double user_load = -1.0;
247
int failed = 0;
248
249
*pkernelLoad = 0.0;
250
251
pthread_mutex_lock(&lock);
252
253
if(perfInit() == 0) {
254
255
if (target == CPU_LOAD_VM_ONLY) {
256
pticks = &counters.jvmTicks;
257
} else if (which == -1) {
258
pticks = &counters.cpuTicks;
259
} else {
260
pticks = &counters.cpus[which];
261
}
262
263
tmp = *pticks;
264
265
if (target == CPU_LOAD_VM_ONLY) {
266
if (get_jvmticks(pticks) != 0) {
267
failed = 1;
268
}
269
} else if (get_totalticks(which, pticks) < 0) {
270
failed = 1;
271
}
272
273
if(!failed) {
274
// seems like we sometimes end up with less kernel ticks when
275
// reading /proc/self/stat a second time, timing issue between cpus?
276
if (pticks->usedKernel < tmp.usedKernel) {
277
kdiff = 0;
278
} else {
279
kdiff = pticks->usedKernel - tmp.usedKernel;
280
}
281
tdiff = pticks->total - tmp.total;
282
udiff = pticks->used - tmp.used;
283
284
if (tdiff == 0) {
285
user_load = 0;
286
} else {
287
if (tdiff < (udiff + kdiff)) {
288
tdiff = udiff + kdiff;
289
}
290
*pkernelLoad = (kdiff / (double)tdiff);
291
// BUG9044876, normalize return values to sane values
292
*pkernelLoad = MAX(*pkernelLoad, 0.0);
293
*pkernelLoad = MIN(*pkernelLoad, 1.0);
294
295
user_load = (udiff / (double)tdiff);
296
user_load = MAX(user_load, 0.0);
297
user_load = MIN(user_load, 1.0);
298
}
299
}
300
}
301
pthread_mutex_unlock(&lock);
302
return user_load;
303
}
304
305
double get_cpu_load(int which) {
306
double u, s;
307
u = get_cpuload_internal(which, &s, CPU_LOAD_GLOBAL);
308
if (u < 0) {
309
return -1.0;
310
}
311
// Cap total systemload to 1.0
312
return MIN((u + s), 1.0);
313
}
314
315
double get_process_load() {
316
double u, s;
317
u = get_cpuload_internal(-1, &s, CPU_LOAD_VM_ONLY);
318
if (u < 0) {
319
return -1.0;
320
}
321
return u + s;
322
}
323
324
JNIEXPORT jdouble JNICALL
325
Java_sun_management_OperatingSystemImpl_getSystemCpuLoad0
326
(JNIEnv *env, jobject dummy)
327
{
328
if (perfInit() == 0) {
329
return get_cpu_load(-1);
330
} else {
331
return -1.0;
332
}
333
}
334
335
JNIEXPORT jdouble JNICALL
336
Java_sun_management_OperatingSystemImpl_getProcessCpuLoad
337
(JNIEnv *env, jobject dummy)
338
{
339
if (perfInit() == 0) {
340
return get_process_load();
341
} else {
342
return -1.0;
343
}
344
}
345
346
JNIEXPORT jdouble JNICALL
347
Java_sun_management_OperatingSystemImpl_getSingleCpuLoad0
348
(JNIEnv *env, jobject mbean, jint cpu_number)
349
{
350
if (perfInit() == 0 && cpu_number >= 0 && cpu_number < counters.nProcs) {
351
return get_cpu_load(cpu_number);
352
} else {
353
return -1.0;
354
}
355
}
356
357
JNIEXPORT jint JNICALL
358
Java_sun_management_OperatingSystemImpl_getHostConfiguredCpuCount0
359
(JNIEnv *env, jobject mbean)
360
{
361
if (perfInit() == 0) {
362
return counters.nProcs;
363
} else {
364
return -1;
365
}
366
}
367
368