annotate src/hotspot/os/solaris/os_perf_solaris.cpp @ 51513:d90c3cbf13df

8003209: JFR events for network utilization Reviewed-by: mgronlun, egahlin
author rwestberg
date Thu, 28 Jun 2018 15:06:55 +0200
parents caf115bb98ad
children f605c91e5219 d2c720caa480
rev   line source
egahlin@50662 1 /*
egahlin@50662 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
egahlin@50662 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
egahlin@50662 4 *
egahlin@50662 5 * This code is free software; you can redistribute it and/or modify it
egahlin@50662 6 * under the terms of the GNU General Public License version 2 only, as
egahlin@50662 7 * published by the Free Software Foundation.
egahlin@50662 8 *
egahlin@50662 9 * This code is distributed in the hope that it will be useful, but WITHOUT
egahlin@50662 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
egahlin@50662 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
egahlin@50662 12 * version 2 for more details (a copy is included in the LICENSE file that
egahlin@50662 13 * accompanied this code).
egahlin@50662 14 *
egahlin@50662 15 * You should have received a copy of the GNU General Public License version
egahlin@50662 16 * 2 along with this work; if not, write to the Free Software Foundation,
egahlin@50662 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
egahlin@50662 18 *
egahlin@50662 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
egahlin@50662 20 * or visit www.oracle.com if you need additional information or have any
egahlin@50662 21 * questions.
egahlin@50662 22 *
egahlin@50662 23 */
egahlin@50662 24
egahlin@50662 25 #include "precompiled.hpp"
egahlin@50662 26 #include "jvm.h"
egahlin@50662 27 #include "memory/allocation.inline.hpp"
egahlin@50662 28 #include "runtime/os.hpp"
egahlin@50662 29 #include "runtime/os_perf.hpp"
egahlin@50662 30 #include "os_solaris.inline.hpp"
egahlin@50662 31 #include "utilities/macros.hpp"
egahlin@50662 32
egahlin@50662 33 #include CPU_HEADER(vm_version_ext)
egahlin@50662 34
egahlin@50662 35 #include <sys/types.h>
egahlin@50662 36 #include <procfs.h>
egahlin@50662 37 #include <dirent.h>
egahlin@50662 38 #include <errno.h>
egahlin@50662 39 #include <stdio.h>
egahlin@50662 40 #include <stdlib.h>
egahlin@50662 41 #include <strings.h>
egahlin@50662 42 #include <unistd.h>
egahlin@50662 43 #include <fcntl.h>
egahlin@50662 44 #include <kstat.h>
egahlin@50662 45 #include <unistd.h>
egahlin@50662 46 #include <string.h>
egahlin@50662 47 #include <sys/sysinfo.h>
egahlin@50662 48 #include <sys/lwp.h>
egahlin@50662 49 #include <pthread.h>
egahlin@50662 50 #include <time.h>
egahlin@50662 51 #include <utmpx.h>
egahlin@50662 52 #include <dlfcn.h>
egahlin@50662 53 #include <sys/loadavg.h>
egahlin@50662 54 #include <limits.h>
egahlin@50662 55
egahlin@50662 56 static const double NANOS_PER_SEC = 1000000000.0;
egahlin@50662 57
egahlin@50662 58 struct CPUPerfTicks {
egahlin@50662 59 kstat_t* kstat;
egahlin@50662 60 uint64_t last_idle;
egahlin@50662 61 uint64_t last_total;
egahlin@50662 62 double last_ratio;
egahlin@50662 63 };
egahlin@50662 64
egahlin@50662 65 struct CPUPerfCounters {
egahlin@50662 66 int nProcs;
egahlin@50662 67 CPUPerfTicks* jvmTicks;
egahlin@50662 68 kstat_ctl_t* kstat_ctrl;
egahlin@50662 69 };
egahlin@50662 70
egahlin@50662 71 static int get_info(const char* path, void* info, size_t s, off_t o) {
egahlin@50662 72 assert(path != NULL, "path is NULL!");
egahlin@50662 73 assert(info != NULL, "info is NULL!");
egahlin@50662 74
egahlin@50662 75 int fd = -1;
egahlin@50662 76
egahlin@50662 77 if ((fd = open(path, O_RDONLY)) < 0) {
egahlin@50662 78 return OS_ERR;
egahlin@50662 79 }
egahlin@50662 80 if (pread(fd, info, s, o) != s) {
egahlin@50662 81 close(fd);
egahlin@50662 82 return OS_ERR;
egahlin@50662 83 }
egahlin@50662 84 close(fd);
egahlin@50662 85 return OS_OK;
egahlin@50662 86 }
egahlin@50662 87
egahlin@50662 88 static int get_psinfo2(void* info, size_t s, off_t o) {
egahlin@50662 89 return get_info("/proc/self/psinfo", info, s, o);
egahlin@50662 90 }
egahlin@50662 91
egahlin@50662 92 static int get_psinfo(psinfo_t* info) {
egahlin@50662 93 return get_psinfo2(info, sizeof(*info), 0);
egahlin@50662 94 }
egahlin@50662 95
egahlin@50662 96 static int get_psinfo(char* file, psinfo_t* info) {
egahlin@50662 97 assert(file != NULL, "file is NULL!");
egahlin@50662 98 assert(info != NULL, "info is NULL!");
egahlin@50662 99 return get_info(file, info, sizeof(*info), 0);
egahlin@50662 100 }
egahlin@50662 101
egahlin@50662 102
egahlin@50662 103 static int get_usage(prusage_t* usage) {
egahlin@50662 104 assert(usage != NULL, "usage is NULL!");
egahlin@50662 105 return get_info("/proc/self/usage", usage, sizeof(*usage), 0);
egahlin@50662 106 }
egahlin@50662 107
egahlin@50662 108 static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
egahlin@50662 109 assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
egahlin@50662 110 assert(load != NULL, "load pointer is NULL!");
egahlin@50662 111 assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
egahlin@50662 112
egahlin@50662 113 if (load->kstat == NULL) {
egahlin@50662 114 // no handle.
egahlin@50662 115 return OS_ERR;
egahlin@50662 116 }
egahlin@50662 117 if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
egahlin@50662 118 // disable handle for this CPU
egahlin@50662 119 load->kstat = NULL;
egahlin@50662 120 return OS_ERR;
egahlin@50662 121 }
egahlin@50662 122 return OS_OK;
egahlin@50662 123 }
egahlin@50662 124
egahlin@50662 125 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
egahlin@50662 126 assert(counters != NULL, "counters pointer is NULL!");
egahlin@50662 127
egahlin@50662 128 cpu_stat_t cpu_stat = {0};
egahlin@50662 129
egahlin@50662 130 if (which_logical_cpu >= counters->nProcs) {
egahlin@50662 131 return .0;
egahlin@50662 132 }
egahlin@50662 133
egahlin@50662 134 CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
egahlin@50662 135 if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
egahlin@50662 136 return .0;
egahlin@50662 137 }
egahlin@50662 138
egahlin@50662 139 uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
egahlin@50662 140 if (usage == NULL) {
egahlin@50662 141 return .0;
egahlin@50662 142 }
egahlin@50662 143
egahlin@50662 144 uint64_t c_idle = usage[CPU_IDLE];
egahlin@50662 145 uint64_t c_total = 0;
egahlin@50662 146
egahlin@50662 147 for (int i = 0; i < CPU_STATES; i++) {
egahlin@50662 148 c_total += usage[i];
egahlin@50662 149 }
egahlin@50662 150
egahlin@50662 151 // Calculate diff against previous snapshot
egahlin@50662 152 uint64_t d_idle = c_idle - load.last_idle;
egahlin@50662 153 uint64_t d_total = c_total - load.last_total;
egahlin@50662 154
egahlin@50662 155 /** update if weve moved */
egahlin@50662 156 if (d_total > 0) {
egahlin@50662 157 // Save current values for next time around
egahlin@50662 158 load.last_idle = c_idle;
egahlin@50662 159 load.last_total = c_total;
egahlin@50662 160 load.last_ratio = (double) (d_total - d_idle) / d_total;
egahlin@50662 161 }
egahlin@50662 162
egahlin@50662 163 return load.last_ratio;
egahlin@50662 164 }
egahlin@50662 165
egahlin@50662 166 static int get_boot_time(uint64_t* time) {
egahlin@50662 167 assert(time != NULL, "time pointer is NULL!");
egahlin@50662 168 setutxent();
egahlin@50662 169 for(;;) {
egahlin@50662 170 struct utmpx* u;
egahlin@50662 171 if ((u = getutxent()) == NULL) {
egahlin@50662 172 break;
egahlin@50662 173 }
egahlin@50662 174 if (u->ut_type == BOOT_TIME) {
egahlin@50662 175 *time = u->ut_xtime;
egahlin@50662 176 endutxent();
egahlin@50662 177 return OS_OK;
egahlin@50662 178 }
egahlin@50662 179 }
egahlin@50662 180 endutxent();
egahlin@50662 181 return OS_ERR;
egahlin@50662 182 }
egahlin@50662 183
egahlin@50662 184 static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
egahlin@50662 185 assert(switches != NULL, "switches pointer is NULL!");
egahlin@50662 186 assert(counters != NULL, "counter pointer is NULL!");
egahlin@50662 187 *switches = 0;
egahlin@50662 188 uint64_t s = 0;
egahlin@50662 189
egahlin@50662 190 // Collect data from all CPUs
egahlin@50662 191 for (int i = 0; i < counters->nProcs; i++) {
egahlin@50662 192 cpu_stat_t cpu_stat = {0};
egahlin@50662 193 CPUPerfTicks load = counters->jvmTicks[i];
egahlin@50662 194
egahlin@50662 195 if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
egahlin@50662 196 s += cpu_stat.cpu_sysinfo.pswitch;
egahlin@50662 197 } else {
egahlin@50662 198 //fail fast...
egahlin@50662 199 return OS_ERR;
egahlin@50662 200 }
egahlin@50662 201 }
egahlin@50662 202 *switches = s;
egahlin@50662 203 return OS_OK;
egahlin@50662 204 }
egahlin@50662 205
egahlin@50662 206 static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
egahlin@50662 207 assert(counters != NULL, "counters is NULL!");
egahlin@50662 208 assert(rate != NULL, "rate pointer is NULL!");
egahlin@50662 209 static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
egahlin@50662 210 static uint64_t lastTime = 0;
egahlin@50662 211 static uint64_t lastSwitches = 0;
egahlin@50662 212 static double lastRate = 0.0;
egahlin@50662 213
egahlin@50662 214 uint64_t lt = 0;
egahlin@50662 215 int res = 0;
egahlin@50662 216
egahlin@50662 217 if (lastTime == 0) {
egahlin@50662 218 uint64_t tmp;
egahlin@50662 219 if (get_boot_time(&tmp) < 0) {
egahlin@50662 220 return OS_ERR;
egahlin@50662 221 }
egahlin@50662 222 lt = tmp * 1000;
egahlin@50662 223 }
egahlin@50662 224
egahlin@50662 225 res = OS_OK;
egahlin@50662 226
egahlin@50662 227 pthread_mutex_lock(&contextSwitchLock);
egahlin@50662 228 {
egahlin@50662 229
egahlin@50662 230 uint64_t sw = 0;
egahlin@50662 231 clock_t t, d;
egahlin@50662 232
egahlin@50662 233 if (lastTime == 0) {
egahlin@50662 234 lastTime = lt;
egahlin@50662 235 }
egahlin@50662 236
egahlin@50662 237 t = clock();
egahlin@50662 238 d = t - lastTime;
egahlin@50662 239
egahlin@50662 240 if (d == 0) {
egahlin@50662 241 *rate = lastRate;
egahlin@50662 242 } else if (get_noof_context_switches(counters, &sw)== OS_OK) {
egahlin@50662 243 *rate = ((double)(sw - lastSwitches) / d) * 1000;
egahlin@50662 244 lastRate = *rate;
egahlin@50662 245 lastSwitches = sw;
egahlin@50662 246 lastTime = t;
egahlin@50662 247 } else {
egahlin@50662 248 *rate = 0.0;
egahlin@50662 249 res = OS_ERR;
egahlin@50662 250 }
egahlin@50662 251 if (*rate < 0.0) {
egahlin@50662 252 *rate = 0.0;
egahlin@50662 253 lastRate = 0.0;
egahlin@50662 254 }
egahlin@50662 255 }
egahlin@50662 256 pthread_mutex_unlock(&contextSwitchLock);
egahlin@50662 257 return res;
egahlin@50662 258 }
egahlin@50662 259
egahlin@50662 260
egahlin@50662 261
egahlin@50662 262 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
egahlin@50662 263 friend class CPUPerformanceInterface;
egahlin@50662 264 private:
egahlin@50662 265 CPUPerfCounters _counters;
egahlin@50662 266 int cpu_load(int which_logical_cpu, double* cpu_load);
egahlin@50662 267 int context_switch_rate(double* rate);
egahlin@50662 268 int cpu_load_total_process(double* cpu_load);
egahlin@50662 269 int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
egahlin@50662 270
egahlin@50662 271 CPUPerformance();
egahlin@50662 272 ~CPUPerformance();
egahlin@50662 273 bool initialize();
egahlin@50662 274 };
egahlin@50662 275
egahlin@50662 276 CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
egahlin@50662 277 _counters.nProcs = 0;
egahlin@50662 278 _counters.jvmTicks = NULL;
egahlin@50662 279 _counters.kstat_ctrl = NULL;
egahlin@50662 280 }
egahlin@50662 281
egahlin@50662 282 bool CPUPerformanceInterface::CPUPerformance::initialize() {
egahlin@50662 283 // initialize kstat control structure,
egahlin@50662 284 _counters.kstat_ctrl = kstat_open();
egahlin@50662 285 assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
egahlin@50662 286
egahlin@50662 287 if (NULL == _counters.kstat_ctrl) {
egahlin@50662 288 return false;
egahlin@50662 289 }
egahlin@50662 290
egahlin@50662 291 // Get number of CPU(s)
egahlin@50662 292 if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
egahlin@50662 293 // ignore error?
egahlin@50662 294 _counters.nProcs = 1;
egahlin@50662 295 }
egahlin@50662 296
egahlin@50662 297 assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
egahlin@50662 298 if (_counters.nProcs == 0) {
egahlin@50662 299 return false;
egahlin@50662 300 }
egahlin@50662 301
egahlin@50662 302 // Data structure(s) for saving CPU load (one per CPU)
egahlin@50662 303 size_t tick_array_size = _counters.nProcs * sizeof(CPUPerfTicks);
egahlin@50662 304 _counters.jvmTicks = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
egahlin@50662 305 if (NULL == _counters.jvmTicks) {
egahlin@50662 306 return false;
egahlin@50662 307 }
egahlin@50662 308 memset(_counters.jvmTicks, 0, tick_array_size);
egahlin@50662 309
egahlin@50662 310 // Get kstat cpu_stat counters for every CPU
egahlin@50662 311 // loop over kstat to find our cpu_stat(s)
egahlin@50662 312 int i = 0;
egahlin@50662 313 for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
egahlin@50662 314 if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
egahlin@50662 315 if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
egahlin@50662 316 continue;
egahlin@50662 317 }
egahlin@50662 318 if (i == _counters.nProcs) {
egahlin@50662 319 // more cpu_stats than reported CPUs
egahlin@50662 320 break;
egahlin@50662 321 }
egahlin@50662 322 _counters.jvmTicks[i++].kstat = kstat;
egahlin@50662 323 }
egahlin@50662 324 }
egahlin@50662 325 return true;
egahlin@50662 326 }
egahlin@50662 327
egahlin@50662 328 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
egahlin@50662 329 if (_counters.jvmTicks != NULL) {
egahlin@50662 330 FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
egahlin@50662 331 }
egahlin@50662 332 if (_counters.kstat_ctrl != NULL) {
egahlin@50662 333 kstat_close(_counters.kstat_ctrl);
egahlin@50662 334 }
egahlin@50662 335 }
egahlin@50662 336
egahlin@50662 337 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
egahlin@50662 338 assert(cpu_load != NULL, "cpu_load pointer is NULL!");
egahlin@50662 339 double t = .0;
egahlin@50662 340 if (-1 == which_logical_cpu) {
egahlin@50662 341 for (int i = 0; i < _counters.nProcs; i++) {
egahlin@50662 342 t += get_cpu_load(i, &_counters);
egahlin@50662 343 }
egahlin@50662 344 // Cap total systemload to 1.0
egahlin@50662 345 t = MIN2<double>((t / _counters.nProcs), 1.0);
egahlin@50662 346 } else {
egahlin@50662 347 t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0);
egahlin@50662 348 }
egahlin@50662 349
egahlin@50662 350 *cpu_load = t;
egahlin@50662 351 return OS_OK;
egahlin@50662 352 }
egahlin@50662 353
egahlin@50662 354 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
egahlin@50662 355 assert(cpu_load != NULL, "cpu_load pointer is NULL!");
egahlin@50662 356
egahlin@50662 357 psinfo_t info;
egahlin@50662 358
egahlin@50662 359 // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
egahlin@50662 360 // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
egahlin@50662 361 if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
egahlin@50662 362 *cpu_load = 0.0;
egahlin@50662 363 return OS_ERR;
egahlin@50662 364 }
egahlin@50662 365 *cpu_load = (double) info.pr_pctcpu / 0x8000;
egahlin@50662 366 return OS_OK;
egahlin@50662 367 }
egahlin@50662 368
egahlin@50662 369 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
egahlin@50662 370 assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
egahlin@50662 371 assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
egahlin@50662 372 assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
egahlin@50662 373
egahlin@50662 374 static uint64_t lastTime;
egahlin@50662 375 static uint64_t lastUser, lastKernel;
egahlin@50662 376 static double lastUserRes, lastKernelRes;
egahlin@50662 377
egahlin@50662 378 pstatus_t pss;
egahlin@50662 379 psinfo_t info;
egahlin@50662 380
egahlin@50662 381 *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
egahlin@50662 382 if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
egahlin@50662 383 return OS_ERR;
egahlin@50662 384 }
egahlin@50662 385
egahlin@50662 386 if (get_psinfo(&info) != 0) {
egahlin@50662 387 return OS_ERR;
egahlin@50662 388 }
egahlin@50662 389
egahlin@50662 390 // get the total time in user, kernel and total time
egahlin@50662 391 // check ratios for 'lately' and multiply the 'recent load'.
egahlin@50662 392 uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
egahlin@50662 393 uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
egahlin@50662 394 uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
egahlin@50662 395 uint64_t diff = time - lastTime;
egahlin@50662 396 double load = (double) info.pr_pctcpu / 0x8000;
egahlin@50662 397
egahlin@50662 398 if (diff > 0) {
egahlin@50662 399 lastUserRes = (load * (user - lastUser)) / diff;
egahlin@50662 400 lastKernelRes = (load * (kernel - lastKernel)) / diff;
egahlin@50662 401
egahlin@50662 402 // BUG9182835 - patch for clamping these values to sane ones.
egahlin@50662 403 lastUserRes = MIN2<double>(1, lastUserRes);
egahlin@50662 404 lastUserRes = MAX2<double>(0, lastUserRes);
egahlin@50662 405 lastKernelRes = MIN2<double>(1, lastKernelRes);
egahlin@50662 406 lastKernelRes = MAX2<double>(0, lastKernelRes);
egahlin@50662 407 }
egahlin@50662 408
egahlin@50662 409 double t = .0;
egahlin@50662 410 cpu_load(-1, &t);
egahlin@50662 411 // clamp at user+system and 1.0
egahlin@50662 412 if (lastUserRes + lastKernelRes > t) {
egahlin@50662 413 t = MIN2<double>(lastUserRes + lastKernelRes, 1.0);
egahlin@50662 414 }
egahlin@50662 415
egahlin@50662 416 *pjvmUserLoad = lastUserRes;
egahlin@50662 417 *pjvmKernelLoad = lastKernelRes;
egahlin@50662 418 *psystemTotalLoad = t;
egahlin@50662 419
egahlin@50662 420 lastTime = time;
egahlin@50662 421 lastUser = user;
egahlin@50662 422 lastKernel = kernel;
egahlin@50662 423
egahlin@50662 424 return OS_OK;
egahlin@50662 425 }
egahlin@50662 426
egahlin@50662 427 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
egahlin@50662 428 return perf_context_switch_rate(&_counters, rate);
egahlin@50662 429 }
egahlin@50662 430
egahlin@50662 431 CPUPerformanceInterface::CPUPerformanceInterface() {
egahlin@50662 432 _impl = NULL;
egahlin@50662 433 }
egahlin@50662 434
egahlin@50662 435 bool CPUPerformanceInterface::initialize() {
egahlin@50662 436 _impl = new CPUPerformanceInterface::CPUPerformance();
egahlin@50662 437 return _impl != NULL && _impl->initialize();
egahlin@50662 438 }
egahlin@50662 439
egahlin@50662 440 CPUPerformanceInterface::~CPUPerformanceInterface(void) {
egahlin@50662 441 if (_impl != NULL) {
egahlin@50662 442 delete _impl;
egahlin@50662 443 }
egahlin@50662 444 }
egahlin@50662 445
egahlin@50662 446 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
egahlin@50662 447 return _impl->cpu_load(which_logical_cpu, cpu_load);
egahlin@50662 448 }
egahlin@50662 449
egahlin@50662 450 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
egahlin@50662 451 return _impl->cpu_load_total_process(cpu_load);
egahlin@50662 452 }
egahlin@50662 453
egahlin@50662 454 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
egahlin@50662 455 return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
egahlin@50662 456 }
egahlin@50662 457
egahlin@50662 458 int CPUPerformanceInterface::context_switch_rate(double* rate) const {
egahlin@50662 459 return _impl->context_switch_rate(rate);
egahlin@50662 460 }
egahlin@50662 461
egahlin@50662 462 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
egahlin@50662 463 friend class SystemProcessInterface;
egahlin@50662 464 private:
egahlin@50662 465 class ProcessIterator : public CHeapObj<mtInternal> {
egahlin@50662 466 friend class SystemProcessInterface::SystemProcesses;
egahlin@50662 467 private:
egahlin@50662 468 DIR* _dir;
egahlin@50662 469 struct dirent* _entry;
egahlin@50662 470 bool _valid;
egahlin@50662 471
egahlin@50662 472 ProcessIterator();
egahlin@50662 473 ~ProcessIterator();
egahlin@50662 474 bool initialize();
egahlin@50662 475
egahlin@50662 476 bool is_valid() const { return _valid; }
egahlin@50662 477 bool is_valid_entry(struct dirent* const entry) const;
egahlin@50662 478 bool is_dir(const char* const name) const;
egahlin@50662 479 char* allocate_string(const char* const str) const;
egahlin@50662 480 int current(SystemProcess* const process_info);
egahlin@50662 481 int next_process();
egahlin@50662 482 };
egahlin@50662 483
egahlin@50662 484 ProcessIterator* _iterator;
egahlin@50662 485 SystemProcesses();
egahlin@50662 486 bool initialize();
egahlin@50662 487 ~SystemProcesses();
egahlin@50662 488
egahlin@50662 489 //information about system processes
egahlin@50662 490 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
egahlin@50662 491 };
egahlin@50662 492
egahlin@50662 493 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
egahlin@50662 494 struct stat64 mystat;
egahlin@50662 495 int ret_val = 0;
egahlin@50662 496
egahlin@50662 497 ret_val = ::stat64(name, &mystat);
egahlin@50662 498
egahlin@50662 499 if (ret_val < 0) {
egahlin@50662 500 return false;
egahlin@50662 501 }
egahlin@50662 502 ret_val = S_ISDIR(mystat.st_mode);
egahlin@50662 503 return ret_val > 0;
egahlin@50662 504 }
egahlin@50662 505
egahlin@50662 506 // if it has a numeric name, is a directory and has a 'psinfo' file in it
egahlin@50662 507 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
egahlin@50662 508 // ignore the "." and ".." directories
egahlin@50662 509 if ((strcmp(entry->d_name, ".") == 0) ||
egahlin@50662 510 (strcmp(entry->d_name, "..") == 0)) {
egahlin@50662 511 return false;
egahlin@50662 512 }
egahlin@50662 513
egahlin@50662 514 char buffer[PATH_MAX] = {0};
egahlin@50662 515 uint64_t size = 0;
egahlin@50662 516 bool result = false;
egahlin@50662 517 FILE *fp = NULL;
egahlin@50662 518
egahlin@50662 519 if (atoi(entry->d_name) != 0) {
egahlin@50662 520 jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
egahlin@50662 521
egahlin@50662 522 if (is_dir(buffer)) {
egahlin@50662 523 memset(buffer, 0, PATH_MAX);
egahlin@50662 524 jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
egahlin@50662 525 if ((fp = fopen(buffer, "r")) != NULL) {
egahlin@50662 526 int nread = 0;
egahlin@50662 527 psinfo_t psinfo_data;
egahlin@50662 528 if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
egahlin@50662 529 // only considering system process owned by root
egahlin@50662 530 if (psinfo_data.pr_uid == 0) {
egahlin@50662 531 result = true;
egahlin@50662 532 }
egahlin@50662 533 }
egahlin@50662 534 }
egahlin@50662 535 }
egahlin@50662 536 }
egahlin@50662 537
egahlin@50662 538 if (fp != NULL) {
egahlin@50662 539 fclose(fp);
egahlin@50662 540 }
egahlin@50662 541
egahlin@50662 542 return result;
egahlin@50662 543 }
egahlin@50662 544
egahlin@50662 545 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
egahlin@50662 546 if (str != NULL) {
egahlin@50662 547 size_t len = strlen(str);
egahlin@50662 548 char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
egahlin@50662 549 strncpy(tmp, str, len);
egahlin@50662 550 tmp[len] = '\0';
egahlin@50662 551 return tmp;
egahlin@50662 552 }
egahlin@50662 553 return NULL;
egahlin@50662 554 }
egahlin@50662 555
egahlin@50662 556 int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
egahlin@50662 557 if (!is_valid()) {
egahlin@50662 558 return OS_ERR;
egahlin@50662 559 }
egahlin@50662 560
egahlin@50662 561 char psinfo_path[PATH_MAX] = {0};
egahlin@50662 562 jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
egahlin@50662 563
egahlin@50662 564 FILE *fp = NULL;
egahlin@50662 565 if ((fp = fopen(psinfo_path, "r")) == NULL) {
egahlin@50662 566 return OS_ERR;
egahlin@50662 567 }
egahlin@50662 568
egahlin@50662 569 int nread = 0;
egahlin@50662 570 psinfo_t psinfo_data;
egahlin@50662 571 if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
egahlin@50662 572 fclose(fp);
egahlin@50662 573 return OS_ERR;
egahlin@50662 574 }
egahlin@50662 575
egahlin@50662 576 char *exe_path = NULL;
egahlin@50662 577 if ((psinfo_data.pr_fname != NULL) &&
egahlin@50662 578 (psinfo_data.pr_psargs != NULL)) {
egahlin@50662 579 char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
egahlin@50662 580 if (path_substring != NULL) {
egahlin@50662 581 int len = path_substring - psinfo_data.pr_psargs;
egahlin@50662 582 exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
egahlin@50662 583 if (exe_path != NULL) {
egahlin@50662 584 jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
egahlin@50662 585 exe_path[len] = '\0';
egahlin@50662 586 }
egahlin@50662 587 }
egahlin@50662 588 }
egahlin@50662 589
egahlin@50662 590 process_info->set_pid(atoi(_entry->d_name));
egahlin@50662 591 process_info->set_name(allocate_string(psinfo_data.pr_fname));
egahlin@50662 592 process_info->set_path(allocate_string(exe_path));
egahlin@50662 593 process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
egahlin@50662 594
egahlin@50662 595 if (exe_path != NULL) {
egahlin@50662 596 FREE_C_HEAP_ARRAY(char, exe_path);
egahlin@50662 597 }
egahlin@50662 598
egahlin@50662 599 if (fp != NULL) {
egahlin@50662 600 fclose(fp);
egahlin@50662 601 }
egahlin@50662 602
egahlin@50662 603 return OS_OK;
egahlin@50662 604 }
egahlin@50662 605
egahlin@50662 606 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
egahlin@50662 607 struct dirent* entry;
egahlin@50662 608
egahlin@50662 609 if (!is_valid()) {
egahlin@50662 610 return OS_ERR;
egahlin@50662 611 }
egahlin@50662 612
egahlin@50662 613 do {
egahlin@50662 614 if ((entry = os::readdir(_dir, _entry)) == NULL) {
egahlin@50662 615 // error
egahlin@50662 616 _valid = false;
egahlin@50662 617 return OS_ERR;
egahlin@50662 618 }
egahlin@50662 619 } while(!is_valid_entry(_entry));
egahlin@50662 620
egahlin@50662 621 _valid = true;
egahlin@50662 622 return OS_OK;
egahlin@50662 623 }
egahlin@50662 624
egahlin@50662 625 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
egahlin@50662 626 _dir = NULL;
egahlin@50662 627 _entry = NULL;
egahlin@50662 628 _valid = false;
egahlin@50662 629 }
egahlin@50662 630
egahlin@50662 631 bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
egahlin@50662 632 _dir = opendir("/proc");
egahlin@50662 633 _entry = (struct dirent*)NEW_C_HEAP_ARRAY(char, sizeof(struct dirent) + _PC_NAME_MAX + 1, mtInternal);
egahlin@50662 634 if (NULL == _entry) {
egahlin@50662 635 return false;
egahlin@50662 636 }
egahlin@50662 637 _valid = true;
egahlin@50662 638 next_process();
egahlin@50662 639
egahlin@50662 640 return true;
egahlin@50662 641 }
egahlin@50662 642
egahlin@50662 643 SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
egahlin@50662 644 if (_entry != NULL) {
egahlin@50662 645 FREE_C_HEAP_ARRAY(char, _entry);
egahlin@50662 646 }
egahlin@50662 647
egahlin@50662 648 if (_dir != NULL) {
egahlin@50662 649 closedir(_dir);
egahlin@50662 650 }
egahlin@50662 651 }
egahlin@50662 652
egahlin@50662 653 SystemProcessInterface::SystemProcesses::SystemProcesses() {
egahlin@50662 654 _iterator = NULL;
egahlin@50662 655 }
egahlin@50662 656
egahlin@50662 657 bool SystemProcessInterface::SystemProcesses::initialize() {
egahlin@50662 658 _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
egahlin@50662 659 return _iterator != NULL && _iterator->initialize();
egahlin@50662 660 }
egahlin@50662 661
egahlin@50662 662 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
egahlin@50662 663 if (_iterator != NULL) {
egahlin@50662 664 delete _iterator;
egahlin@50662 665 }
egahlin@50662 666 }
egahlin@50662 667
egahlin@50662 668 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
egahlin@50662 669 assert(system_processes != NULL, "system_processes pointer is NULL!");
egahlin@50662 670 assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
egahlin@50662 671 assert(_iterator != NULL, "iterator is NULL!");
egahlin@50662 672
egahlin@50662 673 // initialize pointers
egahlin@50662 674 *no_of_sys_processes = 0;
egahlin@50662 675 *system_processes = NULL;
egahlin@50662 676
egahlin@50662 677 while (_iterator->is_valid()) {
egahlin@50662 678 SystemProcess* tmp = new SystemProcess();
egahlin@50662 679 _iterator->current(tmp);
egahlin@50662 680
egahlin@50662 681 //if already existing head
egahlin@50662 682 if (*system_processes != NULL) {
egahlin@50662 683 //move "first to second"
egahlin@50662 684 tmp->set_next(*system_processes);
egahlin@50662 685 }
egahlin@50662 686 // new head
egahlin@50662 687 *system_processes = tmp;
egahlin@50662 688 // increment
egahlin@50662 689 (*no_of_sys_processes)++;
egahlin@50662 690 // step forward
egahlin@50662 691 _iterator->next_process();
egahlin@50662 692 }
egahlin@50662 693 return OS_OK;
egahlin@50662 694 }
egahlin@50662 695
egahlin@50662 696 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
egahlin@50662 697 return _impl->system_processes(system_procs, no_of_sys_processes);
egahlin@50662 698 }
egahlin@50662 699
egahlin@50662 700 SystemProcessInterface::SystemProcessInterface() {
egahlin@50662 701 _impl = NULL;
egahlin@50662 702 }
egahlin@50662 703
egahlin@50662 704 bool SystemProcessInterface::initialize() {
egahlin@50662 705 _impl = new SystemProcessInterface::SystemProcesses();
egahlin@50662 706 return _impl != NULL && _impl->initialize();
egahlin@50662 707
egahlin@50662 708 }
egahlin@50662 709
egahlin@50662 710 SystemProcessInterface::~SystemProcessInterface() {
egahlin@50662 711 if (_impl != NULL) {
egahlin@50662 712 delete _impl;
egahlin@50662 713 }
egahlin@50662 714 }
egahlin@50662 715
egahlin@50662 716 CPUInformationInterface::CPUInformationInterface() {
egahlin@50662 717 _cpu_info = NULL;
egahlin@50662 718 }
egahlin@50662 719
egahlin@50662 720 bool CPUInformationInterface::initialize() {
egahlin@50662 721 _cpu_info = new CPUInformation();
egahlin@50662 722 if (_cpu_info == NULL) {
egahlin@50662 723 return false;
egahlin@50662 724 }
egahlin@50662 725 _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
egahlin@50662 726 _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
egahlin@50662 727 _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
egahlin@50662 728 _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
egahlin@50662 729 _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
egahlin@50662 730 return true;
egahlin@50662 731 }
egahlin@50662 732
egahlin@50662 733 CPUInformationInterface::~CPUInformationInterface() {
egahlin@50662 734 if (_cpu_info != NULL) {
egahlin@50662 735 if (_cpu_info->cpu_name() != NULL) {
egahlin@50662 736 const char* cpu_name = _cpu_info->cpu_name();
egahlin@50662 737 FREE_C_HEAP_ARRAY(char, cpu_name);
egahlin@50662 738 _cpu_info->set_cpu_name(NULL);
egahlin@50662 739 }
egahlin@50662 740 if (_cpu_info->cpu_description() != NULL) {
egahlin@50662 741 const char* cpu_desc = _cpu_info->cpu_description();
egahlin@50662 742 FREE_C_HEAP_ARRAY(char, cpu_desc);
egahlin@50662 743 _cpu_info->set_cpu_description(NULL);
egahlin@50662 744 }
egahlin@50662 745 delete _cpu_info;
egahlin@50662 746 }
egahlin@50662 747 }
egahlin@50662 748
egahlin@50662 749 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
egahlin@50662 750 if (_cpu_info == NULL) {
egahlin@50662 751 return OS_ERR;
egahlin@50662 752 }
egahlin@50662 753
egahlin@50662 754 cpu_info = *_cpu_info; // shallow copy assignment
egahlin@50662 755 return OS_OK;
egahlin@50662 756 }
rwestberg@51513 757
rwestberg@51513 758 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
rwestberg@51513 759 friend class NetworkPerformanceInterface;
rwestberg@51513 760 private:
rwestberg@51513 761 NetworkPerformance();
rwestberg@51513 762 NetworkPerformance(const NetworkPerformance& rhs); // no impl
rwestberg@51513 763 NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
rwestberg@51513 764 bool initialize();
rwestberg@51513 765 ~NetworkPerformance();
rwestberg@51513 766 int network_utilization(NetworkInterface** network_interfaces) const;
rwestberg@51513 767 };
rwestberg@51513 768
rwestberg@51513 769 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
rwestberg@51513 770
rwestberg@51513 771 }
rwestberg@51513 772
rwestberg@51513 773 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
rwestberg@51513 774 return true;
rwestberg@51513 775 }
rwestberg@51513 776
rwestberg@51513 777 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
rwestberg@51513 778
rwestberg@51513 779 }
rwestberg@51513 780
rwestberg@51513 781 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
rwestberg@51513 782 {
rwestberg@51513 783 kstat_ctl_t* ctl = kstat_open();
rwestberg@51513 784 if (ctl == NULL) {
rwestberg@51513 785 return OS_ERR;
rwestberg@51513 786 }
rwestberg@51513 787
rwestberg@51513 788 NetworkInterface* ret = NULL;
rwestberg@51513 789 for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) {
rwestberg@51513 790 if (strcmp(k->ks_class, "net") != 0) {
rwestberg@51513 791 continue;
rwestberg@51513 792 }
rwestberg@51513 793 if (strcmp(k->ks_module, "link") != 0) {
rwestberg@51513 794 continue;
rwestberg@51513 795 }
rwestberg@51513 796
rwestberg@51513 797 if (kstat_read(ctl, k, NULL) == -1) {
rwestberg@51513 798 return OS_ERR;
rwestberg@51513 799 }
rwestberg@51513 800
rwestberg@51513 801 uint64_t bytes_in = UINT64_MAX;
rwestberg@51513 802 uint64_t bytes_out = UINT64_MAX;
rwestberg@51513 803 for (int i = 0; i < k->ks_ndata; ++i) {
rwestberg@51513 804 kstat_named_t* data = &reinterpret_cast<kstat_named_t*>(k->ks_data)[i];
rwestberg@51513 805 if (strcmp(data->name, "rbytes64") == 0) {
rwestberg@51513 806 bytes_in = data->value.ui64;
rwestberg@51513 807 }
rwestberg@51513 808 else if (strcmp(data->name, "obytes64") == 0) {
rwestberg@51513 809 bytes_out = data->value.ui64;
rwestberg@51513 810 }
rwestberg@51513 811 }
rwestberg@51513 812
rwestberg@51513 813 if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) {
rwestberg@51513 814 NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret);
rwestberg@51513 815 ret = cur;
rwestberg@51513 816 }
rwestberg@51513 817 }
rwestberg@51513 818
rwestberg@51513 819 *network_interfaces = ret;
rwestberg@51513 820
rwestberg@51513 821 return OS_OK;
rwestberg@51513 822 }
rwestberg@51513 823
rwestberg@51513 824 NetworkPerformanceInterface::NetworkPerformanceInterface() {
rwestberg@51513 825 _impl = NULL;
rwestberg@51513 826 }
rwestberg@51513 827
rwestberg@51513 828 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
rwestberg@51513 829 if (_impl != NULL) {
rwestberg@51513 830 delete _impl;
rwestberg@51513 831 }
rwestberg@51513 832 }
rwestberg@51513 833
rwestberg@51513 834 bool NetworkPerformanceInterface::initialize() {
rwestberg@51513 835 _impl = new NetworkPerformanceInterface::NetworkPerformance();
rwestberg@51513 836 return _impl != NULL && _impl->initialize();
rwestberg@51513 837 }
rwestberg@51513 838
rwestberg@51513 839 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
rwestberg@51513 840 return _impl->network_utilization(network_interfaces);
rwestberg@51513 841 }