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 #include "precompiled.hpp" 25 #include "memory/allocation.inline.hpp" 26 #include "memory/resourceArea.hpp" 27 #include "runtime/os.hpp" 28 #include "runtime/os_perf.hpp" 29 #include "utilities/macros.hpp" 30 #include CPU_HEADER(vm_version_ext) 31 32 #ifdef __APPLE__ 33 #import <libproc.h> 34 #include <sys/time.h> 35 #include <sys/sysctl.h> 36 #include <mach/mach.h> 37 #include <mach/task_info.h> 38 #include <sys/socket.h> 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 #include <net/route.h> 42 #endif 43 44 static const double NANOS_PER_SEC = 1000000000.0; 45 46 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> { 47 friend class CPUPerformanceInterface; 48 private: 49 long _total_cpu_nanos; 50 long _total_csr_nanos; 51 long _jvm_user_nanos; 52 long _jvm_system_nanos; 53 long _jvm_context_switches; 54 long _used_ticks; 55 long _total_ticks; 56 int _active_processor_count; 57 58 bool now_in_nanos(long* resultp) { 59 timeval current_time; 60 if (gettimeofday(¤t_time, NULL) != 0) { 61 // Error getting current time 62 return false; 63 } 64 *resultp = current_time.tv_sec * NANOS_PER_SEC + 1000L * current_time.tv_usec; 65 return true; 66 } 67 68 double normalize(double value) { 69 return MIN2<double>(MAX2<double>(value, 0.0), 1.0); 70 } 71 int cpu_load(int which_logical_cpu, double* cpu_load); 72 int context_switch_rate(double* rate); 73 int cpu_load_total_process(double* cpu_load); 74 int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); 75 76 NONCOPYABLE(CPUPerformance); 77 78 public: 79 CPUPerformance(); 80 bool initialize(); 81 ~CPUPerformance(); 82 }; 83 84 CPUPerformanceInterface::CPUPerformance::CPUPerformance() { 85 _total_cpu_nanos= 0; 86 _total_csr_nanos= 0; 87 _jvm_context_switches = 0; 88 _jvm_user_nanos = 0; 89 _jvm_system_nanos = 0; 90 _used_ticks = 0; 91 _total_ticks = 0; 92 _active_processor_count = 0; 93 } 94 95 bool CPUPerformanceInterface::CPUPerformance::initialize() { 96 return true; 97 } 98 99 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { 100 } 101 102 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { 103 return FUNCTIONALITY_NOT_IMPLEMENTED; 104 } 105 106 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { 107 #ifdef __APPLE__ 108 host_name_port_t host = mach_host_self(); 109 host_flavor_t flavor = HOST_CPU_LOAD_INFO; 110 mach_msg_type_number_t host_info_count = HOST_CPU_LOAD_INFO_COUNT; 111 host_cpu_load_info_data_t cpu_load_info; 112 113 kern_return_t kr = host_statistics(host, flavor, (host_info_t)&cpu_load_info, &host_info_count); 114 if (kr != KERN_SUCCESS) { 115 return OS_ERR; 116 } 117 118 long used_ticks = cpu_load_info.cpu_ticks[CPU_STATE_USER] + cpu_load_info.cpu_ticks[CPU_STATE_NICE] + cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM]; 119 long total_ticks = used_ticks + cpu_load_info.cpu_ticks[CPU_STATE_IDLE]; 120 121 if (_used_ticks == 0 || _total_ticks == 0) { 122 // First call, just set the values 123 _used_ticks = used_ticks; 124 _total_ticks = total_ticks; 125 return OS_ERR; 126 } 127 128 long used_delta = used_ticks - _used_ticks; 129 long total_delta = total_ticks - _total_ticks; 130 131 _used_ticks = used_ticks; 132 _total_ticks = total_ticks; 133 134 if (total_delta == 0) { 135 // Avoid division by zero 136 return OS_ERR; 137 } 138 139 *cpu_load = (double)used_delta / total_delta; 140 141 return OS_OK; 142 #else 143 return FUNCTIONALITY_NOT_IMPLEMENTED; 144 #endif 145 } 146 147 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { 148 #ifdef __APPLE__ 149 int result = cpu_load_total_process(psystemTotalLoad); 150 mach_port_t task = mach_task_self(); 151 mach_msg_type_number_t task_info_count = TASK_INFO_MAX; 152 task_info_data_t task_info_data; 153 kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count); 154 if (kr != KERN_SUCCESS) { 155 return OS_ERR; 156 } 157 task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data; 158 159 int active_processor_count = os::active_processor_count(); 160 long jvm_user_nanos = absolutetime_info->total_user; 161 long jvm_system_nanos = absolutetime_info->total_system; 162 163 long total_cpu_nanos; 164 if(!now_in_nanos(&total_cpu_nanos)) { 165 return OS_ERR; 166 } 167 168 if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) { 169 // First call or change in active processor count 170 result = OS_ERR; 171 } 172 173 long delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos); 174 if (delta_nanos == 0) { 175 // Avoid division by zero 176 return OS_ERR; 177 } 178 179 *pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos); 180 *pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos); 181 182 _active_processor_count = active_processor_count; 183 _total_cpu_nanos = total_cpu_nanos; 184 _jvm_user_nanos = jvm_user_nanos; 185 _jvm_system_nanos = jvm_system_nanos; 186 187 return result; 188 #else 189 return FUNCTIONALITY_NOT_IMPLEMENTED; 190 #endif 191 } 192 193 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { 194 #ifdef __APPLE__ 195 mach_port_t task = mach_task_self(); 196 mach_msg_type_number_t task_info_count = TASK_INFO_MAX; 197 task_info_data_t task_info_data; 198 kern_return_t kr = task_info(task, TASK_EVENTS_INFO, (task_info_t)task_info_data, &task_info_count); 199 if (kr != KERN_SUCCESS) { 200 return OS_ERR; 201 } 202 203 int result = OS_OK; 204 if (_total_csr_nanos == 0 || _jvm_context_switches == 0) { 205 // First call just set initial values. 206 result = OS_ERR; 207 } 208 209 long jvm_context_switches = ((task_events_info_t)task_info_data)->csw; 210 211 long total_csr_nanos; 212 if(!now_in_nanos(&total_csr_nanos)) { 213 return OS_ERR; 214 } 215 double delta_in_sec = (double)(total_csr_nanos - _total_csr_nanos) / NANOS_PER_SEC; 216 if (delta_in_sec == 0.0) { 217 // Avoid division by zero 218 return OS_ERR; 219 } 220 221 *rate = (jvm_context_switches - _jvm_context_switches) / delta_in_sec; 222 223 _jvm_context_switches = jvm_context_switches; 224 _total_csr_nanos = total_csr_nanos; 225 226 return result; 227 #else 228 return FUNCTIONALITY_NOT_IMPLEMENTED; 229 #endif 230 } 231 232 CPUPerformanceInterface::CPUPerformanceInterface() { 233 _impl = NULL; 234 } 235 236 bool CPUPerformanceInterface::initialize() { 237 _impl = new CPUPerformanceInterface::CPUPerformance(); 238 return _impl->initialize(); 239 } 240 241 CPUPerformanceInterface::~CPUPerformanceInterface() { 242 if (_impl != NULL) { 243 delete _impl; 244 } 245 } 246 247 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { 248 return _impl->cpu_load(which_logical_cpu, cpu_load); 249 } 250 251 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { 252 return _impl->cpu_load_total_process(cpu_load); 253 } 254 255 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { 256 return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); 257 } 258 259 int CPUPerformanceInterface::context_switch_rate(double* rate) const { 260 return _impl->context_switch_rate(rate); 261 } 262 263 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> { 264 friend class SystemProcessInterface; 265 private: 266 SystemProcesses(); 267 bool initialize(); 268 NONCOPYABLE(SystemProcesses); 269 ~SystemProcesses(); 270 271 //information about system processes 272 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; 273 }; 274 275 SystemProcessInterface::SystemProcesses::SystemProcesses() { 276 } 277 278 bool SystemProcessInterface::SystemProcesses::initialize() { 279 return true; 280 } 281 282 SystemProcessInterface::SystemProcesses::~SystemProcesses() { 283 } 284 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { 285 assert(system_processes != NULL, "system_processes pointer is NULL!"); 286 assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!"); 287 #ifdef __APPLE__ 288 pid_t* pids = NULL; 289 int pid_count = 0; 290 ResourceMark rm; 291 292 int try_count = 0; 293 while (pids == NULL) { 294 // Find out buffer size 295 size_t pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); 296 if (pids_bytes <= 0) { 297 return OS_ERR; 298 } 299 pid_count = pids_bytes / sizeof(pid_t); 300 pids = NEW_RESOURCE_ARRAY(pid_t, pid_count); 301 memset(pids, 0, pids_bytes); 302 303 pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes); 304 if (pids_bytes <= 0) { 305 // couldn't fit buffer, retry. 306 FREE_RESOURCE_ARRAY(pid_t, pids, pid_count); 307 pids = NULL; 308 try_count++; 309 if (try_count > 3) { 310 return OS_ERR; 311 } 312 } else { 313 pid_count = pids_bytes / sizeof(pid_t); 314 } 315 } 316 317 int process_count = 0; 318 SystemProcess* next = NULL; 319 for (int i = 0; i < pid_count; i++) { 320 pid_t pid = pids[i]; 321 if (pid != 0) { 322 char buffer[PROC_PIDPATHINFO_MAXSIZE]; 323 memset(buffer, 0 , sizeof(buffer)); 324 if (proc_pidpath(pid, buffer, sizeof(buffer)) != -1) { 325 int length = strlen(buffer); 326 if (length > 0) { 327 SystemProcess* current = new SystemProcess(); 328 char * path = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal); 329 strcpy(path, buffer); 330 current->set_path(path); 331 current->set_pid((int)pid); 332 current->set_next(next); 333 next = current; 334 process_count++; 335 } 336 } 337 } 338 } 339 340 *no_of_sys_processes = process_count; 341 *system_processes = next; 342 343 return OS_OK; 344 #endif 345 return FUNCTIONALITY_NOT_IMPLEMENTED; 346 } 347 348 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const { 349 return _impl->system_processes(system_procs, no_of_sys_processes); 350 } 351 352 SystemProcessInterface::SystemProcessInterface() { 353 _impl = NULL; 354 } 355 356 bool SystemProcessInterface::initialize() { 357 _impl = new SystemProcessInterface::SystemProcesses(); 358 return _impl->initialize(); 359 } 360 361 SystemProcessInterface::~SystemProcessInterface() { 362 if (_impl != NULL) { 363 delete _impl; 364 } 365 } 366 367 CPUInformationInterface::CPUInformationInterface() { 368 _cpu_info = NULL; 369 } 370 371 bool CPUInformationInterface::initialize() { 372 _cpu_info = new CPUInformation(); 373 _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); 374 _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); 375 _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); 376 _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); 377 _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); 378 return true; 379 } 380 381 CPUInformationInterface::~CPUInformationInterface() { 382 if (_cpu_info != NULL) { 383 if (_cpu_info->cpu_name() != NULL) { 384 const char* cpu_name = _cpu_info->cpu_name(); 385 FREE_C_HEAP_ARRAY(char, cpu_name); 386 _cpu_info->set_cpu_name(NULL); 387 } 388 if (_cpu_info->cpu_description() != NULL) { 389 const char* cpu_desc = _cpu_info->cpu_description(); 390 FREE_C_HEAP_ARRAY(char, cpu_desc); 391 _cpu_info->set_cpu_description(NULL); 392 } 393 delete _cpu_info; 394 } 395 } 396 397 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { 398 if (NULL == _cpu_info) { 399 return OS_ERR; 400 } 401 402 cpu_info = *_cpu_info; // shallow copy assignment 403 return OS_OK; 404 } 405 406 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> { 407 friend class NetworkPerformanceInterface; 408 private: 409 NetworkPerformance(); 410 NONCOPYABLE(NetworkPerformance); 411 bool initialize(); 412 ~NetworkPerformance(); 413 int network_utilization(NetworkInterface** network_interfaces) const; 414 }; 415 416 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { 417 } 418 419 bool NetworkPerformanceInterface::NetworkPerformance::initialize() { 420 return true; 421 } 422 423 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { 424 } 425 426 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { 427 size_t len; 428 int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0}; 429 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) { 430 return OS_ERR; 431 } 432 uint8_t* buf = NEW_RESOURCE_ARRAY(uint8_t, len); 433 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &len, NULL, 0) != 0) { 434 return OS_ERR; 435 } 436 437 size_t index = 0; 438 NetworkInterface* ret = NULL; 439 while (index < len) { 440 if_msghdr* msghdr = reinterpret_cast<if_msghdr*>(buf + index); 441 index += msghdr->ifm_msglen; 442 443 if (msghdr->ifm_type != RTM_IFINFO2) { 444 continue; 445 } 446 447 if_msghdr2* msghdr2 = reinterpret_cast<if_msghdr2*>(msghdr); 448 sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr2 + 1); 449 450 // The interface name is not necessarily NUL-terminated 451 char name_buf[128]; 452 size_t name_len = MIN2(sizeof(name_buf) - 1, static_cast<size_t>(sockaddr->sdl_nlen)); 453 strncpy(name_buf, sockaddr->sdl_data, name_len); 454 name_buf[name_len] = '\0'; 455 456 uint64_t bytes_in = msghdr2->ifm_data.ifi_ibytes; 457 uint64_t bytes_out = msghdr2->ifm_data.ifi_obytes; 458 459 NetworkInterface* cur = new NetworkInterface(name_buf, bytes_in, bytes_out, ret); 460 ret = cur; 461 } 462 463 *network_interfaces = ret; 464 465 return OS_OK; 466 } 467 468 NetworkPerformanceInterface::NetworkPerformanceInterface() { 469 _impl = NULL; 470 } 471 472 NetworkPerformanceInterface::~NetworkPerformanceInterface() { 473 if (_impl != NULL) { 474 delete _impl; 475 } 476 } 477 478 bool NetworkPerformanceInterface::initialize() { 479 _impl = new NetworkPerformanceInterface::NetworkPerformance(); 480 return _impl->initialize(); 481 } 482 483 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { 484 return _impl->network_utilization(network_interfaces); 485 }