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