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