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