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