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