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
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(¤t_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 CPUPerformance(const CPUPerformance& rhs); // no impl
114 CPUPerformance& operator=(const CPUPerformance& rhs); // no impl
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 != NULL && _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 SystemProcesses(const SystemProcesses& rhs); // no impl
591 SystemProcesses& operator=(const SystemProcesses& rhs); // no impl
592 ~SystemProcesses();
593
594 //information about system processes
595 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
596 };
597
SystemProcesses()598 SystemProcessInterface::SystemProcesses::SystemProcesses() {
599 }
600
initialize()601 bool SystemProcessInterface::SystemProcesses::initialize() {
602 return true;
603 }
604
~SystemProcesses()605 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
606 }
system_processes(SystemProcess ** system_processes,int * no_of_sys_processes) const607 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
608 assert(system_processes != NULL, "system_processes pointer is NULL!");
609 assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
610 #ifdef __APPLE__
611 pid_t* pids = NULL;
612 int pid_count = 0;
613 ResourceMark rm;
614
615 int try_count = 0;
616 while (pids == NULL) {
617 // Find out buffer size
618 size_t pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
619 if (pids_bytes <= 0) {
620 return OS_ERR;
621 }
622 pid_count = pids_bytes / sizeof(pid_t);
623 pids = NEW_RESOURCE_ARRAY(pid_t, pid_count);
624 memset(pids, 0, pids_bytes);
625
626 pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes);
627 if (pids_bytes <= 0) {
628 // couldn't fit buffer, retry.
629 FREE_RESOURCE_ARRAY(pid_t, pids, pid_count);
630 pids = NULL;
631 try_count++;
632 if (try_count > 3) {
633 return OS_ERR;
634 }
635 } else {
636 pid_count = pids_bytes / sizeof(pid_t);
637 }
638 }
639
640 int process_count = 0;
641 SystemProcess* next = NULL;
642 for (int i = 0; i < pid_count; i++) {
643 pid_t pid = pids[i];
644 if (pid != 0) {
645 char buffer[PROC_PIDPATHINFO_MAXSIZE];
646 memset(buffer, 0 , sizeof(buffer));
647 if (proc_pidpath(pid, buffer, sizeof(buffer)) != -1) {
648 int length = strlen(buffer);
649 if (length > 0) {
650 SystemProcess* current = new SystemProcess();
651 char * path = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
652 strcpy(path, buffer);
653 current->set_path(path);
654 current->set_pid((int)pid);
655 current->set_next(next);
656 next = current;
657 process_count++;
658 }
659 }
660 }
661 }
662
663 *no_of_sys_processes = process_count;
664 *system_processes = next;
665
666 return OS_OK;
667 #elif defined(__FreeBSD__)
668 struct kinfo_proc *lproc;
669 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
670 const u_int miblen = sizeof(mib) / sizeof(mib[0]);
671 size_t length;
672 int pid_count;
673
674 if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
675 return OS_ERR;
676 }
677
678 lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc, length, mtInternal);
679 if (lproc == NULL) {
680 return OS_ERR;
681 }
682
683 if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
684 FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
685 return OS_ERR;
686 }
687
688 pid_count = length / sizeof(*lproc);
689 int process_count = 0;
690 SystemProcess *next = NULL;
691
692 for (int i = 0; i < pid_count; i++) {
693 // Executable path
694 int pmib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, lproc[i].ki_pid };
695 const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
696 char pbuf[PATH_MAX];
697 size_t plen = sizeof(pbuf);
698 if (sysctl(pmib, pmiblen, pbuf, &plen, NULL, 0) == -1) {
699 continue;
700 }
701 plen = strnlen(pbuf, PATH_MAX);
702 if (plen == 0) {
703 continue;
704 }
705 char *path = NEW_C_HEAP_ARRAY_RETURN_NULL(char, plen + 1, mtInternal);
706 if (path == NULL) {
707 continue;
708 }
709 strlcpy(path, pbuf, plen + 1);
710
711 // Command line
712 int amib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, lproc[i].ki_pid };
713 const u_int amiblen = sizeof(amib) / sizeof(amib[0]);
714 char abuf[ARG_MAX];
715 size_t alen = sizeof(abuf);
716 char *cmdline = NULL;
717 if (sysctl(amib, amiblen, abuf, &alen, NULL, 0) != -1 && alen > 0) {
718 // Arguments are NUL separated in the result, replace that with a space
719 for (size_t j = 0; j < alen; j++) {
720 if (abuf[j] == '\0') {
721 abuf[j] = ' ';
722 }
723 }
724 cmdline = NEW_C_HEAP_ARRAY_RETURN_NULL(char, alen + 1, mtInternal);
725 if (cmdline != NULL) {
726 strlcpy(cmdline, abuf, alen + 1);
727 }
728 }
729
730 SystemProcess* current = new SystemProcess();
731 current->set_pid((int)lproc[i].ki_pid);
732 current->set_path(path);
733 current->set_command_line(cmdline);
734 current->set_next(next);
735 next = current;
736 process_count++;
737 }
738
739 FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
740 *no_of_sys_processes = process_count;
741 *system_processes = next;
742
743 return OS_OK;
744 #elif defined(__OpenBSD__)
745 struct kinfo_proc *lproc;
746 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0 };
747 const u_int miblen = sizeof(mib) / sizeof(mib[0]);
748 size_t length;
749 int pid_count, ret = OS_OK;
750
751 if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
752 return OS_ERR;
753 }
754
755 lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc, length, mtInternal);
756 if (lproc == NULL) {
757 return OS_ERR;
758 }
759
760 mib[5] = length / sizeof(struct kinfo_proc);
761
762 if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
763 FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
764 return OS_ERR;
765 }
766
767 pid_count = length / sizeof(*lproc);
768 int process_count = 0;
769 SystemProcess *next = NULL;
770
771 for (int i = 0; i < pid_count; i++) {
772 int pmib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_ARGV };
773 const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
774 size_t slen;
775
776 if (sysctl(pmib, pmiblen, NULL, &length, NULL, 0) == -1) {
777 ret = OS_ERR;
778 break;
779 }
780
781 // Allocate space for args and get the arguments
782 char **argv = NEW_C_HEAP_ARRAY_RETURN_NULL(char*, length, mtInternal);
783 if (argv == NULL) {
784 ret = OS_ERR;
785 break;
786 }
787
788 if (sysctl(pmib, pmiblen, argv, &length, NULL, 0) == -1) {
789 ret = OS_ERR;
790 FREE_C_HEAP_ARRAY(char*, argv);
791 break;
792 }
793
794 if (argv[0] == NULL) {
795 FREE_C_HEAP_ARRAY(char*, argv);
796 continue;
797 }
798
799 slen = strnlen(argv[0], length);
800 if (slen > 0) {
801 SystemProcess* current = new SystemProcess();
802 char * path = NEW_C_HEAP_ARRAY(char, slen + 1, mtInternal);
803 strlcpy(path, argv[0], slen + 1);
804 current->set_path(path);
805 current->set_pid((int)lproc[i].p_pid);
806 /* TODO: build concatenated string for current->set_command_line() */
807 current->set_next(next);
808 next = current;
809 process_count++;
810 }
811
812 FREE_C_HEAP_ARRAY(char*, argv);
813 }
814
815 FREE_C_HEAP_ARRAY(struct kinfo_proc, lproc);
816
817 if (ret != OS_OK) {
818 SystemProcess* current = next;
819 while (current) {
820 next = current->next();
821 delete current; /* ~SystemProcess frees internal strings */
822 current = next;
823 }
824 return ret;
825 }
826
827 *no_of_sys_processes = process_count;
828 *system_processes = next;
829
830 return OS_OK;
831 #elif defined(__NetBSD__)
832 struct kinfo_proc2 *lproc;
833 int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0 };
834 const u_int miblen = sizeof(mib) / sizeof(mib[0]);
835 size_t length;
836 int pid_count;
837
838 if (sysctl(mib, miblen, NULL, &length, NULL, 0) == -1) {
839 return OS_ERR;
840 }
841
842 lproc = NEW_C_HEAP_ARRAY_RETURN_NULL(struct kinfo_proc2, length, mtInternal);
843 if (lproc == NULL) {
844 return OS_ERR;
845 }
846
847 mib[5] = length / sizeof(struct kinfo_proc2);
848
849 if (sysctl(mib, miblen, lproc, &length, NULL, 0) == -1) {
850 FREE_C_HEAP_ARRAY(struct kinfo_proc2, lproc);
851 return OS_ERR;
852 }
853
854 pid_count = length / sizeof(*lproc);
855 int process_count = 0;
856 SystemProcess *next = NULL;
857
858 for (int i = 0; i < pid_count; i++) {
859 // Executable path
860 int pmib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_PATHNAME };
861 const u_int pmiblen = sizeof(pmib) / sizeof(pmib[0]);
862 char pbuf[PATH_MAX];
863 size_t plen = sizeof(pbuf);
864 if (sysctl(pmib, pmiblen, pbuf, &plen, NULL, 0) == -1) {
865 continue;
866 }
867 plen = strnlen(pbuf, PATH_MAX);
868 if (plen == 0) {
869 continue;
870 }
871 char *path = NEW_C_HEAP_ARRAY_RETURN_NULL(char, plen + 1, mtInternal);
872 if (path == NULL) {
873 continue;
874 }
875 strlcpy(path, pbuf, plen + 1);
876
877 // Command line
878 int amib[] = { CTL_KERN, KERN_PROC_ARGS, lproc[i].p_pid, KERN_PROC_ARGV };
879 const u_int amiblen = sizeof(amib) / sizeof(amib[0]);
880 char abuf[ARG_MAX];
881 size_t alen = sizeof(abuf);
882 char *cmdline = NULL;
883 if (sysctl(amib, amiblen, abuf, &alen, NULL, 0) != -1 && alen > 0) {
884 // Arguments are NUL separated in the result, replace that with a space
885 for (size_t j = 0; j < alen; j++) {
886 if (abuf[j] == '\0') {
887 abuf[j] = ' ';
888 }
889 }
890 cmdline = NEW_C_HEAP_ARRAY_RETURN_NULL(char, alen + 1, mtInternal);
891 if (cmdline != NULL) {
892 strlcpy(cmdline, abuf, alen + 1);
893 }
894 }
895
896 SystemProcess* current = new SystemProcess();
897 current->set_pid((int)lproc[i].p_pid);
898 current->set_path(path);
899 current->set_command_line(cmdline);
900 current->set_next(next);
901 next = current;
902 process_count++;
903 }
904
905 FREE_C_HEAP_ARRAY(struct kinfo_proc2, lproc);
906 *no_of_sys_processes = process_count;
907 *system_processes = next;
908
909 return OS_OK;
910 #else
911 return FUNCTIONALITY_NOT_IMPLEMENTED;
912 #endif
913 }
914
system_processes(SystemProcess ** system_procs,int * no_of_sys_processes) const915 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
916 return _impl->system_processes(system_procs, no_of_sys_processes);
917 }
918
SystemProcessInterface()919 SystemProcessInterface::SystemProcessInterface() {
920 _impl = NULL;
921 }
922
initialize()923 bool SystemProcessInterface::initialize() {
924 _impl = new SystemProcessInterface::SystemProcesses();
925 return _impl != NULL && _impl->initialize();
926 }
927
~SystemProcessInterface()928 SystemProcessInterface::~SystemProcessInterface() {
929 if (_impl != NULL) {
930 delete _impl;
931 }
932 }
933
CPUInformationInterface()934 CPUInformationInterface::CPUInformationInterface() {
935 _cpu_info = NULL;
936 }
937
initialize()938 bool CPUInformationInterface::initialize() {
939 _cpu_info = new CPUInformation();
940
941 if (NULL == _cpu_info) {
942 return false;
943 }
944 _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
945 _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
946 _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
947 _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
948 _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
949
950 return true;
951 }
952
~CPUInformationInterface()953 CPUInformationInterface::~CPUInformationInterface() {
954 if (_cpu_info != NULL) {
955 if (_cpu_info->cpu_name() != NULL) {
956 const char* cpu_name = _cpu_info->cpu_name();
957 FREE_C_HEAP_ARRAY(char, cpu_name);
958 _cpu_info->set_cpu_name(NULL);
959 }
960 if (_cpu_info->cpu_description() != NULL) {
961 const char* cpu_desc = _cpu_info->cpu_description();
962 FREE_C_HEAP_ARRAY(char, cpu_desc);
963 _cpu_info->set_cpu_description(NULL);
964 }
965 delete _cpu_info;
966 }
967 }
968
cpu_information(CPUInformation & cpu_info)969 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
970 if (NULL == _cpu_info) {
971 return OS_ERR;
972 }
973
974 cpu_info = *_cpu_info; // shallow copy assignment
975 return OS_OK;
976 }
977
978 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
979 friend class NetworkPerformanceInterface;
980 private:
981 NetworkPerformance();
982 NetworkPerformance(const NetworkPerformance& rhs); // no impl
983 NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
984 bool initialize();
985 ~NetworkPerformance();
986 int network_utilization(NetworkInterface** network_interfaces) const;
987 };
988
NetworkPerformance()989 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
990 }
991
initialize()992 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
993 return true;
994 }
995
~NetworkPerformance()996 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
997 }
998
network_utilization(NetworkInterface ** network_interfaces) const999 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
1000 size_t len;
1001 int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0};
1002 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) {
1003 return OS_ERR;
1004 }
1005 uint8_t* buf = NEW_RESOURCE_ARRAY(uint8_t, len);
1006 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &len, NULL, 0) != 0) {
1007 return OS_ERR;
1008 }
1009
1010 size_t index = 0;
1011 NetworkInterface* ret = NULL;
1012 while (index < len) {
1013 if_msghdr* msghdr = reinterpret_cast<if_msghdr*>(buf + index);
1014 index += msghdr->ifm_msglen;
1015
1016 if (msghdr->ifm_type != RTM_IFINFO2) {
1017 continue;
1018 }
1019
1020 #if defined(__APPLE__)
1021 if_msghdr2* msghdr2 = reinterpret_cast<if_msghdr2*>(msghdr);
1022 sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr2 + 1);
1023 #else
1024 sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr + 1);
1025 #endif
1026
1027 // The interface name is not necessarily NUL-terminated
1028 char name_buf[128];
1029 size_t name_len = MIN2(sizeof(name_buf) - 1, static_cast<size_t>(sockaddr->sdl_nlen));
1030 strlcpy(name_buf, sockaddr->sdl_data, name_len + 1);
1031
1032 #if defined(__APPLE__)
1033 uint64_t bytes_in = msghdr2->ifm_data.ifi_ibytes;
1034 uint64_t bytes_out = msghdr2->ifm_data.ifi_obytes;
1035 #else
1036 uint64_t bytes_in = msghdr->ifm_data.ifi_ibytes;
1037 uint64_t bytes_out = msghdr->ifm_data.ifi_obytes;
1038 #endif
1039
1040 NetworkInterface* cur = new NetworkInterface(name_buf, bytes_in, bytes_out, ret);
1041 ret = cur;
1042 }
1043
1044 *network_interfaces = ret;
1045
1046 return OS_OK;
1047 }
1048
NetworkPerformanceInterface()1049 NetworkPerformanceInterface::NetworkPerformanceInterface() {
1050 _impl = NULL;
1051 }
1052
~NetworkPerformanceInterface()1053 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1054 if (_impl != NULL) {
1055 delete _impl;
1056 }
1057 }
1058
initialize()1059 bool NetworkPerformanceInterface::initialize() {
1060 _impl = new NetworkPerformanceInterface::NetworkPerformance();
1061 return _impl != NULL && _impl->initialize();
1062 }
1063
network_utilization(NetworkInterface ** network_interfaces) const1064 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1065 return _impl->network_utilization(network_interfaces);
1066 }
1067