duke@435: /* xdono@772: * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: # include "incls/_precompiled.incl" duke@435: # include "incls/_statSampler.cpp.incl" duke@435: duke@435: // -------------------------------------------------------- duke@435: // StatSamplerTask duke@435: duke@435: class StatSamplerTask : public PeriodicTask { duke@435: public: duke@435: StatSamplerTask(int interval_time) : PeriodicTask(interval_time) {} duke@435: void task() { StatSampler::collect_sample(); } duke@435: }; duke@435: duke@435: duke@435: //---------------------------------------------------------- duke@435: // Implementation of StatSampler duke@435: duke@435: StatSamplerTask* StatSampler::_task = NULL; duke@435: PerfDataList* StatSampler::_sampled = NULL; duke@435: duke@435: /* duke@435: * the initialize method is called from the engage() method duke@435: * and is responsible for initializing various global variables. duke@435: */ duke@435: void StatSampler::initialize() { duke@435: duke@435: if (!UsePerfData) return; duke@435: duke@435: // create performance data that could not be created prior duke@435: // to vm_init_globals() or otherwise have no logical home. duke@435: duke@435: create_misc_perfdata(); duke@435: duke@435: // get copy of the sampled list duke@435: _sampled = PerfDataManager::sampled(); duke@435: duke@435: } duke@435: duke@435: /* duke@435: * The engage() method is called at initialization time via duke@435: * Thread::create_vm() to initialize the StatSampler and duke@435: * register it with the WatcherThread as a periodic task. duke@435: */ duke@435: void StatSampler::engage() { duke@435: duke@435: if (!UsePerfData) return; duke@435: duke@435: if (!is_active()) { duke@435: duke@435: initialize(); duke@435: duke@435: // start up the periodic task duke@435: _task = new StatSamplerTask(PerfDataSamplingInterval); duke@435: _task->enroll(); duke@435: } duke@435: } duke@435: duke@435: duke@435: /* duke@435: * the disengage() method is responsible for deactivating the periodic duke@435: * task and, if logging was enabled, for logging the final sample. This duke@435: * method is called from before_exit() in java.cpp and is only called duke@435: * after the WatcherThread has been stopped. duke@435: */ duke@435: void StatSampler::disengage() { duke@435: duke@435: if (!UsePerfData) return; duke@435: duke@435: if (!is_active()) duke@435: return; duke@435: duke@435: // remove StatSamplerTask duke@435: _task->disenroll(); duke@435: delete _task; duke@435: _task = NULL; duke@435: duke@435: // force a final sample duke@435: sample_data(_sampled); duke@435: } duke@435: duke@435: /* duke@435: * the destroy method is responsible for releasing any resources used by duke@435: * the StatSampler prior to shutdown of the VM. this method is called from duke@435: * before_exit() in java.cpp and is only called after the WatcherThread duke@435: * has stopped. duke@435: */ duke@435: void StatSampler::destroy() { duke@435: duke@435: if (!UsePerfData) return; duke@435: duke@435: if (_sampled != NULL) { duke@435: delete(_sampled); duke@435: _sampled = NULL; duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * The sample_data() method is responsible for sampling the duke@435: * the data value for each PerfData instance in the given list. duke@435: */ duke@435: void StatSampler::sample_data(PerfDataList* list) { duke@435: duke@435: assert(list != NULL, "null list unexpected"); duke@435: duke@435: for (int index = 0; index < list->length(); index++) { duke@435: PerfData* item = list->at(index); duke@435: item->sample(); duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * the collect_sample() method is the method invoked by the duke@435: * WatcherThread via the PeriodicTask::task() method. This method duke@435: * is responsible for collecting data samples from sampled duke@435: * PerfData instances every PerfDataSamplingInterval milliseconds. duke@435: * It is also responsible for logging the requested set of duke@435: * PerfData instances every _sample_count milliseconds. While duke@435: * logging data, it will output a column header after every _print_header duke@435: * rows of data have been logged. duke@435: */ duke@435: void StatSampler::collect_sample() { duke@435: duke@435: // future - check for new PerfData objects. PerfData objects might duke@435: // get added to the PerfDataManager lists after we have already duke@435: // built our local copies. duke@435: // duke@435: // if (PerfDataManager::count() > previous) { duke@435: // // get a new copy of the sampled list duke@435: // if (_sampled != NULL) { duke@435: // delete(_sampled); duke@435: // _sampled = NULL; duke@435: // } duke@435: // _sampled = PerfDataManager::sampled(); duke@435: // } duke@435: duke@435: assert(_sampled != NULL, "list not initialized"); duke@435: duke@435: sample_data(_sampled); duke@435: } duke@435: duke@435: /* duke@435: * method to upcall into Java to return the value of the specified duke@435: * property as a utf8 string, or NULL if does not exist. The caller duke@435: * is responsible for setting a ResourceMark for proper cleanup of duke@435: * the utf8 strings. duke@435: */ duke@435: const char* StatSampler::get_system_property(const char* name, TRAPS) { duke@435: duke@435: // setup the arguments to getProperty duke@435: Handle key_str = java_lang_String::create_from_str(name, CHECK_NULL); duke@435: duke@435: // return value duke@435: JavaValue result(T_OBJECT); duke@435: duke@435: // public static String getProperty(String key, String def); duke@435: JavaCalls::call_static(&result, never@1577: KlassHandle(THREAD, SystemDictionary::System_klass()), duke@435: vmSymbolHandles::getProperty_name(), duke@435: vmSymbolHandles::string_string_signature(), duke@435: key_str, duke@435: CHECK_NULL); duke@435: duke@435: oop value_oop = (oop)result.get_jobject(); duke@435: if (value_oop == NULL) { duke@435: return NULL; duke@435: } duke@435: duke@435: // convert Java String to utf8 string duke@435: char* value = java_lang_String::as_utf8_string(value_oop); duke@435: duke@435: return value; duke@435: } duke@435: duke@435: /* duke@435: * The list of System Properties that have corresponding PerfData duke@435: * string instrumentation created by retrieving the named property's duke@435: * value from System.getProperty() and unconditionally creating a duke@435: * PerfStringConstant object initialized to the retreived value. This duke@435: * is not an exhustive list of Java properties with corresponding string duke@435: * instrumentation as the create_system_property_instrumentation() method duke@435: * creates other property based instrumentation conditionally. duke@435: */ duke@435: duke@435: // stable interface, supported counters duke@435: static const char* property_counters_ss[] = { duke@435: "java.vm.specification.version", duke@435: "java.vm.specification.name", duke@435: "java.vm.specification.vendor", duke@435: "java.vm.version", duke@435: "java.vm.name", duke@435: "java.vm.vendor", duke@435: "java.vm.info", duke@435: "java.library.path", duke@435: "java.class.path", duke@435: "java.endorsed.dirs", duke@435: "java.ext.dirs", thurka@714: "java.version", duke@435: "java.home", duke@435: NULL duke@435: }; duke@435: duke@435: // unstable interface, supported counters duke@435: static const char* property_counters_us[] = { duke@435: NULL duke@435: }; duke@435: duke@435: // unstable interface, unsupported counters duke@435: static const char* property_counters_uu[] = { duke@435: "sun.boot.class.path", duke@435: "sun.boot.library.path", duke@435: NULL duke@435: }; duke@435: duke@435: typedef struct { duke@435: const char** property_list; duke@435: CounterNS name_space; duke@435: } PropertyCounters; duke@435: duke@435: static PropertyCounters property_counters[] = { duke@435: { property_counters_ss, JAVA_PROPERTY }, duke@435: { property_counters_us, COM_PROPERTY }, duke@435: { property_counters_uu, SUN_PROPERTY }, duke@435: { NULL, SUN_PROPERTY } duke@435: }; duke@435: duke@435: duke@435: /* duke@435: * Method to create PerfData string instruments that contain the values duke@435: * of various system properties. String instruments are created for each duke@435: * property specified in the property lists provided in property_counters[]. duke@435: * Property counters have a counter name space prefix prepended to the duke@435: * property name as indicated in property_counters[]. duke@435: */ duke@435: void StatSampler::create_system_property_instrumentation(TRAPS) { duke@435: duke@435: ResourceMark rm; duke@435: duke@435: for (int i = 0; property_counters[i].property_list != NULL; i++) { duke@435: duke@435: for (int j = 0; property_counters[i].property_list[j] != NULL; j++) { duke@435: duke@435: const char* property_name = property_counters[i].property_list[j]; duke@435: assert(property_name != NULL, "property name should not be NULL"); duke@435: duke@435: const char* value = get_system_property(property_name, CHECK); duke@435: duke@435: // the property must exist duke@435: assert(value != NULL, "property name should be valid"); duke@435: duke@435: if (value != NULL) { duke@435: // create the property counter duke@435: PerfDataManager::create_string_constant(property_counters[i].name_space, duke@435: property_name, value, CHECK); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * The create_misc_perfdata() method provides a place to create duke@435: * PerfData instances that would otherwise have no better place duke@435: * to exist. duke@435: */ duke@435: void StatSampler::create_misc_perfdata() { duke@435: duke@435: ResourceMark rm; duke@435: EXCEPTION_MARK; duke@435: duke@435: // numeric constants duke@435: duke@435: // frequency of the native high resolution timer duke@435: PerfDataManager::create_constant(SUN_OS, "hrt.frequency", duke@435: PerfData::U_Hertz, os::elapsed_frequency(), duke@435: CHECK); duke@435: duke@435: // string constants duke@435: duke@435: // create string instrumentation for various Java properties. duke@435: create_system_property_instrumentation(CHECK); duke@435: duke@435: // hotspot flags (from .hotspotrc) and args (from command line) duke@435: // duke@435: PerfDataManager::create_string_constant(JAVA_RT, "vmFlags", duke@435: Arguments::jvm_flags(), CHECK); duke@435: PerfDataManager::create_string_constant(JAVA_RT, "vmArgs", duke@435: Arguments::jvm_args(), CHECK); duke@435: duke@435: // java class name/jar file and arguments to main class duke@435: // note: name is cooridnated with launcher and Arguments.cpp duke@435: PerfDataManager::create_string_constant(SUN_RT, "javaCommand", duke@435: Arguments::java_command(), CHECK); duke@435: duke@435: // the Java VM Internal version string duke@435: PerfDataManager::create_string_constant(SUN_RT, "internalVersion", duke@435: VM_Version::internal_vm_info_string(), duke@435: CHECK); duke@435: duke@435: // create sampled instrumentation objects duke@435: create_sampled_perfdata(); duke@435: } duke@435: duke@435: /* duke@435: * helper class to provide for sampling of the elapsed_counter value duke@435: * maintained in the OS class. duke@435: */ duke@435: class HighResTimeSampler : public PerfSampleHelper { duke@435: public: duke@435: jlong take_sample() { return os::elapsed_counter(); } duke@435: }; duke@435: duke@435: /* duke@435: * the create_sampled_perdata() method provides a place to instantiate duke@435: * sampled PerfData instances that would otherwise have no better place duke@435: * to exist. duke@435: */ duke@435: void StatSampler::create_sampled_perfdata() { duke@435: duke@435: EXCEPTION_MARK; duke@435: duke@435: // setup sampling of the elapsed time counter maintained in the duke@435: // the os class. This counter can be used as either a time stamp duke@435: // for each logged entry or as a liveness indicator for the VM. duke@435: PerfSampleHelper* psh = new HighResTimeSampler(); duke@435: PerfDataManager::create_counter(SUN_OS, "hrt.ticks", duke@435: PerfData::U_Ticks, psh, CHECK); duke@435: } duke@435: duke@435: /* duke@435: * the statSampler_exit() function is called from os_init.cpp on duke@435: * exit of the vm. duke@435: */ duke@435: void statSampler_exit() { duke@435: duke@435: if (!UsePerfData) return; duke@435: duke@435: StatSampler::destroy(); duke@435: }