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 }