1/*
2 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "jfr/jfrEvents.hpp"
27#include "jfr/periodic/jfrNetworkUtilization.hpp"
28#include "jfr/periodic/jfrOSInterface.hpp"
29#include "memory/allocation.inline.hpp"
30#include "memory/resourceArea.hpp"
31#include "runtime/os.hpp"
32#include "runtime/os_perf.hpp"
33#include "utilities/ostream.hpp"
34
35#include <stdlib.h> // for environment variables
36#ifdef __APPLE__
37#include <crt_externs.h>
38#define environ (*_NSGetEnviron())
39#endif
40
41#ifndef environ
42extern char** environ;
43#endif
44
45static JfrOSInterface* _instance = NULL;
46
47JfrOSInterface& JfrOSInterface::instance() {
48 return *_instance;
49}
50
51JfrOSInterface* JfrOSInterface::create() {
52 assert(_instance == NULL, "invariant");
53 _instance = new JfrOSInterface();
54 return _instance;
55}
56
57void JfrOSInterface::destroy() {
58 JfrNetworkUtilization::destroy();
59 if (_instance != NULL) {
60 delete _instance;
61 _instance = NULL;
62 }
63}
64
65class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
66 friend class JfrOSInterface;
67 private:
68 CPUInformationInterface* _cpu_info_interface;
69 CPUPerformanceInterface* _cpu_perf_interface;
70 SystemProcessInterface* _system_process_interface;
71 NetworkPerformanceInterface* _network_performance_interface;
72
73 CPUInformationInterface* cpu_info_interface();
74 CPUPerformanceInterface* cpu_perf_interface();
75 SystemProcessInterface* system_process_interface();
76 NetworkPerformanceInterface* network_performance_interface();
77
78 JfrOSInterfaceImpl();
79 bool initialize();
80 ~JfrOSInterfaceImpl();
81
82 // cpu info
83 int cpu_information(CPUInformation& cpu_info);
84 int cpu_load(int which_logical_cpu, double* cpu_load);
85 int context_switch_rate(double* rate);
86 int cpu_load_total_process(double* cpu_load);
87 int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotal);
88
89 // os information
90 int os_version(char** os_version) const;
91
92 // environment information
93 void generate_environment_variables_events();
94
95 // system processes information
96 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
97
98 int network_utilization(NetworkInterface** network_interfaces);
99};
100
101JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL),
102 _cpu_perf_interface(NULL),
103 _system_process_interface(NULL),
104 _network_performance_interface(NULL) {}
105
106template <typename T>
107static T* create_interface() {
108 ResourceMark rm;
109 T* iface = new T();
110 if (iface != NULL) {
111 if (!iface->initialize()) {
112 delete iface;
113 iface = NULL;
114 }
115 }
116 return iface;
117}
118
119CPUInformationInterface* JfrOSInterface::JfrOSInterfaceImpl::cpu_info_interface() {
120 if (_cpu_info_interface == NULL) {
121 _cpu_info_interface = create_interface<CPUInformationInterface>();
122 }
123 return _cpu_info_interface;
124}
125
126CPUPerformanceInterface* JfrOSInterface::JfrOSInterfaceImpl::cpu_perf_interface() {
127 if (_cpu_perf_interface == NULL) {
128 _cpu_perf_interface = create_interface<CPUPerformanceInterface>();
129 }
130 return _cpu_perf_interface;
131}
132
133SystemProcessInterface* JfrOSInterface::JfrOSInterfaceImpl::system_process_interface() {
134 if (_system_process_interface == NULL) {
135 _system_process_interface = create_interface<SystemProcessInterface>();
136 }
137 return _system_process_interface;
138}
139
140NetworkPerformanceInterface* JfrOSInterface::JfrOSInterfaceImpl::network_performance_interface() {
141 if (_network_performance_interface == NULL) {
142 _network_performance_interface = create_interface<NetworkPerformanceInterface>();
143 }
144 return _network_performance_interface;
145}
146
147bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
148 return true;
149}
150
151JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
152 if (_cpu_info_interface != NULL) {
153 delete _cpu_info_interface;
154 _cpu_info_interface = NULL;
155 }
156 if (_cpu_perf_interface != NULL) {
157 delete _cpu_perf_interface;
158 _cpu_perf_interface = NULL;
159 }
160 if (_system_process_interface != NULL) {
161 delete _system_process_interface;
162 _system_process_interface = NULL;
163 }
164 if (_network_performance_interface != NULL) {
165 delete _network_performance_interface;
166 _network_performance_interface = NULL;
167 }
168}
169
170int JfrOSInterface::JfrOSInterfaceImpl::cpu_information(CPUInformation& cpu_info) {
171 CPUInformationInterface* const iface = cpu_info_interface();
172 return iface == NULL ? OS_ERR : iface->cpu_information(cpu_info);
173}
174
175int JfrOSInterface::JfrOSInterfaceImpl::cpu_load(int which_logical_cpu, double* cpu_load) {
176 CPUPerformanceInterface* const iface = cpu_perf_interface();
177 return iface == NULL ? OS_ERR : iface->cpu_load(which_logical_cpu, cpu_load);
178}
179
180int JfrOSInterface::JfrOSInterfaceImpl::context_switch_rate(double* rate) {
181 CPUPerformanceInterface* const iface = cpu_perf_interface();
182 return iface == NULL ? OS_ERR : iface->context_switch_rate(rate);
183}
184
185int JfrOSInterface::JfrOSInterfaceImpl::cpu_load_total_process(double* cpu_load) {
186 CPUPerformanceInterface* const iface = cpu_perf_interface();
187 return iface == NULL ? OS_ERR : iface->cpu_load_total_process(cpu_load);
188}
189
190int JfrOSInterface::JfrOSInterfaceImpl::cpu_loads_process(double* pjvmUserLoad,
191 double* pjvmKernelLoad,
192 double* psystemTotal) {
193 CPUPerformanceInterface* const iface = cpu_perf_interface();
194 return iface == NULL ? OS_ERR : iface->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotal);
195}
196
197int JfrOSInterface::JfrOSInterfaceImpl::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) {
198 assert(system_processes != NULL, "system_processes pointer is NULL!");
199 assert(no_of_sys_processes != NULL, "no_of_sys_processes pointer is NULL!");
200 SystemProcessInterface* const iface = system_process_interface();
201 return iface == NULL ? OS_ERR : iface->system_processes(system_processes, no_of_sys_processes);
202}
203
204int JfrOSInterface::JfrOSInterfaceImpl::network_utilization(NetworkInterface** network_interfaces) {
205 NetworkPerformanceInterface* const iface = network_performance_interface();
206 return iface == NULL ? OS_ERR : iface->network_utilization(network_interfaces);
207}
208
209// assigned char* is RESOURCE_HEAP_ALLOCATED
210// caller need to ensure proper ResourceMark placement.
211int JfrOSInterface::JfrOSInterfaceImpl::os_version(char** os_version) const {
212 assert(os_version != NULL, "os_version pointer is NULL!");
213 stringStream os_ver_info;
214 os::print_os_info_brief(&os_ver_info);
215 *os_version = os_ver_info.as_string();
216 return OS_OK;
217}
218
219JfrOSInterface::JfrOSInterface() {
220 _impl = NULL;
221}
222
223bool JfrOSInterface::initialize() {
224 _impl = new JfrOSInterface::JfrOSInterfaceImpl();
225 return _impl != NULL && _impl->initialize();
226}
227
228JfrOSInterface::~JfrOSInterface() {
229 if (_impl != NULL) {
230 delete _impl;
231 _impl = NULL;
232 }
233}
234
235int JfrOSInterface::cpu_information(CPUInformation& cpu_info) {
236 return instance()._impl->cpu_information(cpu_info);
237}
238
239int JfrOSInterface::cpu_load(int which_logical_cpu, double* cpu_load) {
240 return instance()._impl->cpu_load(which_logical_cpu, cpu_load);
241}
242
243int JfrOSInterface::context_switch_rate(double* rate) {
244 return instance()._impl->context_switch_rate(rate);
245}
246
247int JfrOSInterface::cpu_load_total_process(double* cpu_load) {
248 return instance()._impl->cpu_load_total_process(cpu_load);
249}
250
251int JfrOSInterface::cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* system_total_load){
252 return instance()._impl->cpu_loads_process(jvm_user_load, jvm_kernel_load, system_total_load);
253}
254
255int JfrOSInterface::os_version(char** os_version) {
256 return instance()._impl->os_version(os_version);
257}
258
259const char* JfrOSInterface::virtualization_name() {
260 VirtualizationType vrt = VM_Version::get_detected_virtualization();
261 if (vrt == XenHVM) {
262 return "Xen hardware-assisted virtualization";
263 } else if (vrt == KVM) {
264 return "KVM virtualization";
265 } else if (vrt == VMWare) {
266 return "VMWare virtualization";
267 } else if (vrt == HyperV) {
268 return "HyperV virtualization";
269 } else if (vrt == PowerVM) {
270 return "PowerVM virtualization";
271 } else if (vrt == PowerKVM) {
272 return "Power KVM virtualization";
273 } else if (vrt == PowerFullPartitionMode) {
274 return "Power full partition";
275 }
276
277 return "No virtualization detected";
278}
279
280int JfrOSInterface::generate_initial_environment_variable_events() {
281 if (environ == NULL) {
282 return OS_ERR;
283 }
284
285 if (EventInitialEnvironmentVariable::is_enabled()) {
286 // One time stamp for all events, so they can be grouped together
287 JfrTicks time_stamp = JfrTicks::now();
288 for (char** p = environ; *p != NULL; p++) {
289 char* variable = *p;
290 char* equal_sign = strchr(variable, '=');
291 if (equal_sign != NULL) {
292 // Extract key/value
293 ResourceMark rm;
294 ptrdiff_t key_length = equal_sign - variable;
295 char* key = NEW_RESOURCE_ARRAY(char, key_length + 1);
296 char* value = equal_sign + 1;
297 strncpy(key, variable, key_length);
298 key[key_length] = '\0';
299 EventInitialEnvironmentVariable event(UNTIMED);
300 event.set_endtime(time_stamp);
301 event.set_key(key);
302 event.set_value(value);
303 event.commit();
304 }
305 }
306 }
307 return OS_OK;
308}
309
310int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) {
311 return instance()._impl->system_processes(sys_processes, no_of_sys_processes);
312}
313
314int JfrOSInterface::network_utilization(NetworkInterface** network_interfaces) {
315 return instance()._impl->network_utilization(network_interfaces);
316}
317