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