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 CPU_HEADER(vm_version_ext) 30 31 #ifdef __APPLE__ 32 #import <libproc.h> 33 #include <sys/time.h> 34 #include <sys/sysctl.h> 35 #include <mach/mach.h> 36 #include <mach/task_info.h> 37 #include <sys/socket.h> 38 #include <net/if.h> 39 #include <net/if_dl.h> 40 #include <net/route.h> 41 #endif 42 43 static const double NANOS_PER_SEC = 1000000000.0; 44 45 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> { 46 friend class CPUPerformanceInterface; 47 private: 48 long _total_cpu_nanos; 49 long _total_csr_nanos; 50 long _jvm_user_nanos; 51 long _jvm_system_nanos; 52 long _jvm_context_switches; 53 long _used_ticks; 54 long _total_ticks; 55 int _active_processor_count; 56 57 bool now_in_nanos(long* resultp) { 58 timeval current_time; 59 if (gettimeofday(¤t_time, NULL) != 0) { 60 // Error getting current time 61 return false; 62 } 63 *resultp = current_time.tv_sec * NANOS_PER_SEC + 1000L * current_time.tv_usec; 64 return true; 65 } 66 67 double normalize(double value) { 68 return MIN2<double>(MAX2<double>(value, 0.0), 1.0); 69 } 70 int cpu_load(int which_logical_cpu, double* cpu_load); 71 int context_switch_rate(double* rate); 72 int cpu_load_total_process(double* cpu_load); 73 int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); 74 75 CPUPerformance(const CPUPerformance& rhs); // no impl 76 CPUPerformance& operator=(const CPUPerformance& rhs); // no impl 77 public: 78 CPUPerformance(); 79 bool initialize(); 80 ~CPUPerformance(); 81 }; 82 83 CPUPerformanceInterface::CPUPerformance::CPUPerformance() { 84 _total_cpu_nanos= 0; 85 _total_csr_nanos= 0; 86 _jvm_context_switches = 0; 87 _jvm_user_nanos = 0; 88 _jvm_system_nanos = 0; 89 _used_ticks = 0; 90 _total_ticks = 0; 91 _active_processor_count = 0; 92 } 93 94 bool CPUPerformanceInterface::CPUPerformance::initialize() { 95 return true; 96 } 97 98 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { 99 } 100 101 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { 102 return FUNCTIONALITY_NOT_IMPLEMENTED; 103 } 104 105 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { 106 #ifdef __APPLE__ 107 host_name_port_t host = mach_host_self(); 108 host_flavor_t flavor = HOST_CPU_LOAD_INFO; 109 mach_msg_type_number_t host_info_count = HOST_CPU_LOAD_INFO_COUNT; 110 host_cpu_load_info_data_t cpu_load_info; 111 112 kern_return_t kr = host_statistics(host, flavor, (host_info_t)&cpu_load_info, &host_info_count); 113 if (kr != KERN_SUCCESS) { 114 return OS_ERR; 115 } 116 117 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]; 118 long total_ticks = used_ticks + cpu_load_info.cpu_ticks[CPU_STATE_IDLE]; 119 120 if (_used_ticks == 0 || _total_ticks == 0) { 121 // First call, just set the values 122 _used_ticks = used_ticks; 123 _total_ticks = total_ticks; 124 return OS_ERR; 125 } 126 127 long used_delta = used_ticks - _used_ticks; 128 long total_delta = total_ticks - _total_ticks; 129 130 _used_ticks = used_ticks; 131 _total_ticks = total_ticks; 132 133 if (total_delta == 0) { 134 // Avoid division by zero 135 return OS_ERR; 136 } 137 138 *cpu_load = (double)used_delta / total_delta; 139 140 return OS_OK; 141 #else 142 return FUNCTIONALITY_NOT_IMPLEMENTED; 143 #endif 144 } 145 146 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { 147 #ifdef __APPLE__ 148 int result = cpu_load_total_process(psystemTotalLoad); 149 mach_port_t task = mach_task_self(); 150 mach_msg_type_number_t task_info_count = TASK_INFO_MAX; 151 task_info_data_t task_info_data; 152 kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count); 153 if (kr != KERN_SUCCESS) { 154 return OS_ERR; 155 } 156 task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data; 157 158 int active_processor_count = os::active_processor_count(); 159 long jvm_user_nanos = absolutetime_info->total_user; 160 long jvm_system_nanos = absolutetime_info->total_system; 161 162 long total_cpu_nanos; 163 if(!now_in_nanos(&total_cpu_nanos)) { 164 return OS_ERR; 165 } 166 167 if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) { 168 // First call or change in active processor count 169 result = OS_ERR; 170 } 171 172 long delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos); 173 if (delta_nanos == 0) { 174 // Avoid division by zero 175 return OS_ERR; 176 } 177 178 *pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos); 179 *pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos); 180 181 _active_processor_count = active_processor_count; 182 _total_cpu_nanos = total_cpu_nanos; 183 _jvm_user_nanos = jvm_user_nanos; 184 _jvm_system_nanos = jvm_system_nanos; 185 186 return result; 187 #else 188 return FUNCTIONALITY_NOT_IMPLEMENTED; 189 #endif 190 } 191 192 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { 193 #ifdef __APPLE__ 194 mach_port_t task = mach_task_self(); 195 mach_msg_type_number_t task_info_count = TASK_INFO_MAX; 196 task_info_data_t task_info_data; 197 kern_return_t kr = task_info(task, TASK_EVENTS_INFO, (task_info_t)task_info_data, &task_info_count); 198 if (kr != KERN_SUCCESS) { 199 return OS_ERR; 200 } 201 202 int result = OS_OK; 203 if (_total_csr_nanos == 0 || _jvm_context_switches == 0) { 204 // First call just set initial values. 205 result = OS_ERR; 206 } 207 208 long jvm_context_switches = ((task_events_info_t)task_info_data)->csw; 209 210 long total_csr_nanos; 211 if(!now_in_nanos(&total_csr_nanos)) { 212 return OS_ERR; 213 } 214 double delta_in_sec = (double)(total_csr_nanos - _total_csr_nanos) / NANOS_PER_SEC; 215 if (delta_in_sec == 0.0) { 216 // Avoid division by zero 217 return OS_ERR; 218 } 219 220 *rate = (jvm_context_switches - _jvm_context_switches) / delta_in_sec; 221 222 _jvm_context_switches = jvm_context_switches; 223 _total_csr_nanos = total_csr_nanos; 224 225 return result; 226 #else 227 return FUNCTIONALITY_NOT_IMPLEMENTED; 228 #endif 229 } 230 231 CPUPerformanceInterface::CPUPerformanceInterface() { 232 _impl = NULL; 233 } 234 235 bool CPUPerformanceInterface::initialize() { 236 _impl = new CPUPerformanceInterface::CPUPerformance(); 237 return _impl->initialize(); 238 } 239 240 CPUPerformanceInterface::~CPUPerformanceInterface() { 241 if (_impl != NULL) { 242 delete _impl; 243 } 244 } 245 246 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { 247 return _impl->cpu_load(which_logical_cpu, cpu_load); 248 } 249 250 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { 251 return _impl->cpu_load_total_process(cpu_load); 252 } 253 254 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { 255 return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); 256 } 257 258 int CPUPerformanceInterface::context_switch_rate(double* rate) const { 259 return _impl->context_switch_rate(rate); 260 } 261 262 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> { 263 friend class SystemProcessInterface; 264 private: 265 SystemProcesses(); 266 bool initialize(); 267 SystemProcesses(const SystemProcesses& rhs); // no impl 268 SystemProcesses& operator=(const SystemProcesses& rhs); // no impl 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 NetworkPerformance(const NetworkPerformance& rhs); // no impl 411 NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl 412 bool initialize(); 413 ~NetworkPerformance(); 414 int network_utilization(NetworkInterface** network_interfaces) const; 415 }; 416 417 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { 418 } 419 420 bool NetworkPerformanceInterface::NetworkPerformance::initialize() { 421 return true; 422 } 423 424 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { 425 } 426 427 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { 428 size_t len; 429 int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0}; 430 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) { 431 return OS_ERR; 432 } 433 uint8_t* buf = NEW_RESOURCE_ARRAY(uint8_t, len); 434 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &len, NULL, 0) != 0) { 435 return OS_ERR; 436 } 437 438 size_t index = 0; 439 NetworkInterface* ret = NULL; 440 while (index < len) { 441 if_msghdr* msghdr = reinterpret_cast<if_msghdr*>(buf + index); 442 index += msghdr->ifm_msglen; 443 444 if (msghdr->ifm_type != RTM_IFINFO2) { 445 continue; 446 } 447 448 if_msghdr2* msghdr2 = reinterpret_cast<if_msghdr2*>(msghdr); 449 sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr2 + 1); 450 451 // The interface name is not necessarily NUL-terminated 452 char name_buf[128]; 453 size_t name_len = MIN2(sizeof(name_buf) - 1, static_cast<size_t>(sockaddr->sdl_nlen)); 454 strncpy(name_buf, sockaddr->sdl_data, name_len); 455 name_buf[name_len] = '\0'; 456 457 uint64_t bytes_in = msghdr2->ifm_data.ifi_ibytes; 458 uint64_t bytes_out = msghdr2->ifm_data.ifi_obytes; 459 460 NetworkInterface* cur = new NetworkInterface(name_buf, bytes_in, bytes_out, ret); 461 ret = cur; 462 } 463 464 *network_interfaces = ret; 465 466 return OS_OK; 467 } 468 469 NetworkPerformanceInterface::NetworkPerformanceInterface() { 470 _impl = NULL; 471 } 472 473 NetworkPerformanceInterface::~NetworkPerformanceInterface() { 474 if (_impl != NULL) { 475 delete _impl; 476 } 477 } 478 479 bool NetworkPerformanceInterface::initialize() { 480 _impl = new NetworkPerformanceInterface::NetworkPerformance(); 481 return _impl->initialize(); 482 } 483 484 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { 485 return _impl->network_utilization(network_interfaces); 486 }