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 
  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
  42 extern char** environ;
  43 #endif
  44 
  45 static JfrOSInterface* _instance = NULL;
  46 
  47 JfrOSInterface& JfrOSInterface::instance() {
  48   return *_instance;
  49 }
  50 
  51 JfrOSInterface* JfrOSInterface::create() {
  52   assert(_instance == NULL, "invariant");
  53   _instance = new JfrOSInterface();
  54   return _instance;
  55 }
  56 
  57 void JfrOSInterface::destroy() {
  58   JfrNetworkUtilization::destroy();
  59   if (_instance != NULL) {
  60     delete _instance;
  61     _instance = NULL;
  62   }
  63 }
  64 
  65 class 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   // stub helper
  74   void functionality_not_implemented(char** str) const;
  75 
  76   JfrOSInterfaceImpl();
  77   bool initialize();
  78   ~JfrOSInterfaceImpl();
  79 
  80   // cpu info
  81   int cpu_information(CPUInformation& cpu_info);
  82   int cpu_load(int which_logical_cpu, double* cpu_load);
  83   int context_switch_rate(double* rate);
  84   int cpu_load_total_process(double* cpu_load);
  85   int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotal);
  86 
  87   // os information
  88   int os_version(char** os_version) const;
  89 
  90   // environment information
  91   void generate_environment_variables_events();
  92 
  93    // system processes information
  94   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
  95 
  96   int network_utilization(NetworkInterface** network_interfaces) const;
  97 };
  98 
  99 JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL),
 100                                                            _cpu_perf_interface(NULL),
 101                                                            _system_process_interface(NULL) {}
 102 
 103 bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
 104   _cpu_info_interface = new CPUInformationInterface();
 105   if (!(_cpu_info_interface != NULL && _cpu_info_interface->initialize())) {
 106     return false;
 107   }
 108   _cpu_perf_interface = new CPUPerformanceInterface();
 109   if (!(_cpu_perf_interface != NULL && _cpu_perf_interface->initialize())) {
 110     return false;
 111   }
 112   _system_process_interface = new SystemProcessInterface();
 113   if (!(_system_process_interface != NULL && _system_process_interface->initialize())) {
 114     return false;
 115   }
 116   _network_performance_interface = new NetworkPerformanceInterface();
 117   return _network_performance_interface != NULL && _network_performance_interface->initialize();
 118 }
 119 
 120 JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
 121   if (_cpu_info_interface != NULL) {
 122     delete _cpu_info_interface;
 123     _cpu_info_interface = NULL;
 124   }
 125   if (_cpu_perf_interface != NULL) {
 126     delete _cpu_perf_interface;
 127     _cpu_perf_interface = NULL;
 128   }
 129   if (_system_process_interface != NULL) {
 130     delete _system_process_interface;
 131     _system_process_interface = NULL;
 132   }
 133   if (_network_performance_interface != NULL) {
 134     delete _network_performance_interface;
 135     _network_performance_interface = NULL;
 136   }
 137 }
 138 
 139 int JfrOSInterface::JfrOSInterfaceImpl::cpu_load(int which_logical_cpu, double* cpu_load) {
 140   return _cpu_perf_interface->cpu_load(which_logical_cpu, cpu_load);
 141 }
 142 
 143 int JfrOSInterface::JfrOSInterfaceImpl::context_switch_rate(double* rate) {
 144   return _cpu_perf_interface->context_switch_rate(rate);
 145 }
 146 
 147 int JfrOSInterface::JfrOSInterfaceImpl::cpu_load_total_process(double* cpu_load) {
 148   return _cpu_perf_interface->cpu_load_total_process(cpu_load);
 149 }
 150 
 151 int JfrOSInterface::JfrOSInterfaceImpl::cpu_loads_process(double* pjvmUserLoad,
 152                                                           double* pjvmKernelLoad,
 153                                                           double* psystemTotal) {
 154   return _cpu_perf_interface->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotal);
 155 }
 156 
 157 int JfrOSInterface::JfrOSInterfaceImpl::cpu_information(CPUInformation& cpu_info) {
 158   return _cpu_info_interface->cpu_information(cpu_info);
 159 }
 160 
 161 int JfrOSInterface::JfrOSInterfaceImpl::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) {
 162   assert(system_processes != NULL, "system_processes pointer is NULL!");
 163   assert(no_of_sys_processes != NULL, "no_of_sys_processes pointer is NULL!");
 164   return _system_process_interface->system_processes(system_processes, no_of_sys_processes);
 165 }
 166 
 167 int JfrOSInterface::JfrOSInterfaceImpl::network_utilization(NetworkInterface** network_interfaces) const {
 168   return _network_performance_interface->network_utilization(network_interfaces);
 169 }
 170 
 171 // assigned char* is RESOURCE_HEAP_ALLOCATED
 172 // caller need to ensure proper ResourceMark placement.
 173 int JfrOSInterface::JfrOSInterfaceImpl::os_version(char** os_version) const {
 174   assert(os_version != NULL, "os_version pointer is NULL!");
 175   stringStream os_ver_info;
 176   os::print_os_info_brief(&os_ver_info);
 177   *os_version = os_ver_info.as_string();
 178   return OS_OK;
 179 }
 180 
 181 void JfrOSInterface::JfrOSInterfaceImpl::functionality_not_implemented(char** str) const {
 182   assert(str != NULL, "address to string is NULL!");
 183   const char* not_impl = "Functionality_not_implemented";
 184   const size_t not_impl_len = strlen(not_impl);
 185   *str = NEW_C_HEAP_ARRAY(char, not_impl_len+1, mtTracing);
 186   strncpy(*str, not_impl, not_impl_len);
 187   (*str)[not_impl_len] = '\0';
 188 }
 189 
 190 JfrOSInterface::JfrOSInterface() {
 191   _impl = NULL;
 192 }
 193 
 194 bool JfrOSInterface::initialize() {
 195   _impl = new JfrOSInterface::JfrOSInterfaceImpl();
 196   return _impl != NULL && _impl->initialize();
 197 }
 198 
 199 JfrOSInterface::~JfrOSInterface() {
 200   if (_impl != NULL) {
 201     delete _impl;
 202     _impl = NULL;
 203   }
 204 }
 205 
 206 int JfrOSInterface::cpu_information(CPUInformation& cpu_info) {
 207   return instance()._impl->cpu_information(cpu_info);
 208 }
 209 
 210 int JfrOSInterface::cpu_load(int which_logical_cpu, double* cpu_load) {
 211   return instance()._impl->cpu_load(which_logical_cpu, cpu_load);
 212 }
 213 
 214 int JfrOSInterface::context_switch_rate(double* rate) {
 215   return instance()._impl->context_switch_rate(rate);
 216 }
 217 
 218 int JfrOSInterface::cpu_load_total_process(double* cpu_load) {
 219   return instance()._impl->cpu_load_total_process(cpu_load);
 220 }
 221 
 222 int JfrOSInterface::cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* system_total_load){
 223   return instance()._impl->cpu_loads_process(jvm_user_load, jvm_kernel_load, system_total_load);
 224 }
 225 
 226 int JfrOSInterface::os_version(char** os_version) {
 227   return instance()._impl->os_version(os_version);
 228 }
 229 
 230 int JfrOSInterface::generate_initial_environment_variable_events() {
 231   if (environ == NULL) {
 232     return OS_ERR;
 233   }
 234 
 235   if (EventInitialEnvironmentVariable::is_enabled()) {
 236     // One time stamp for all events, so they can be grouped together
 237     JfrTicks time_stamp = JfrTicks::now();
 238     for (char** p = environ; *p != NULL; p++) {
 239       char* variable = *p;
 240       char* equal_sign = strchr(variable, '=');
 241       if (equal_sign != NULL) {
 242         // Extract key/value
 243         ResourceMark rm;
 244         ptrdiff_t key_length = equal_sign - variable;
 245         char* key = NEW_RESOURCE_ARRAY(char, key_length + 1);
 246         char* value = equal_sign + 1;
 247         strncpy(key, variable, key_length);
 248         key[key_length] = '\0';
 249         EventInitialEnvironmentVariable event(UNTIMED);
 250         event.set_endtime(time_stamp);
 251         event.set_key(key);
 252         event.set_value(value);
 253         event.commit();
 254       }
 255     }
 256   }
 257   return OS_OK;
 258 }
 259 
 260 int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) {
 261   return instance()._impl->system_processes(sys_processes, no_of_sys_processes);
 262 }
 263 
 264 int JfrOSInterface::network_utilization(NetworkInterface** network_interfaces) {
 265   return instance()._impl->network_utilization(network_interfaces);
 266 }