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(¤t_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