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