1 /*
2  * Copyright (c) 2012, 2021, 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/globalDefinitions.hpp"
30 #include CPU_HEADER(vm_version_ext)
31 
32 #ifdef __APPLE__
33   #import <libproc.h>
34   #include <mach/mach.h>
35   #include <mach/task_info.h>
36 #else
37   #include <sys/user.h>
38   #include <sys/sched.h>
39   #include <sys/resource.h>
40   #define NET_RT_IFLIST2 NET_RT_IFLIST
41   #define RTM_IFINFO2    RTM_IFINFO
42 #endif
43 #ifdef __NetBSD__
44   #include <uvm/uvm_extern.h>
45 #endif
46 #include <sys/time.h>
47 #include <sys/sysctl.h>
48 #include <sys/socket.h>
49 #include <net/if.h>
50 #include <net/if_dl.h>
51 #include <net/route.h>
52 
53 static const time_t NANOS_PER_SEC = 1000000000LL;
54 static const time_t MICROS_PER_SEC = 1000000LL;
55 static const time_t NANOS_PER_MICROSEC = 1000LL;
56 
57 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
58    friend class CPUPerformanceInterface;
59  private:
60 #if defined(__APPLE__)
61   long _total_cpu_nanos;
62   long _total_csr_nanos;
63   long _jvm_user_nanos;
64   long _jvm_system_nanos;
65   long _jvm_context_switches;
66   long _used_ticks;
67   long _total_ticks;
68   int  _active_processor_count;
69 
normalize(double value)70   double normalize(double value) {
71     return MIN2<double>(MAX2<double>(value, 0.0), 1.0);
72   }
73 #else
74   struct CPUTicks {
75     uint64_t usedTicks;
76     uint64_t totalTicks;
77   };
78 
79   struct JVMTicks {
80     uint64_t userTicks;
81     uint64_t systemTicks;
82     CPUTicks cpuTicks;
83   };
84 
85   int _num_procs;
86   int _stathz;          // statistics clock frequency
87   JVMTicks _jvm_ticks;
88   CPUTicks* _cpus;
89   long _total_csr_nanos;
90   long _jvm_context_switches;
91 
92   int init_stathz(void);
93   uint64_t tvtoticks(struct timeval tv);
94   int get_cpu_ticks(CPUTicks *ticks, int which_logical_cpu);
95   int get_jvm_ticks(JVMTicks *jvm_ticks);
96 #endif
97 
now_in_nanos(long * resultp)98   bool now_in_nanos(long* resultp) {
99     struct timespec tp;
100     int status = clock_gettime(CLOCK_REALTIME, &tp);
101     assert(status == 0, "clock_gettime error: %s", os::strerror(errno));
102     if (status != 0) {
103       return false;
104     }
105     *resultp = tp.tv_sec * NANOS_PER_SEC + tp.tv_nsec;
106     return true;
107   }
108 
109   int cpu_load(int which_logical_cpu, double* cpu_load);
110   int context_switch_rate(double* rate);
111   int cpu_load_total_process(double* cpu_load);
112   int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
113 
114   NONCOPYABLE(CPUPerformance);
115 
116  public:
117   CPUPerformance();
118   bool initialize();
119   ~CPUPerformance();
120 };
121 
122 #if defined(__APPLE__)
123 
CPUPerformance()124 CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
125   _total_cpu_nanos= 0;
126   _total_csr_nanos= 0;
127   _jvm_context_switches = 0;
128   _jvm_user_nanos = 0;
129   _jvm_system_nanos = 0;
130   _used_ticks = 0;
131   _total_ticks = 0;
132   _active_processor_count = 0;
133 }
134 
initialize()135 bool CPUPerformanceInterface::CPUPerformance::initialize() {
136   return true;
137 }
138 
~CPUPerformance()139 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
140 }
141 
cpu_load(int which_logical_cpu,double * cpu_load)142 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
143   return FUNCTIONALITY_NOT_IMPLEMENTED;
144 }
145 
cpu_load_total_process(double * cpu_load)146 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
147   host_name_port_t host = mach_host_self();
148   host_flavor_t flavor = HOST_CPU_LOAD_INFO;
149   mach_msg_type_number_t host_info_count = HOST_CPU_LOAD_INFO_COUNT;
150   host_cpu_load_info_data_t cpu_load_info;
151 
152   kern_return_t kr = host_statistics(host, flavor, (host_info_t)&cpu_load_info, &host_info_count);
153   if (kr != KERN_SUCCESS) {
154     return OS_ERR;
155   }
156 
157   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];
158   long total_ticks = used_ticks + cpu_load_info.cpu_ticks[CPU_STATE_IDLE];
159 
160   if (_used_ticks == 0 || _total_ticks == 0) {
161     // First call, just set the values
162     _used_ticks  = used_ticks;
163     _total_ticks = total_ticks;
164     return OS_ERR;
165   }
166 
167   long used_delta  = used_ticks - _used_ticks;
168   long total_delta = total_ticks - _total_ticks;
169 
170   _used_ticks  = used_ticks;
171   _total_ticks = total_ticks;
172 
173   if (total_delta == 0) {
174     // Avoid division by zero
175     return OS_ERR;
176   }
177 
178   *cpu_load = (double)used_delta / total_delta;
179 
180   return OS_OK;
181 }
182 
cpu_loads_process(double * pjvmUserLoad,double * pjvmKernelLoad,double * psystemTotalLoad)183 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
184   int result = cpu_load_total_process(psystemTotalLoad);
185   mach_port_t task = mach_task_self();
186   mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
187   task_info_data_t task_info_data;
188   kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count);
189   if (kr != KERN_SUCCESS) {
190     return OS_ERR;
191   }
192   task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data;
193 
194   int active_processor_count = os::active_processor_count();
195   long jvm_user_nanos = absolutetime_info->total_user;
196   long jvm_system_nanos = absolutetime_info->total_system;
197 
198   long total_cpu_nanos;
199   if(!now_in_nanos(&total_cpu_nanos)) {
200     return OS_ERR;
201   }
202 
203   if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) {
204     // First call or change in active processor count
205     result = OS_ERR;
206   }
207 
208   long delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos);
209   if (delta_nanos == 0) {
210     // Avoid division by zero
211     return OS_ERR;
212   }
213 
214   *pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos);
215   *pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos);
216 
217   _active_processor_count = active_processor_count;
218   _total_cpu_nanos = total_cpu_nanos;
219   _jvm_user_nanos = jvm_user_nanos;
220   _jvm_system_nanos = jvm_system_nanos;
221 
222   return result;
223 }
224 
225 #else // !APPLE
226 
CPUPerformance()227 CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
228   _num_procs = 0;
229   _stathz = 0;
230   _jvm_ticks = JVMTicks();
231   _cpus = NULL;
232   _total_csr_nanos= 0;
233   _jvm_context_switches = 0;
234 }
235 
initialize()236 bool CPUPerformanceInterface::CPUPerformance::initialize() {
237   _num_procs = os::processor_count();
238   if (_num_procs < 1) {
239     return false;
240   }
241 
242   if (init_stathz() != OS_OK) {
243     return false;
244   }
245 
246   size_t cpus_array_count = _num_procs + 1;
247   _cpus = NEW_C_HEAP_ARRAY_RETURN_NULL(CPUTicks, cpus_array_count, mtInternal);
248   if (_cpus == NULL) {
249     return false;
250   }
251   memset(_cpus, 0, cpus_array_count * sizeof(*_cpus));
252 
253   // For the CPU load total
254   if (get_cpu_ticks(&_cpus[_num_procs], -1) != OS_OK) {
255     FREE_C_HEAP_ARRAY(CPUTicks, _cpus);
256     _cpus = NULL;
257     return false;
258   }
259 
260   // For each CPU. Ignoring errors.
261   for (int i = 0; i < _num_procs; i++) {
262     get_cpu_ticks(&_cpus[i], i);
263   }
264 
265   // For JVM load
266   if (get_jvm_ticks(&_jvm_ticks) != OS_OK) {
267     FREE_C_HEAP_ARRAY(CPUTicks, _cpus);
268     _cpus = NULL;
269     return false;
270   }
271   return true;
272 }
273 
~CPUPerformance()274 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
275   if (_cpus != NULL) {
276     FREE_C_HEAP_ARRAY(CPUTicks, _cpus);
277   }
278 }
279 
init_stathz(void)280 int CPUPerformanceInterface::CPUPerformance::init_stathz(void) {
281   struct clockinfo ci;
282   size_t length = sizeof(ci);
283   int mib[] = { CTL_KERN, KERN_CLOCKRATE };
284   const u_int miblen = sizeof(mib) / sizeof(mib[0]);
285 
286   if (sysctl(mib, miblen, &ci, &length, NULL, 0) == -1) {
287     return OS_ERR;
288   }
289 
290   _stathz = ci.stathz;
291 
292   return OS_OK;
293 }
294 
get_cpu_ticks(CPUTicks * ticks,int which_logical_cpu)295 int CPUPerformanceInterface::CPUPerformance::get_cpu_ticks(CPUTicks *ticks, int which_logical_cpu) {
296 #if defined(__NetBSD__)
297   uint64_t cpu_load_info[CPUSTATES];
298 #else
299   long cpu_load_info[CPUSTATES];
300 #endif
301   size_t length = sizeof(cpu_load_info);
302 
303   if (which_logical_cpu == -1) {
304 #if defined(__OpenBSD__)
305     int mib[] = { CTL_KERN, KERN_CPTIME };
306     const u_int miblen = sizeof(mib) / sizeof(mib[0]);
307 
308     if (sysctl(mib, miblen, &cpu_load_info, &length, NULL, 0) == -1) {
309       return OS_ERR;
310     }
311     // OpenBSD returns the sum/_num_procs. Unify with other stat units
312     for (size_t i=0; i < CPUSTATES; i++) {
313        cpu_load_info[i] *= _num_procs;
314     }
315 #else
316     if (sysctlbyname("kern.cp_time", &cpu_load_info, &length, NULL, 0) == -1) {
317       return OS_ERR;
318     }
319 #endif
320   } else {
321 #if defined(__OpenBSD__)
322     int mib[] = { CTL_KERN, KERN_CPTIME2, which_logical_cpu };
323     const u_int miblen = sizeof(mib) / sizeof(mib[0]);
324 
325     if (sysctl(mib, miblen, &cpu_load_info, &length, NULL, 0) == -1) {
326       return OS_ERR;
327     }
328 #elif defined(__FreeBSD__) || defined(__DragonFly__)
329     size_t alllength = length * _num_procs;
330     long *allcpus = NEW_C_HEAP_ARRAY(long, CPUSTATES * _num_procs, mtInternal);
331 
332     if (sysctlbyname("kern.cp_times", allcpus, &alllength, NULL, 0) == -1) {
333       FREE_C_HEAP_ARRAY(long, allcpus);
334       return OS_ERR;
335     }
336 
337     memcpy(cpu_load_info, &allcpus[which_logical_cpu * CPUSTATES], sizeof(long) * CPUSTATES);
338     FREE_C_HEAP_ARRAY(long, allcpus);
339 #else
340     char name[24];
341     snprintf(name, sizeof(name), "kern.cp_time.%d", which_logical_cpu);
342     if (sysctlbyname(name, &cpu_load_info, &length, NULL, 0) == -1) {
343       return OS_ERR;
344     }
345 #endif
346   }
347 
348   ticks->totalTicks = 0;
349   for (size_t i=0; i < CPUSTATES; i++) {
350      ticks->totalTicks += cpu_load_info[i];
351   }
352   ticks->usedTicks = ticks->totalTicks - cpu_load_info[CP_IDLE];
353 
354   return OS_OK;
355 }
356 
tvtoticks(struct timeval tv)357 uint64_t CPUPerformanceInterface::CPUPerformance::tvtoticks(struct timeval tv) {
358   uint64_t ticks = 0;
359   ticks += (uint64_t)tv.tv_sec * _stathz;
360   ticks += (uint64_t)tv.tv_usec * _stathz / MICROS_PER_SEC;
361   return ticks;
362 }
363 
get_jvm_ticks(JVMTicks * jvm_ticks)364 int CPUPerformanceInterface::CPUPerformance::get_jvm_ticks(JVMTicks *jvm_ticks) {
365   struct rusage usage;
366 
367   if (getrusage(RUSAGE_SELF, &usage) != 0) {
368     return OS_ERR;
369   }
370 
371   if (get_cpu_ticks(&jvm_ticks->cpuTicks, -1) != OS_OK) {
372     return OS_ERR;
373   }
374 
375   jvm_ticks->userTicks = tvtoticks(usage.ru_utime);
376   jvm_ticks->systemTicks = tvtoticks(usage.ru_stime);
377 
378   // ensure values are consistent with each other
379   if (jvm_ticks->userTicks + jvm_ticks->systemTicks > jvm_ticks->cpuTicks.usedTicks)
380     jvm_ticks->cpuTicks.usedTicks = jvm_ticks->userTicks + jvm_ticks->systemTicks;
381 
382   if (jvm_ticks->cpuTicks.usedTicks > jvm_ticks->cpuTicks.totalTicks)
383     jvm_ticks->cpuTicks.totalTicks = jvm_ticks->cpuTicks.usedTicks;
384 
385   return OS_OK;
386 }
387 
cpu_load(int which_logical_cpu,double * cpu_load)388 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
389   CPUTicks curCPUTicks, *prevCPUTicks;
390   uint64_t cpuUsedDelta, cpuTotalDelta;
391 
392   *cpu_load = 0.0;
393 
394   if (_cpus == NULL) {
395     return OS_ERR;
396   }
397 
398   if (which_logical_cpu < -1 || which_logical_cpu >= _num_procs) {
399     return OS_ERR;
400   }
401 
402   if (get_cpu_ticks(&curCPUTicks, which_logical_cpu) != OS_OK) {
403     return OS_ERR;
404   }
405 
406   const int cpu_idx = (which_logical_cpu == -1) ? _num_procs : which_logical_cpu;
407   prevCPUTicks = &_cpus[cpu_idx];
408 
409   cpuUsedDelta = curCPUTicks.usedTicks > prevCPUTicks->usedTicks ?
410     curCPUTicks.usedTicks - prevCPUTicks->usedTicks : 0;
411   cpuTotalDelta = curCPUTicks.totalTicks > prevCPUTicks->totalTicks ?
412     curCPUTicks.totalTicks - prevCPUTicks->totalTicks : 0;
413 
414   prevCPUTicks->usedTicks = curCPUTicks.usedTicks;
415   prevCPUTicks->totalTicks = curCPUTicks.totalTicks;
416 
417   if (cpuTotalDelta == 0)
418     return OS_ERR;
419 
420   if (cpuUsedDelta > cpuTotalDelta)
421     cpuTotalDelta = cpuUsedDelta;
422 
423   *cpu_load = (double)cpuUsedDelta/cpuTotalDelta;
424 
425   return OS_OK;
426 }
427 
cpu_load_total_process(double * cpu_load)428 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
429   double jvmUserLoad, jvmKernelLoad, systemTotalLoad;
430 
431   if (cpu_loads_process(&jvmUserLoad, &jvmKernelLoad, &systemTotalLoad) != OS_OK) {
432     *cpu_load = 0.0;
433     return OS_ERR;
434   }
435 
436   *cpu_load = jvmUserLoad + jvmKernelLoad;
437   return OS_OK;
438 }
439 
cpu_loads_process(double * pjvmUserLoad,double * pjvmKernelLoad,double * psystemTotalLoad)440 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
441   JVMTicks curJVMTicks;
442   CPUTicks *curCPUTicks, *prevCPUTicks;
443 
444   uint64_t jvmUserDelta, jvmSystemDelta, cpuUsedDelta, cpuTotalDelta;
445 
446   *pjvmUserLoad = 0.0;
447   *pjvmKernelLoad = 0.0;
448   *psystemTotalLoad = 0.0;
449 
450   if (_cpus == NULL) {
451     return OS_ERR;
452   }
453 
454   if (get_jvm_ticks(&curJVMTicks) != OS_OK) {
455     return OS_ERR;
456   }
457 
458   curCPUTicks = &curJVMTicks.cpuTicks;
459   prevCPUTicks = &_jvm_ticks.cpuTicks;
460 
461   jvmUserDelta = curJVMTicks.userTicks > _jvm_ticks.userTicks ?
462     curJVMTicks.userTicks - _jvm_ticks.userTicks : 0;
463   jvmSystemDelta = curJVMTicks.systemTicks > _jvm_ticks.systemTicks ?
464     curJVMTicks.systemTicks - _jvm_ticks.systemTicks : 0;
465 
466   cpuUsedDelta = curCPUTicks->usedTicks > prevCPUTicks->usedTicks ?
467     curCPUTicks->usedTicks - prevCPUTicks->usedTicks : 0;
468   cpuTotalDelta = curCPUTicks->totalTicks > prevCPUTicks->totalTicks ?
469     curCPUTicks->totalTicks - prevCPUTicks->totalTicks : 0;
470 
471   _jvm_ticks.userTicks = curJVMTicks.userTicks;
472   _jvm_ticks.systemTicks = curJVMTicks.systemTicks;
473   prevCPUTicks->usedTicks = curCPUTicks->usedTicks;
474   prevCPUTicks->totalTicks = curCPUTicks->totalTicks;
475 
476   // ensure values are consistent with each other
477   if (jvmUserDelta + jvmSystemDelta > cpuUsedDelta)
478     cpuUsedDelta = jvmUserDelta + jvmSystemDelta;
479 
480   if (cpuUsedDelta > cpuTotalDelta)
481     cpuTotalDelta = cpuUsedDelta;
482 
483   if (cpuTotalDelta == 0) {
484     return OS_ERR;
485   }
486 
487   *pjvmUserLoad = (double)jvmUserDelta/cpuTotalDelta;
488   *pjvmKernelLoad = (double)jvmSystemDelta/cpuTotalDelta;
489   *psystemTotalLoad = (double)cpuUsedDelta/cpuTotalDelta;
490 
491   return OS_OK;
492 }
493 
494 #endif
495 
context_switch_rate(double * rate)496 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
497 #ifdef __APPLE__
498   mach_port_t task = mach_task_self();
499   mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
500   task_info_data_t task_info_data;
501   kern_return_t kr = task_info(task, TASK_EVENTS_INFO, (task_info_t)task_info_data, &task_info_count);
502   if (kr != KERN_SUCCESS) {
503     return OS_ERR;
504   }
505 
506   long jvm_context_switches = ((task_events_info_t)task_info_data)->csw;
507 #elif defined(__FreeBSD__) || defined(__DragonFly__)
508   unsigned int jvm_context_switches = 0;
509   size_t length = sizeof(jvm_context_switches);
510   if (sysctlbyname("vm.stats.sys.v_swtch", &jvm_context_switches, &length, NULL, 0) == -1) {
511     return OS_ERR;
512   }
513 #elif defined(__OpenBSD__) || defined(__NetBSD__)
514 #if defined(__OpenBSD__)
515   struct uvmexp js;
516   int mib[] = { CTL_VM, VM_UVMEXP };
517 #else
518   struct uvmexp_sysctl js;
519   int mib[] = { CTL_VM, VM_UVMEXP2 };
520 #endif
521   size_t jslength = sizeof(js);
522   const u_int miblen = sizeof(mib) / sizeof(mib[0]);
523   unsigned int jvm_context_switches = 0;
524   if (sysctl(mib, miblen, &js, &jslength, NULL, 0) != 0) {
525     return OS_ERR;
526   }
527 
528   jvm_context_switches = (unsigned int)js.swtch;
529 #endif
530 
531   int result = OS_OK;
532   if (_total_csr_nanos == 0 || _jvm_context_switches == 0) {
533     // First call just set initial values.
534     result = OS_ERR;
535   }
536 
537   long total_csr_nanos;
538   if(!now_in_nanos(&total_csr_nanos)) {
539     return OS_ERR;
540   }
541   double delta_in_sec = (double)(total_csr_nanos - _total_csr_nanos) / (double)NANOS_PER_SEC;
542   if (delta_in_sec == 0.0) {
543     // Avoid division by zero
544     return OS_ERR;
545   }
546 
547   *rate = (jvm_context_switches - _jvm_context_switches) / delta_in_sec;
548 
549   _jvm_context_switches = jvm_context_switches;
550   _total_csr_nanos = total_csr_nanos;
551 
552   return result;
553 }
554 
CPUPerformanceInterface()555 CPUPerformanceInterface::CPUPerformanceInterface() {
556   _impl = NULL;
557 }
558 
initialize()559 bool CPUPerformanceInterface::initialize() {
560   _impl = new CPUPerformanceInterface::CPUPerformance();
561   return _impl->initialize();
562 }
563 
~CPUPerformanceInterface()564 CPUPerformanceInterface::~CPUPerformanceInterface() {
565   if (_impl != NULL) {
566     delete _impl;
567   }
568 }
569 
cpu_load(int which_logical_cpu,double * cpu_load) const570 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
571   return _impl->cpu_load(which_logical_cpu, cpu_load);
572 }
573 
cpu_load_total_process(double * cpu_load) const574 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
575   return _impl->cpu_load_total_process(cpu_load);
576 }
577 
cpu_loads_process(double * pjvmUserLoad,double * pjvmKernelLoad,double * psystemTotalLoad) const578 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
579   return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
580 }
581 
context_switch_rate(double * rate) const582 int CPUPerformanceInterface::context_switch_rate(double* rate) const {
583   return _impl->context_switch_rate(rate);
584 }
585 
586 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
587   friend class SystemProcessInterface;
588  private:
589   SystemProcesses();
590   bool initialize();
591   NONCOPYABLE(SystemProcesses);
592   ~SystemProcesses();
593 
594   //information about system processes
595   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
596 };
597 
SystemProcesses()598 SystemProcessInterface::SystemProcesses::SystemProcesses() {
599 }
600 
initialize()601 bool SystemProcessInterface::SystemProcesses::initialize() {
602   return true;
603 }
604 
~SystemProcesses()605 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
606 }
system_processes(SystemProcess ** system_processes,int * no_of_sys_processes) const607 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
608   assert(system_processes != NULL, "system_processes pointer is NULL!");
609   assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
610 #ifdef __APPLE__
611   pid_t* pids = NULL;
612   int pid_count = 0;
613   ResourceMark rm;
614 
615   int try_count = 0;
616   while (pids == NULL) {
617     // Find out buffer size
618     size_t pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
619     if (pids_bytes <= 0) {
620       return OS_ERR;
621     }
622     pid_count = pids_bytes / sizeof(pid_t);
623     pids = NEW_RESOURCE_ARRAY(pid_t, pid_count);
624     memset(pids, 0, pids_bytes);
625 
626     pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes);
627     if (pids_bytes <= 0) {
628        // couldn't fit buffer, retry.
629       FREE_RESOURCE_ARRAY(pid_t, pids, pid_count);
630       pids = NULL;
631       try_count++;
632       if (try_count > 3) {
633       return OS_ERR;
634       }
635     } else {
636       pid_count = pids_bytes / sizeof(pid_t);
637     }
638   }
639 
640   int process_count = 0;
641   SystemProcess* next = NULL;
642   for (int i = 0; i < pid_count; i++) {
643     pid_t pid = pids[i];
644     if (pid != 0) {
645       char buffer[PROC_PIDPATHINFO_MAXSIZE];
646       memset(buffer, 0 , sizeof(buffer));
647       if (proc_pidpath(pid, buffer, sizeof(buffer)) != -1) {
648         int length = strlen(buffer);
649         if (length > 0) {
650           SystemProcess* current = new SystemProcess();
651           char * path = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
652           strcpy(path, buffer);
653           current->set_path(path);
654           current->set_pid((int)pid);
655           current->set_next(next);
656           next = current;
657           process_count++;
658         }
659       }
660     }
661   }
662 
663   *no_of_sys_processes = process_count;
664   *system_processes = next;
665 
666   return OS_OK;
667 #elif defined(__FreeBSD__)
668   struct kinfo_proc *lproc;
669   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
670   const u_int miblen = sizeof(mib) / sizeof(mib[0]);
671   size_t length;
672   int pid_count;
673 
674   if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
675     return OS_ERR;
676   }
677 
678   lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc, length, mtInternal);
679   if (lproc == NULL) {
680     return OS_ERR;
681   }
682 
683   if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
684     FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
685     return OS_ERR;
686   }
687 
688   pid_count = length / sizeof(*lproc);
689   int process_count = 0;
690   SystemProcess *next = NULL;
691 
692   for (int i = 0; i < pid_count; i++) {
693     // Executable path
694     int pmib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, lproc[i].ki_pid };
695     const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
696     char pbuf[PATH_MAX];
697     size_t plen = sizeof(pbuf);
698     if (sysctl(pmib, pmiblen, pbuf, &plen, NULL, 0) == -1) {
699       continue;
700     }
701     plen = strnlen(pbuf, PATH_MAX);
702     if (plen == 0) {
703       continue;
704     }
705     char *path = NEW_C_HEAP_ARRAY_RETURN_NULL(char, plen + 1, mtInternal);
706     if (path == NULL) {
707       continue;
708     }
709     strlcpy(path, pbuf, plen + 1);
710 
711     // Command line
712     int amib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, lproc[i].ki_pid };
713     const u_int amiblen = sizeof(amib) / sizeof(amib[0]);
714     char abuf[ARG_MAX];
715     size_t alen = sizeof(abuf);
716     char *cmdline = NULL;
717     if (sysctl(amib, amiblen, abuf, &alen, NULL, 0) != -1 && alen > 0) {
718       // Arguments are NUL separated in the result, replace that with a space
719       for (size_t j = 0; j < alen; j++) {
720         if (abuf[j] == '\0') {
721           abuf[j] = ' ';
722         }
723       }
724       cmdline = NEW_C_HEAP_ARRAY_RETURN_NULL(char, alen + 1, mtInternal);
725       if (cmdline != NULL) {
726         strlcpy(cmdline, abuf, alen + 1);
727       }
728     }
729 
730     SystemProcess* current = new SystemProcess();
731     current->set_pid((int)lproc[i].ki_pid);
732     current->set_path(path);
733     current->set_command_line(cmdline);
734     current->set_next(next);
735     next = current;
736     process_count++;
737   }
738 
739   FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
740   *no_of_sys_processes = process_count;
741   *system_processes = next;
742 
743   return OS_OK;
744 #elif defined(__OpenBSD__)
745   struct kinfo_proc *lproc;
746   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0 };
747   const u_int miblen = sizeof(mib) / sizeof(mib[0]);
748   size_t length;
749   int pid_count, ret = OS_OK;
750 
751   if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
752     return OS_ERR;
753   }
754 
755   lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc, length, mtInternal);
756   if (lproc == NULL) {
757     return OS_ERR;
758   }
759 
760   mib[5] = length / sizeof(struct kinfo_proc);
761 
762   if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
763     FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
764     return OS_ERR;
765   }
766 
767   pid_count = length / sizeof(*lproc);
768   int process_count = 0;
769   SystemProcess *next = NULL;
770 
771   for (int i = 0; i < pid_count; i++) {
772     int pmib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_ARGV };
773     const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
774     size_t slen;
775 
776     if (sysctl(pmib, pmiblen, NULL, &length, NULL, 0) == -1) {
777       ret = OS_ERR;
778       break;
779     }
780 
781     // Allocate space for args and get the arguments
782     char **argv = NEW_C_HEAP_ARRAY_RETURN_NULL(char*, length, mtInternal);
783     if (argv == NULL) {
784       ret = OS_ERR;
785       break;
786     }
787 
788     if (sysctl(pmib, pmiblen, argv, &length, NULL, 0) == -1) {
789       ret = OS_ERR;
790       FREE_C_HEAP_ARRAY(char*, argv);
791       break;
792     }
793 
794     if (argv[0] == NULL) {
795       FREE_C_HEAP_ARRAY(char*, argv);
796       continue;
797     }
798 
799     slen = strnlen(argv[0], length);
800     if (slen > 0) {
801       SystemProcess* current = new SystemProcess();
802       char * path = NEW_C_HEAP_ARRAY(char, slen + 1, mtInternal);
803       strlcpy(path, argv[0], slen + 1);
804       current->set_path(path);
805       current->set_pid((int)lproc[i].p_pid);
806       /* TODO: build concatenated string for current->set_command_line() */
807       current->set_next(next);
808       next = current;
809       process_count++;
810     }
811 
812     FREE_C_HEAP_ARRAY(char*, argv);
813   }
814 
815   FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
816 
817   if (ret != OS_OK) {
818     SystemProcess* current = next;
819     while (current) {
820       next = current->next();
821       delete current; /* ~SystemProcess frees internal strings */
822       current = next;
823     }
824     return ret;
825   }
826 
827   *no_of_sys_processes = process_count;
828   *system_processes = next;
829 
830   return OS_OK;
831 #elif defined(__NetBSD__)
832   struct kinfo_proc2 *lproc;
833   int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0 };
834   const u_int miblen = sizeof(mib) / sizeof(mib[0]);
835   size_t length;
836   int pid_count;
837 
838   if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
839     return OS_ERR;
840   }
841 
842   lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc2, length, mtInternal);
843   if (lproc == NULL) {
844     return OS_ERR;
845   }
846 
847   mib[5] = length / sizeof(struct kinfo_proc2);
848 
849   if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
850     FREE_C_HEAP_ARRAY(struct kinfo_proc2, lproc);
851     return OS_ERR;
852   }
853 
854   pid_count = length / sizeof(*lproc);
855   int process_count = 0;
856   SystemProcess *next = NULL;
857 
858   for (int i = 0; i < pid_count; i++) {
859     // Executable path
860     int pmib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_PATHNAME };
861     const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
862     char pbuf[PATH_MAX];
863     size_t plen = sizeof(pbuf);
864     if (sysctl(pmib, pmiblen, pbuf, &plen, NULL, 0) == -1) {
865       continue;
866     }
867     plen = strnlen(pbuf, PATH_MAX);
868     if (plen == 0) {
869       continue;
870     }
871     char *path = NEW_C_HEAP_ARRAY_RETURN_NULL(char, plen + 1, mtInternal);
872     if (path == NULL) {
873       continue;
874     }
875     strlcpy(path, pbuf, plen + 1);
876 
877     // Command line
878     int amib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_ARGV };
879     const u_int amiblen = sizeof(amib) / sizeof(amib[0]);
880     char abuf[ARG_MAX];
881     size_t alen = sizeof(abuf);
882     char *cmdline = NULL;
883     if (sysctl(amib, amiblen, abuf, &alen, NULL, 0) != -1 && alen > 0) {
884       // Arguments are NUL separated in the result, replace that with a space
885       for (size_t j = 0; j < alen; j++) {
886         if (abuf[j] == '\0') {
887           abuf[j] = ' ';
888         }
889       }
890       cmdline = NEW_C_HEAP_ARRAY_RETURN_NULL(char, alen + 1, mtInternal);
891       if (cmdline != NULL) {
892         strlcpy(cmdline, abuf, alen + 1);
893       }
894     }
895 
896     SystemProcess* current = new SystemProcess();
897     current->set_pid((int)lproc[i].p_pid);
898     current->set_path(path);
899     current->set_command_line(cmdline);
900     current->set_next(next);
901     next = current;
902     process_count++;
903   }
904 
905   FREE_C_HEAP_ARRAY(struct kinfo_proc2, lproc);
906   *no_of_sys_processes = process_count;
907   *system_processes = next;
908 
909   return OS_OK;
910 #else
911   return FUNCTIONALITY_NOT_IMPLEMENTED;
912 #endif
913 }
914 
system_processes(SystemProcess ** system_procs,int * no_of_sys_processes) const915 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
916   return _impl->system_processes(system_procs, no_of_sys_processes);
917 }
918 
SystemProcessInterface()919 SystemProcessInterface::SystemProcessInterface() {
920   _impl = NULL;
921 }
922 
initialize()923 bool SystemProcessInterface::initialize() {
924   _impl = new SystemProcessInterface::SystemProcesses();
925   return _impl->initialize();
926 }
927 
~SystemProcessInterface()928 SystemProcessInterface::~SystemProcessInterface() {
929   if (_impl != NULL) {
930     delete _impl;
931  }
932 }
933 
CPUInformationInterface()934 CPUInformationInterface::CPUInformationInterface() {
935   _cpu_info = NULL;
936 }
937 
initialize()938 bool CPUInformationInterface::initialize() {
939   _cpu_info = new CPUInformation();
940   _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
941   _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
942   _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
943   _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
944   _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
945   return true;
946 }
947 
~CPUInformationInterface()948 CPUInformationInterface::~CPUInformationInterface() {
949   if (_cpu_info != NULL) {
950     if (_cpu_info->cpu_name() != NULL) {
951       const char* cpu_name = _cpu_info->cpu_name();
952       FREE_C_HEAP_ARRAY(char, cpu_name);
953       _cpu_info->set_cpu_name(NULL);
954     }
955     if (_cpu_info->cpu_description() != NULL) {
956       const char* cpu_desc = _cpu_info->cpu_description();
957       FREE_C_HEAP_ARRAY(char, cpu_desc);
958       _cpu_info->set_cpu_description(NULL);
959     }
960     delete _cpu_info;
961   }
962 }
963 
cpu_information(CPUInformation & cpu_info)964 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
965   if (NULL == _cpu_info) {
966     return OS_ERR;
967   }
968 
969   cpu_info = *_cpu_info; // shallow copy assignment
970   return OS_OK;
971 }
972 
973 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
974   friend class NetworkPerformanceInterface;
975  private:
976   NetworkPerformance();
977   NONCOPYABLE(NetworkPerformance);
978   bool initialize();
979   ~NetworkPerformance();
980   int network_utilization(NetworkInterface** network_interfaces) const;
981 };
982 
NetworkPerformance()983 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
984 }
985 
initialize()986 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
987   return true;
988 }
989 
~NetworkPerformance()990 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
991 }
992 
network_utilization(NetworkInterface ** network_interfaces) const993 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
994   size_t len;
995   int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0};
996   if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) {
997     return OS_ERR;
998   }
999   uint8_t* buf = NEW_RESOURCE_ARRAY(uint8_t, len);
1000   if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &len, NULL, 0) != 0) {
1001     return OS_ERR;
1002   }
1003 
1004   size_t index = 0;
1005   NetworkInterface* ret = NULL;
1006   while (index < len) {
1007     if_msghdr* msghdr = reinterpret_cast<if_msghdr*>(buf + index);
1008     index += msghdr->ifm_msglen;
1009 
1010     if (msghdr->ifm_type != RTM_IFINFO2) {
1011       continue;
1012     }
1013 
1014 #if defined(__APPLE__)
1015     if_msghdr2* msghdr2 = reinterpret_cast<if_msghdr2*>(msghdr);
1016     sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr2 + 1);
1017 #else
1018     sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr + 1);
1019 #endif
1020 
1021     // The interface name is not necessarily NUL-terminated
1022     char name_buf[128];
1023     size_t name_len = MIN2(sizeof(name_buf) - 1, static_cast<size_t>(sockaddr->sdl_nlen));
1024     strlcpy(name_buf, sockaddr->sdl_data, name_len + 1);
1025 
1026 #if defined(__APPLE__)
1027     uint64_t bytes_in = msghdr2->ifm_data.ifi_ibytes;
1028     uint64_t bytes_out = msghdr2->ifm_data.ifi_obytes;
1029 #else
1030     uint64_t bytes_in = msghdr->ifm_data.ifi_ibytes;
1031     uint64_t bytes_out = msghdr->ifm_data.ifi_obytes;
1032 #endif
1033 
1034     NetworkInterface* cur = new NetworkInterface(name_buf, bytes_in, bytes_out, ret);
1035     ret = cur;
1036   }
1037 
1038   *network_interfaces = ret;
1039 
1040   return OS_OK;
1041 }
1042 
NetworkPerformanceInterface()1043 NetworkPerformanceInterface::NetworkPerformanceInterface() {
1044   _impl = NULL;
1045 }
1046 
~NetworkPerformanceInterface()1047 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1048   if (_impl != NULL) {
1049     delete _impl;
1050   }
1051 }
1052 
initialize()1053 bool NetworkPerformanceInterface::initialize() {
1054   _impl = new NetworkPerformanceInterface::NetworkPerformance();
1055   return _impl->initialize();
1056 }
1057 
network_utilization(NetworkInterface ** network_interfaces) const1058 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1059   return _impl->network_utilization(network_interfaces);
1060 }
1061