| 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 | |