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