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