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