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