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