Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/linux/vm/os_perf_linux.cpp
32285 views
1
/*
2
* Copyright (c) 2012, 2018, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "precompiled.hpp"
26
#include "jvm.h"
27
#include "memory/allocation.inline.hpp"
28
#include "os_linux.inline.hpp"
29
#include "runtime/os.hpp"
30
#include "runtime/os_perf.hpp"
31
32
#ifdef TARGET_ARCH_aarch32
33
# include "vm_version_ext_aarch32.hpp"
34
#endif
35
#ifdef TARGET_ARCH_aarch64
36
# include "vm_version_ext_aarch64.hpp"
37
#endif
38
#ifdef TARGET_ARCH_x86
39
# include "vm_version_ext_x86.hpp"
40
#endif
41
#ifdef TARGET_ARCH_sparc
42
# include "vm_version_ext_sparc.hpp"
43
#endif
44
#ifdef TARGET_ARCH_zero
45
# include "vm_version_ext_zero.hpp"
46
#endif
47
#ifdef TARGET_ARCH_arm
48
# include "vm_version_ext_arm.hpp"
49
#endif
50
#ifdef TARGET_ARCH_ppc
51
# include "vm_version_ext_ppc.hpp"
52
#endif
53
54
#include <stdio.h>
55
#include <stdarg.h>
56
#include <unistd.h>
57
#include <errno.h>
58
#include <string.h>
59
#include <sys/resource.h>
60
#include <sys/types.h>
61
#include <sys/stat.h>
62
#include <dirent.h>
63
#include <stdlib.h>
64
#include <dlfcn.h>
65
#include <pthread.h>
66
#include <limits.h>
67
68
#ifdef __ANDROID__
69
# include "ifaddrs.h"
70
#else
71
# include <ifaddrs.h>
72
#endif
73
#include <fcntl.h>
74
75
/**
76
/proc/[number]/stat
77
Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.
78
79
The fields, in order, with their proper scanf(3) format specifiers, are:
80
81
1. pid %d The process id.
82
83
2. comm %s
84
The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
85
86
3. state %c
87
One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk
88
sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
89
90
4. ppid %d
91
The PID of the parent.
92
93
5. pgrp %d
94
The process group ID of the process.
95
96
6. session %d
97
The session ID of the process.
98
99
7. tty_nr %d
100
The tty the process uses.
101
102
8. tpgid %d
103
The process group ID of the process which currently owns the tty that the process is connected to.
104
105
9. flags %lu
106
The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.
107
108
10. minflt %lu
109
The number of minor faults the process has made which have not required loading a memory page from disk.
110
111
11. cminflt %lu
112
The number of minor faults that the process's waited-for children have made.
113
114
12. majflt %lu
115
The number of major faults the process has made which have required loading a memory page from disk.
116
117
13. cmajflt %lu
118
The number of major faults that the process's waited-for children have made.
119
120
14. utime %lu
121
The number of jiffies that this process has been scheduled in user mode.
122
123
15. stime %lu
124
The number of jiffies that this process has been scheduled in kernel mode.
125
126
16. cutime %ld
127
The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)
128
129
17. cstime %ld
130
The number of jiffies that this process' waited-for children have been scheduled in kernel mode.
131
132
18. priority %ld
133
The standard nice value, plus fifteen. The value is never negative in the kernel.
134
135
19. nice %ld
136
The nice value ranges from 19 (nicest) to -19 (not nice to others).
137
138
20. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.
139
140
21. itrealvalue %ld
141
The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
142
143
22. starttime %lu
144
The time in jiffies the process started after system boot.
145
146
23. vsize %lu
147
Virtual memory size in bytes.
148
149
24. rss %ld
150
Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count
151
towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.
152
153
25. rlim %lu
154
Current limit in bytes on the rss of the process (usually 4294967295 on i386).
155
156
26. startcode %lu
157
The address above which program text can run.
158
159
27. endcode %lu
160
The address below which program text can run.
161
162
28. startstack %lu
163
The address of the start of the stack.
164
165
29. kstkesp %lu
166
The current value of esp (stack pointer), as found in the kernel stack page for the process.
167
168
30. kstkeip %lu
169
The current EIP (instruction pointer).
170
171
31. signal %lu
172
The bitmap of pending signals (usually 0).
173
174
32. blocked %lu
175
The bitmap of blocked signals (usually 0, 2 for shells).
176
177
33. sigignore %lu
178
The bitmap of ignored signals.
179
180
34. sigcatch %lu
181
The bitmap of catched signals.
182
183
35. wchan %lu
184
This is the "channel" in which the process is waiting. It is the address of a system call, and can be looked up in a namelist if you need
185
a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)
186
187
36. nswap %lu
188
Number of pages swapped - not maintained.
189
190
37. cnswap %lu
191
Cumulative nswap for child processes.
192
193
38. exit_signal %d
194
Signal to be sent to parent when we die.
195
196
39. processor %d
197
CPU number last executed on.
198
199
200
201
///// SSCANF FORMAT STRING. Copy and use.
202
203
field: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
204
format: %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d
205
206
207
*/
208
209
/**
210
* For platforms that have them, when declaring
211
* a printf-style function,
212
* formatSpec is the parameter number (starting at 1)
213
* that is the format argument ("%d pid %s")
214
* params is the parameter number where the actual args to
215
* the format starts. If the args are in a va_list, this
216
* should be 0.
217
*/
218
#ifndef PRINTF_ARGS
219
# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params)
220
#endif
221
222
#ifndef SCANF_ARGS
223
# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params)
224
#endif
225
226
#ifndef _PRINTFMT_
227
# define _PRINTFMT_
228
#endif
229
230
#ifndef _SCANFMT_
231
# define _SCANFMT_
232
#endif
233
234
235
struct CPUPerfTicks {
236
uint64_t used;
237
uint64_t usedKernel;
238
uint64_t total;
239
};
240
241
typedef enum {
242
CPU_LOAD_VM_ONLY,
243
CPU_LOAD_GLOBAL,
244
} CpuLoadTarget;
245
246
enum {
247
UNDETECTED,
248
UNDETECTABLE,
249
LINUX26_NPTL,
250
BAREMETAL
251
};
252
253
struct CPUPerfCounters {
254
int nProcs;
255
CPUPerfTicks jvmTicks;
256
CPUPerfTicks* cpus;
257
};
258
259
static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);
260
261
/** reads /proc/<pid>/stat data, with some checks and some skips.
262
* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"
263
*/
264
static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {
265
FILE*f;
266
int n;
267
char buf[2048];
268
269
if ((f = fopen(procfile, "r")) == NULL) {
270
return -1;
271
}
272
273
if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
274
char *tmp;
275
276
buf[n-1] = '\0';
277
/** skip through pid and exec name. */
278
if ((tmp = strrchr(buf, ')')) != NULL) {
279
// skip the ')' and the following space
280
// but check that buffer is long enough
281
tmp += 2;
282
if (tmp < buf + n) {
283
n = vsscanf(tmp, fmt, args);
284
}
285
}
286
}
287
288
fclose(f);
289
290
return n;
291
}
292
293
static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {
294
int n;
295
va_list args;
296
297
va_start(args, fmt);
298
n = vread_statdata(procfile, fmt, args);
299
va_end(args);
300
return n;
301
}
302
303
static FILE* open_statfile(void) {
304
FILE *f;
305
306
if ((f = fopen("/proc/stat", "r")) == NULL) {
307
static int haveWarned = 0;
308
if (!haveWarned) {
309
haveWarned = 1;
310
}
311
}
312
return f;
313
}
314
315
static void
316
next_line(FILE *f) {
317
int c;
318
do {
319
c = fgetc(f);
320
} while (c != '\n' && c != EOF);
321
}
322
323
/**
324
* Return the total number of ticks since the system was booted.
325
* If the usedTicks parameter is not NULL, it will be filled with
326
* the number of ticks spent on actual processes (user, system or
327
* nice processes) since system boot. Note that this is the total number
328
* of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
329
* n times the number of ticks that has passed in clock time.
330
*
331
* Returns a negative value if the reading of the ticks failed.
332
*/
333
static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {
334
FILE* fh;
335
uint64_t userTicks, niceTicks, systemTicks, idleTicks;
336
uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;
337
int logical_cpu = -1;
338
const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;
339
int n;
340
341
if ((fh = open_statfile()) == NULL) {
342
return OS_ERR;
343
}
344
if (-1 == which_logical_cpu) {
345
n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
346
UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
347
&userTicks, &niceTicks, &systemTicks, &idleTicks,
348
&iowTicks, &irqTicks, &sirqTicks);
349
} else {
350
// Move to next line
351
next_line(fh);
352
353
// find the line for requested cpu faster to just iterate linefeeds?
354
for (int i = 0; i < which_logical_cpu; i++) {
355
next_line(fh);
356
}
357
358
n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
359
UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
360
&logical_cpu, &userTicks, &niceTicks,
361
&systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);
362
}
363
364
fclose(fh);
365
if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
366
#ifdef DEBUG_LINUX_PROC_STAT
367
vm_fprintf(stderr, "[stat] read failed");
368
#endif
369
return OS_ERR;
370
}
371
372
#ifdef DEBUG_LINUX_PROC_STAT
373
vm_fprintf(stderr, "[stat] read "
374
UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
375
UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",
376
userTicks, niceTicks, systemTicks, idleTicks,
377
iowTicks, irqTicks, sirqTicks);
378
#endif
379
380
pticks->used = userTicks + niceTicks;
381
pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
382
pticks->total = userTicks + niceTicks + systemTicks + idleTicks +
383
iowTicks + irqTicks + sirqTicks;
384
385
return OS_OK;
386
}
387
388
389
static int get_systemtype(void) {
390
static int procEntriesType = UNDETECTED;
391
DIR *taskDir;
392
393
if (procEntriesType != UNDETECTED) {
394
return procEntriesType;
395
}
396
397
// Check whether we have a task subdirectory
398
if ((taskDir = opendir("/proc/self/task")) == NULL) {
399
procEntriesType = UNDETECTABLE;
400
} else {
401
// The task subdirectory exists; we're on a Linux >= 2.6 system
402
closedir(taskDir);
403
procEntriesType = LINUX26_NPTL;
404
}
405
406
return procEntriesType;
407
}
408
409
/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
410
static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {
411
return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,
412
userTicks, systemTicks);
413
}
414
415
/**
416
* Return the number of ticks spent in any of the processes belonging
417
* to the JVM on any CPU.
418
*/
419
static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {
420
uint64_t userTicks;
421
uint64_t systemTicks;
422
423
if (get_systemtype() != LINUX26_NPTL) {
424
return OS_ERR;
425
}
426
427
if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {
428
return OS_ERR;
429
}
430
431
// get the total
432
if (get_total_ticks(-1, pticks) != OS_OK) {
433
return OS_ERR;
434
}
435
436
pticks->used = userTicks;
437
pticks->usedKernel = systemTicks;
438
439
return OS_OK;
440
}
441
442
/**
443
* Return the load of the CPU as a double. 1.0 means the CPU process uses all
444
* available time for user or system processes, 0.0 means the CPU uses all time
445
* being idle.
446
*
447
* Returns a negative value if there is a problem in determining the CPU load.
448
*/
449
static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {
450
uint64_t udiff, kdiff, tdiff;
451
CPUPerfTicks* pticks;
452
CPUPerfTicks tmp;
453
double user_load;
454
455
*pkernelLoad = 0.0;
456
457
if (target == CPU_LOAD_VM_ONLY) {
458
pticks = &counters->jvmTicks;
459
} else if (-1 == which_logical_cpu) {
460
pticks = &counters->cpus[counters->nProcs];
461
} else {
462
pticks = &counters->cpus[which_logical_cpu];
463
}
464
465
tmp = *pticks;
466
467
if (target == CPU_LOAD_VM_ONLY) {
468
if (get_jvm_ticks(pticks) != OS_OK) {
469
return -1.0;
470
}
471
} else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {
472
return -1.0;
473
}
474
475
// seems like we sometimes end up with less kernel ticks when
476
// reading /proc/self/stat a second time, timing issue between cpus?
477
if (pticks->usedKernel < tmp.usedKernel) {
478
kdiff = 0;
479
} else {
480
kdiff = pticks->usedKernel - tmp.usedKernel;
481
}
482
tdiff = pticks->total - tmp.total;
483
udiff = pticks->used - tmp.used;
484
485
if (tdiff == 0) {
486
return 0.0;
487
} else if (tdiff < (udiff + kdiff)) {
488
tdiff = udiff + kdiff;
489
}
490
*pkernelLoad = (kdiff / (double)tdiff);
491
// BUG9044876, normalize return values to sane values
492
*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);
493
*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);
494
495
user_load = (udiff / (double)tdiff);
496
user_load = MAX2<double>(user_load, 0.0);
497
user_load = MIN2<double>(user_load, 1.0);
498
499
return user_load;
500
}
501
502
static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {
503
FILE *f;
504
va_list args;
505
506
va_start(args, fmt);
507
508
if ((f = open_statfile()) == NULL) {
509
va_end(args);
510
return OS_ERR;
511
}
512
for (;;) {
513
char line[80];
514
if (fgets(line, sizeof(line), f) != NULL) {
515
if (vsscanf(line, fmt, args) == 1) {
516
fclose(f);
517
va_end(args);
518
return OS_OK;
519
}
520
} else {
521
fclose(f);
522
va_end(args);
523
return OS_ERR;
524
}
525
}
526
}
527
528
static int get_noof_context_switches(uint64_t* switches) {
529
return parse_stat("ctxt " UINT64_FORMAT "\n", switches);
530
}
531
532
/** returns boot time in _seconds_ since epoch */
533
static int get_boot_time(uint64_t* time) {
534
return parse_stat("btime " UINT64_FORMAT "\n", time);
535
}
536
537
static int perf_context_switch_rate(double* rate) {
538
static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
539
static uint64_t lastTime;
540
static uint64_t lastSwitches;
541
static double lastRate;
542
543
uint64_t lt = 0;
544
int res = 0;
545
546
if (lastTime == 0) {
547
uint64_t tmp;
548
if (get_boot_time(&tmp) < 0) {
549
return OS_ERR;
550
}
551
lt = tmp * 1000;
552
}
553
554
res = OS_OK;
555
556
pthread_mutex_lock(&contextSwitchLock);
557
{
558
559
uint64_t sw;
560
s8 t, d;
561
562
if (lastTime == 0) {
563
lastTime = lt;
564
}
565
566
t = os::javaTimeMillis();
567
d = t - lastTime;
568
569
if (d == 0) {
570
*rate = lastRate;
571
} else if (!get_noof_context_switches(&sw)) {
572
*rate = ( (double)(sw - lastSwitches) / d ) * 1000;
573
lastRate = *rate;
574
lastSwitches = sw;
575
lastTime = t;
576
} else {
577
*rate = 0;
578
res = OS_ERR;
579
}
580
if (*rate <= 0) {
581
*rate = 0;
582
lastRate = 0;
583
}
584
}
585
pthread_mutex_unlock(&contextSwitchLock);
586
587
return res;
588
}
589
590
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
591
friend class CPUPerformanceInterface;
592
private:
593
CPUPerfCounters _counters;
594
595
int cpu_load(int which_logical_cpu, double* cpu_load);
596
int context_switch_rate(double* rate);
597
int cpu_load_total_process(double* cpu_load);
598
int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
599
600
public:
601
CPUPerformance();
602
bool initialize();
603
~CPUPerformance();
604
};
605
606
CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
607
_counters.nProcs = os::active_processor_count();
608
_counters.cpus = NULL;
609
}
610
611
bool CPUPerformanceInterface::CPUPerformance::initialize() {
612
size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);
613
_counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
614
if (NULL == _counters.cpus) {
615
return false;
616
}
617
memset(_counters.cpus, 0, tick_array_size);
618
619
// For the CPU load total
620
get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);
621
622
// For each CPU
623
for (int i = 0; i < _counters.nProcs; i++) {
624
get_total_ticks(i, &_counters.cpus[i]);
625
}
626
// For JVM load
627
get_jvm_ticks(&_counters.jvmTicks);
628
629
// initialize context switch system
630
// the double is only for init
631
double init_ctx_switch_rate;
632
perf_context_switch_rate(&init_ctx_switch_rate);
633
634
return true;
635
}
636
637
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
638
if (_counters.cpus != NULL) {
639
FREE_C_HEAP_ARRAY(char, _counters.cpus, mtInternal);
640
}
641
}
642
643
int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
644
double u, s;
645
u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);
646
if (u < 0) {
647
*cpu_load = 0.0;
648
return OS_ERR;
649
}
650
// Cap total systemload to 1.0
651
*cpu_load = MIN2<double>((u + s), 1.0);
652
return OS_OK;
653
}
654
655
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
656
double u, s;
657
u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
658
if (u < 0) {
659
*cpu_load = 0.0;
660
return OS_ERR;
661
}
662
*cpu_load = u + s;
663
return OS_OK;
664
}
665
666
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
667
double u, s, t;
668
669
assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
670
assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
671
assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
672
673
u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
674
if (u < 0) {
675
*pjvmUserLoad = 0.0;
676
*pjvmKernelLoad = 0.0;
677
*psystemTotalLoad = 0.0;
678
return OS_ERR;
679
}
680
681
cpu_load(-1, &t);
682
// clamp at user+system and 1.0
683
if (u + s > t) {
684
t = MIN2<double>(u + s, 1.0);
685
}
686
687
*pjvmUserLoad = u;
688
*pjvmKernelLoad = s;
689
*psystemTotalLoad = t;
690
691
return OS_OK;
692
}
693
694
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
695
return perf_context_switch_rate(rate);
696
}
697
698
CPUPerformanceInterface::CPUPerformanceInterface() {
699
_impl = NULL;
700
}
701
702
bool CPUPerformanceInterface::initialize() {
703
_impl = new CPUPerformanceInterface::CPUPerformance();
704
return NULL == _impl ? false : _impl->initialize();
705
}
706
707
CPUPerformanceInterface::~CPUPerformanceInterface() {
708
if (_impl != NULL) {
709
delete _impl;
710
}
711
}
712
713
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
714
return _impl->cpu_load(which_logical_cpu, cpu_load);
715
}
716
717
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
718
return _impl->cpu_load_total_process(cpu_load);
719
}
720
721
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
722
return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
723
}
724
725
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
726
return _impl->context_switch_rate(rate);
727
}
728
729
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
730
friend class SystemProcessInterface;
731
private:
732
class ProcessIterator : public CHeapObj<mtInternal> {
733
friend class SystemProcessInterface::SystemProcesses;
734
private:
735
DIR* _dir;
736
struct dirent* _entry;
737
bool _valid;
738
char _exeName[PATH_MAX];
739
char _exePath[PATH_MAX];
740
741
ProcessIterator();
742
~ProcessIterator();
743
bool initialize();
744
745
bool is_valid() const { return _valid; }
746
bool is_valid_entry(struct dirent* entry) const;
747
bool is_dir(const char* name) const;
748
int fsize(const char* name, uint64_t& size) const;
749
750
char* allocate_string(const char* str) const;
751
void get_exe_name();
752
char* get_exe_path();
753
char* get_cmdline();
754
755
int current(SystemProcess* process_info);
756
int next_process();
757
};
758
759
ProcessIterator* _iterator;
760
SystemProcesses();
761
bool initialize();
762
~SystemProcesses();
763
764
//information about system processes
765
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
766
};
767
768
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
769
struct stat mystat;
770
int ret_val = 0;
771
772
ret_val = stat(name, &mystat);
773
if (ret_val < 0) {
774
return false;
775
}
776
ret_val = S_ISDIR(mystat.st_mode);
777
return ret_val > 0;
778
}
779
780
int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {
781
assert(name != NULL, "name pointer is NULL!");
782
size = 0;
783
struct stat fbuf;
784
785
if (stat(name, &fbuf) < 0) {
786
return OS_ERR;
787
}
788
size = fbuf.st_size;
789
return OS_OK;
790
}
791
792
// if it has a numeric name, is a directory and has a 'stat' file in it
793
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
794
char buffer[PATH_MAX];
795
uint64_t size = 0;
796
797
if (atoi(entry->d_name) != 0) {
798
jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
799
buffer[PATH_MAX - 1] = '\0';
800
801
if (is_dir(buffer)) {
802
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);
803
buffer[PATH_MAX - 1] = '\0';
804
if (fsize(buffer, size) != OS_ERR) {
805
return true;
806
}
807
}
808
}
809
return false;
810
}
811
812
// get exe-name from /proc/<pid>/stat
813
void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {
814
FILE* fp;
815
char buffer[PATH_MAX];
816
817
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);
818
buffer[PATH_MAX - 1] = '\0';
819
if ((fp = fopen(buffer, "r")) != NULL) {
820
if (fgets(buffer, PATH_MAX, fp) != NULL) {
821
char* start, *end;
822
// exe-name is between the first pair of ( and )
823
start = strchr(buffer, '(');
824
if (start != NULL && start[1] != '\0') {
825
start++;
826
end = strrchr(start, ')');
827
if (end != NULL) {
828
size_t len;
829
len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);
830
memcpy(_exeName, start, len);
831
_exeName[len] = '\0';
832
}
833
}
834
}
835
fclose(fp);
836
}
837
}
838
839
// get command line from /proc/<pid>/cmdline
840
char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {
841
FILE* fp;
842
char buffer[PATH_MAX];
843
char* cmdline = NULL;
844
845
jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);
846
buffer[PATH_MAX - 1] = '\0';
847
if ((fp = fopen(buffer, "r")) != NULL) {
848
size_t size = 0;
849
char dummy;
850
851
// find out how long the file is (stat always returns 0)
852
while (fread(&dummy, 1, 1, fp) == 1) {
853
size++;
854
}
855
if (size > 0) {
856
cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);
857
if (cmdline != NULL) {
858
cmdline[0] = '\0';
859
if (fseek(fp, 0, SEEK_SET) == 0) {
860
if (fread(cmdline, 1, size, fp) == size) {
861
// the file has the arguments separated by '\0',
862
// so we translate '\0' to ' '
863
for (size_t i = 0; i < size; i++) {
864
if (cmdline[i] == '\0') {
865
cmdline[i] = ' ';
866
}
867
}
868
cmdline[size] = '\0';
869
}
870
}
871
}
872
}
873
fclose(fp);
874
}
875
return cmdline;
876
}
877
878
// get full path to exe from /proc/<pid>/exe symlink
879
char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
880
char buffer[PATH_MAX];
881
882
jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
883
buffer[PATH_MAX - 1] = '\0';
884
return realpath(buffer, _exePath);
885
}
886
887
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
888
if (str != NULL) {
889
size_t len = strlen(str);
890
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
891
strncpy(tmp, str, len);
892
tmp[len] = '\0';
893
return tmp;
894
}
895
return NULL;
896
}
897
898
int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
899
if (!is_valid()) {
900
return OS_ERR;
901
}
902
903
process_info->set_pid(atoi(_entry->d_name));
904
905
get_exe_name();
906
process_info->set_name(allocate_string(_exeName));
907
908
if (get_exe_path() != NULL) {
909
process_info->set_path(allocate_string(_exePath));
910
}
911
912
char* cmdline = NULL;
913
cmdline = get_cmdline();
914
if (cmdline != NULL) {
915
process_info->set_command_line(allocate_string(cmdline));
916
FREE_C_HEAP_ARRAY(char, cmdline, mtInternal);
917
}
918
919
return OS_OK;
920
}
921
922
int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
923
if (!is_valid()) {
924
return OS_ERR;
925
}
926
927
do {
928
_entry = os::readdir(_dir);
929
if (_entry == NULL) {
930
// Error or reached end. Could use errno to distinguish those cases.
931
_valid = false;
932
return OS_ERR;
933
}
934
} while(!is_valid_entry(_entry));
935
936
_valid = true;
937
return OS_OK;
938
}
939
940
SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
941
_dir = NULL;
942
_entry = NULL;
943
_valid = false;
944
}
945
946
bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
947
_dir = os::opendir("/proc");
948
_entry = NULL;
949
_valid = true;
950
next_process();
951
952
return true;
953
}
954
955
SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
956
if (_dir != NULL) {
957
os::closedir(_dir);
958
}
959
}
960
961
SystemProcessInterface::SystemProcesses::SystemProcesses() {
962
_iterator = NULL;
963
}
964
965
bool SystemProcessInterface::SystemProcesses::initialize() {
966
_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
967
return NULL == _iterator ? false : _iterator->initialize();
968
}
969
970
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
971
if (_iterator != NULL) {
972
delete _iterator;
973
}
974
}
975
976
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
977
assert(system_processes != NULL, "system_processes pointer is NULL!");
978
assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
979
assert(_iterator != NULL, "iterator is NULL!");
980
981
// initialize pointers
982
*no_of_sys_processes = 0;
983
*system_processes = NULL;
984
985
while (_iterator->is_valid()) {
986
SystemProcess* tmp = new SystemProcess();
987
_iterator->current(tmp);
988
989
//if already existing head
990
if (*system_processes != NULL) {
991
//move "first to second"
992
tmp->set_next(*system_processes);
993
}
994
// new head
995
*system_processes = tmp;
996
// increment
997
(*no_of_sys_processes)++;
998
// step forward
999
_iterator->next_process();
1000
}
1001
return OS_OK;
1002
}
1003
1004
int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
1005
return _impl->system_processes(system_procs, no_of_sys_processes);
1006
}
1007
1008
SystemProcessInterface::SystemProcessInterface() {
1009
_impl = NULL;
1010
}
1011
1012
bool SystemProcessInterface::initialize() {
1013
_impl = new SystemProcessInterface::SystemProcesses();
1014
return NULL == _impl ? false : _impl->initialize();
1015
}
1016
1017
SystemProcessInterface::~SystemProcessInterface() {
1018
if (_impl != NULL) {
1019
delete _impl;
1020
}
1021
}
1022
1023
CPUInformationInterface::CPUInformationInterface() {
1024
_cpu_info = NULL;
1025
}
1026
1027
bool CPUInformationInterface::initialize() {
1028
_cpu_info = new CPUInformation();
1029
if (NULL == _cpu_info) {
1030
return false;
1031
}
1032
_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
1033
_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
1034
_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
1035
_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
1036
_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
1037
1038
return true;
1039
}
1040
1041
CPUInformationInterface::~CPUInformationInterface() {
1042
if (_cpu_info != NULL) {
1043
if (_cpu_info->cpu_name() != NULL) {
1044
const char* cpu_name = _cpu_info->cpu_name();
1045
FREE_C_HEAP_ARRAY(char, cpu_name, mtInternal);
1046
_cpu_info->set_cpu_name(NULL);
1047
}
1048
if (_cpu_info->cpu_description() != NULL) {
1049
const char* cpu_desc = _cpu_info->cpu_description();
1050
FREE_C_HEAP_ARRAY(char, cpu_desc, mtInternal);
1051
_cpu_info->set_cpu_description(NULL);
1052
}
1053
delete _cpu_info;
1054
}
1055
}
1056
1057
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
1058
if (_cpu_info == NULL) {
1059
return OS_ERR;
1060
}
1061
1062
cpu_info = *_cpu_info; // shallow copy assignment
1063
return OS_OK;
1064
}
1065
1066
class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
1067
friend class NetworkPerformanceInterface;
1068
private:
1069
NetworkPerformance();
1070
NetworkPerformance(const NetworkPerformance& rhs); // no impl
1071
NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
1072
bool initialize();
1073
~NetworkPerformance();
1074
int64_t read_counter(const char* iface, const char* counter) const;
1075
int network_utilization(NetworkInterface** network_interfaces) const;
1076
};
1077
1078
NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
1079
1080
}
1081
1082
bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
1083
return true;
1084
}
1085
1086
NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
1087
}
1088
1089
int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const {
1090
char buf[128];
1091
1092
snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);
1093
1094
int fd = open(buf, O_RDONLY);
1095
if (fd == -1) {
1096
return -1;
1097
}
1098
1099
ssize_t num_bytes = read(fd, buf, sizeof(buf));
1100
close(fd);
1101
if ((num_bytes == -1) || (num_bytes >= static_cast<ssize_t>(sizeof(buf))) || (num_bytes < 1)) {
1102
return -1;
1103
}
1104
1105
buf[num_bytes] = '\0';
1106
int64_t value = strtoll(buf, NULL, 10);
1107
1108
return value;
1109
}
1110
1111
int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
1112
{
1113
ifaddrs* addresses;
1114
ifaddrs* cur_address;
1115
1116
if (getifaddrs(&addresses) != 0) {
1117
return OS_ERR;
1118
}
1119
1120
NetworkInterface* ret = NULL;
1121
for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {
1122
if ((cur_address->ifa_addr == NULL) || (cur_address->ifa_addr->sa_family != AF_PACKET)) {
1123
continue;
1124
}
1125
1126
int64_t bytes_in = read_counter(cur_address->ifa_name, "rx_bytes");
1127
int64_t bytes_out = read_counter(cur_address->ifa_name, "tx_bytes");
1128
1129
NetworkInterface* cur = new NetworkInterface(cur_address->ifa_name, bytes_in, bytes_out, ret);
1130
ret = cur;
1131
}
1132
1133
freeifaddrs(addresses);
1134
*network_interfaces = ret;
1135
1136
return OS_OK;
1137
}
1138
1139
NetworkPerformanceInterface::NetworkPerformanceInterface() {
1140
_impl = NULL;
1141
}
1142
1143
NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1144
if (_impl != NULL) {
1145
delete _impl;
1146
}
1147
}
1148
1149
bool NetworkPerformanceInterface::initialize() {
1150
_impl = new NetworkPerformanceInterface::NetworkPerformance();
1151
return _impl != NULL && _impl->initialize();
1152
}
1153
1154
int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1155
return _impl->network_utilization(network_interfaces);
1156
}
1157
1158