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