1 /*
   2  * Copyright (c) 2001, 2011, 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 "classfile/systemDictionary.hpp"
  27 #include "classfile/vmSymbols.hpp"
  28 #include "memory/allocation.inline.hpp"
  29 #include "memory/resourceArea.hpp"
  30 #include "oops/oop.inline.hpp"
  31 #include "runtime/arguments.hpp"
  32 #include "runtime/java.hpp"
  33 #include "runtime/javaCalls.hpp"
  34 #include "runtime/os.hpp"
  35 #include "runtime/statSampler.hpp"
  36 #ifdef TARGET_ARCH_x86
  37 # include "vm_version_x86.hpp"
  38 #endif
  39 #ifdef TARGET_ARCH_aarch64
  40 # include "vm_version_aarch64.hpp"
  41 #endif
  42 #ifdef TARGET_ARCH_sparc
  43 # include "vm_version_sparc.hpp"
  44 #endif
  45 #ifdef TARGET_ARCH_zero
  46 # include "vm_version_zero.hpp"
  47 #endif
  48 #ifdef TARGET_ARCH_arm
  49 # include "vm_version_arm.hpp"
  50 #endif
  51 #ifdef TARGET_ARCH_ppc
  52 # include "vm_version_ppc.hpp"
  53 #endif
  54 
  55 // --------------------------------------------------------
  56 // StatSamplerTask
  57 
  58 class StatSamplerTask : public PeriodicTask {
  59   public:
  60     StatSamplerTask(int interval_time) : PeriodicTask(interval_time) {}
  61     void task() { StatSampler::collect_sample(); }
  62 };
  63 
  64 
  65 //----------------------------------------------------------
  66 // Implementation of StatSampler
  67 
  68 StatSamplerTask*              StatSampler::_task   = NULL;
  69 PerfDataList*                 StatSampler::_sampled = NULL;
  70 
  71 /*
  72  * the initialize method is called from the engage() method
  73  * and is responsible for initializing various global variables.
  74  */
  75 void StatSampler::initialize() {
  76 
  77   if (!UsePerfData) return;
  78 
  79   // create performance data that could not be created prior
  80   // to vm_init_globals() or otherwise have no logical home.
  81 
  82   create_misc_perfdata();
  83 
  84   // get copy of the sampled list
  85   _sampled = PerfDataManager::sampled();
  86 
  87 }
  88 
  89 /*
  90  * The engage() method is called at initialization time via
  91  * Thread::create_vm() to initialize the StatSampler and
  92  * register it with the WatcherThread as a periodic task.
  93  */
  94 void StatSampler::engage() {
  95 
  96   if (!UsePerfData) return;
  97 
  98   if (!is_active()) {
  99 
 100     initialize();
 101 
 102     // start up the periodic task
 103     _task = new StatSamplerTask(PerfDataSamplingInterval);
 104     _task->enroll();
 105   }
 106 }
 107 
 108 
 109 /*
 110  * the disengage() method is responsible for deactivating the periodic
 111  * task and, if logging was enabled, for logging the final sample. This
 112  * method is called from before_exit() in java.cpp and is only called
 113  * after the WatcherThread has been stopped.
 114  */
 115 void StatSampler::disengage() {
 116 
 117   if (!UsePerfData) return;
 118 
 119   if (!is_active())
 120     return;
 121 
 122   // remove StatSamplerTask
 123   _task->disenroll();
 124   delete _task;
 125   _task = NULL;
 126 
 127   // force a final sample
 128   sample_data(_sampled);
 129 }
 130 
 131 /*
 132  * the destroy method is responsible for releasing any resources used by
 133  * the StatSampler prior to shutdown of the VM. this method is called from
 134  * before_exit() in java.cpp and is only called after the WatcherThread
 135  * has stopped.
 136  */
 137 void StatSampler::destroy() {
 138 
 139   if (!UsePerfData) return;
 140 
 141   if (_sampled != NULL) {
 142     delete(_sampled);
 143     _sampled = NULL;
 144   }
 145 }
 146 
 147 /*
 148  * The sample_data() method is responsible for sampling the
 149  * the data value for each PerfData instance in the given list.
 150  */
 151 void StatSampler::sample_data(PerfDataList* list) {
 152 
 153   assert(list != NULL, "null list unexpected");
 154 
 155   for (int index = 0; index < list->length(); index++) {
 156     PerfData* item = list->at(index);
 157     item->sample();
 158   }
 159 }
 160 
 161 /*
 162  * the collect_sample() method is the method invoked by the
 163  * WatcherThread via the PeriodicTask::task() method. This method
 164  * is responsible for collecting data samples from sampled
 165  * PerfData instances every PerfDataSamplingInterval milliseconds.
 166  * It is also responsible for logging the requested set of
 167  * PerfData instances every _sample_count milliseconds. While
 168  * logging data, it will output a column header after every _print_header
 169  * rows of data have been logged.
 170  */
 171 void StatSampler::collect_sample() {
 172 
 173   // future - check for new PerfData objects. PerfData objects might
 174   // get added to the PerfDataManager lists after we have already
 175   // built our local copies.
 176   //
 177   // if (PerfDataManager::count() > previous) {
 178   //   // get a new copy of the sampled list
 179   //   if (_sampled != NULL) {
 180   //     delete(_sampled);
 181   //     _sampled = NULL;
 182   //   }
 183   //   _sampled = PerfDataManager::sampled();
 184   // }
 185 
 186   assert(_sampled != NULL, "list not initialized");
 187 
 188   sample_data(_sampled);
 189 }
 190 
 191 /*
 192  * method to upcall into Java to return the value of the specified
 193  * property as a utf8 string, or NULL if does not exist. The caller
 194  * is responsible for setting a ResourceMark for proper cleanup of
 195  * the utf8 strings.
 196  */
 197 const char* StatSampler::get_system_property(const char* name, TRAPS) {
 198 
 199   // setup the arguments to getProperty
 200   Handle key_str   = java_lang_String::create_from_str(name, CHECK_NULL);
 201 
 202   // return value
 203   JavaValue result(T_OBJECT);
 204 
 205   // public static String getProperty(String key, String def);
 206   JavaCalls::call_static(&result,
 207                          KlassHandle(THREAD, SystemDictionary::System_klass()),
 208                          vmSymbols::getProperty_name(),
 209                          vmSymbols::string_string_signature(),
 210                          key_str,
 211                          CHECK_NULL);
 212 
 213   oop value_oop = (oop)result.get_jobject();
 214   if (value_oop == NULL) {
 215     return NULL;
 216   }
 217 
 218   // convert Java String to utf8 string
 219   char* value = java_lang_String::as_utf8_string(value_oop);
 220 
 221   return value;
 222 }
 223 
 224 /*
 225  * The list of System Properties that have corresponding PerfData
 226  * string instrumentation created by retrieving the named property's
 227  * value from System.getProperty() and unconditionally creating a
 228  * PerfStringConstant object initialized to the retreived value. This
 229  * is not an exhustive list of Java properties with corresponding string
 230  * instrumentation as the create_system_property_instrumentation() method
 231  * creates other property based instrumentation conditionally.
 232  */
 233 
 234 // stable interface, supported counters
 235 static const char* property_counters_ss[] = {
 236   "java.vm.specification.version",
 237   "java.vm.specification.name",
 238   "java.vm.specification.vendor",
 239   "java.vm.version",
 240   "java.vm.name",
 241   "java.vm.vendor",
 242   "java.vm.info",
 243   "java.library.path",
 244   "java.class.path",
 245   "java.endorsed.dirs",
 246   "java.ext.dirs",
 247   "java.version",
 248   "java.home",
 249   NULL
 250 };
 251 
 252 // unstable interface, supported counters
 253 static const char* property_counters_us[] = {
 254   NULL
 255 };
 256 
 257 // unstable interface, unsupported counters
 258 static const char* property_counters_uu[] = {
 259   "sun.boot.class.path",
 260   "sun.boot.library.path",
 261   NULL
 262 };
 263 
 264 typedef struct {
 265   const char** property_list;
 266   CounterNS name_space;
 267 } PropertyCounters;
 268 
 269 static PropertyCounters property_counters[] = {
 270   { property_counters_ss, JAVA_PROPERTY },
 271   { property_counters_us, COM_PROPERTY },
 272   { property_counters_uu, SUN_PROPERTY },
 273   { NULL, SUN_PROPERTY }
 274 };
 275 
 276 
 277 /*
 278  * Method to create PerfData string instruments that contain the values
 279  * of various system properties. String instruments are created for each
 280  * property specified in the property lists provided in property_counters[].
 281  * Property counters have a counter name space prefix prepended to the
 282  * property name as indicated in property_counters[].
 283  */
 284 void StatSampler::create_system_property_instrumentation(TRAPS) {
 285 
 286   ResourceMark rm;
 287 
 288   for (int i = 0; property_counters[i].property_list != NULL; i++) {
 289 
 290     for (int j = 0; property_counters[i].property_list[j] != NULL; j++) {
 291 
 292       const char* property_name = property_counters[i].property_list[j];
 293       assert(property_name != NULL, "property name should not be NULL");
 294 
 295       const char* value = get_system_property(property_name, CHECK);
 296 
 297       // the property must exist
 298       assert(value != NULL, "property name should be valid");
 299 
 300       if (value != NULL) {
 301         // create the property counter
 302         PerfDataManager::create_string_constant(property_counters[i].name_space,
 303                                                 property_name, value, CHECK);
 304       }
 305     }
 306   }
 307 }
 308 
 309 /*
 310  * The create_misc_perfdata() method provides a place to create
 311  * PerfData instances that would otherwise have no better place
 312  * to exist.
 313  */
 314 void StatSampler::create_misc_perfdata() {
 315 
 316   ResourceMark rm;
 317   EXCEPTION_MARK;
 318 
 319   // numeric constants
 320 
 321   // frequency of the native high resolution timer
 322   PerfDataManager::create_constant(SUN_OS, "hrt.frequency",
 323                                    PerfData::U_Hertz, os::elapsed_frequency(),
 324                                    CHECK);
 325 
 326   // string constants
 327 
 328   // create string instrumentation for various Java properties.
 329   create_system_property_instrumentation(CHECK);
 330 
 331   // hotspot flags (from .hotspotrc) and args (from command line)
 332   //
 333   PerfDataManager::create_string_constant(JAVA_RT, "vmFlags",
 334                                           Arguments::jvm_flags(), CHECK);
 335   PerfDataManager::create_string_constant(JAVA_RT, "vmArgs",
 336                                           Arguments::jvm_args(), CHECK);
 337 
 338   // java class name/jar file and arguments to main class
 339   // note: name is cooridnated with launcher and Arguments.cpp
 340   PerfDataManager::create_string_constant(SUN_RT, "javaCommand",
 341                                           Arguments::java_command(), CHECK);
 342 
 343   // the Java VM Internal version string
 344   PerfDataManager::create_string_constant(SUN_RT, "internalVersion",
 345                                          VM_Version::internal_vm_info_string(),
 346                                          CHECK);
 347 
 348   // create sampled instrumentation objects
 349   create_sampled_perfdata();
 350 }
 351 
 352 /*
 353  * helper class to provide for sampling of the elapsed_counter value
 354  * maintained in the OS class.
 355  */
 356 class HighResTimeSampler : public PerfSampleHelper {
 357   public:
 358     jlong take_sample() { return os::elapsed_counter(); }
 359 };
 360 
 361 /*
 362  * the create_sampled_perdata() method provides a place to instantiate
 363  * sampled PerfData instances that would otherwise have no better place
 364  * to exist.
 365  */
 366 void StatSampler::create_sampled_perfdata() {
 367 
 368   EXCEPTION_MARK;
 369 
 370   // setup sampling of the elapsed time counter maintained in the
 371   // the os class. This counter can be used as either a time stamp
 372   // for each logged entry or as a liveness indicator for the VM.
 373   PerfSampleHelper* psh = new HighResTimeSampler();
 374   PerfDataManager::create_counter(SUN_OS, "hrt.ticks",
 375                                   PerfData::U_Ticks, psh, CHECK);
 376 }
 377 
 378 /*
 379  * the statSampler_exit() function is called from os_init.cpp on
 380  * exit of the vm.
 381  */
 382 void statSampler_exit() {
 383 
 384   if (!UsePerfData) return;
 385 
 386   StatSampler::destroy();
 387 }