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