8241678: Remove PerfData sampling via StatSampler

Reviewed-by: jsjolen, ayang
This commit is contained in:
Casper Norrbin 2025-05-28 12:00:15 +00:00 committed by Albert Mingkun Yang
parent f30e15411f
commit 6ebae6cded
25 changed files with 210 additions and 715 deletions

View File

@ -58,7 +58,6 @@
#include "runtime/perfMemory.hpp"
#include "runtime/safefetch.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/threads.hpp"
#include "runtime/timer.hpp"
#include "runtime/vm_version.hpp"

View File

@ -53,7 +53,6 @@
#include "runtime/perfMemory.hpp"
#include "runtime/semaphore.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/threads.hpp"
#include "runtime/timer.hpp"

View File

@ -56,7 +56,6 @@
#include "runtime/osThread.hpp"
#include "runtime/perfMemory.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/threads.hpp"
#include "runtime/threadSMR.hpp"

View File

@ -60,7 +60,6 @@
#include "runtime/safepointMechanism.hpp"
#include "runtime/semaphore.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/suspendedThreadTask.hpp"
#include "runtime/threads.hpp"

View File

@ -33,8 +33,7 @@
SpaceCounters::SpaceCounters(const char* name, int ordinal, size_t max_size,
MutableSpace* m, GenerationCounters* gc)
: _last_used_in_bytes(0), _object_space(m)
{
: _object_space(m) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
@ -60,7 +59,7 @@ SpaceCounters::SpaceCounters(const char* name, int ordinal, size_t max_size,
cname = PerfDataManager::counter_name(_name_space, "used");
_used = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
new UsedHelper(this),
_object_space->used_in_bytes(),
CHECK);
cname = PerfDataManager::counter_name(_name_space, "initCapacity");
@ -74,21 +73,5 @@ SpaceCounters::~SpaceCounters() {
}
void SpaceCounters::update_used() {
size_t new_used = _object_space->used_in_bytes();
Atomic::store(&_last_used_in_bytes, new_used);
_used->set_value(new_used);
}
jlong SpaceCounters::UsedHelper::take_sample() {
// Sampling may occur during GC, possibly while GC is updating the space.
// The space can be in an inconsistent state during such an update. We
// don't want to block sampling for the duration of a GC. Instead, skip
// sampling in that case, using the last recorded value.
assert(!Heap_lock->owned_by_self(), "precondition");
if (Heap_lock->try_lock()) {
size_t new_used = _counters->_object_space->used_in_bytes();
Atomic::store(&_counters->_last_used_in_bytes, new_used);
Heap_lock->unlock();
}
return Atomic::load(&_counters->_last_used_in_bytes);
_used->set_value(_object_space->used_in_bytes());
}

View File

@ -39,7 +39,6 @@ class SpaceCounters: public CHeapObj<mtGC> {
private:
PerfVariable* _capacity;
PerfVariable* _used;
volatile size_t _last_used_in_bytes;
// Constant PerfData types don't need to retain a reference.
// However, it's a good idea to document them here.
@ -48,8 +47,6 @@ class SpaceCounters: public CHeapObj<mtGC> {
MutableSpace* _object_space;
char* _name_space;
class UsedHelper;
public:
SpaceCounters(const char* name, int ordinal, size_t max_size,
@ -71,14 +68,4 @@ class SpaceCounters: public CHeapObj<mtGC> {
const char* name_space() const { return _name_space; }
};
class SpaceCounters::UsedHelper: public PerfLongSampleHelper {
private:
SpaceCounters* _counters;
public:
UsedHelper(SpaceCounters* counters) : _counters(counters) { }
jlong take_sample() override;
};
#endif // SHARE_GC_PARALLEL_SPACECOUNTERS_HPP

View File

@ -28,8 +28,7 @@
CSpaceCounters::CSpaceCounters(const char* name, int ordinal, size_t max_size,
ContiguousSpace* s, GenerationCounters* gc)
: _last_used_in_bytes(0), _space(s)
{
: _space(s) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
@ -57,7 +56,7 @@ CSpaceCounters::CSpaceCounters(const char* name, int ordinal, size_t max_size,
cname = PerfDataManager::counter_name(_name_space, "used");
_used = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
new UsedHelper(this),
_space->used(),
CHECK);
cname = PerfDataManager::counter_name(_name_space, "initCapacity");
@ -75,26 +74,10 @@ void CSpaceCounters::update_capacity() {
}
void CSpaceCounters::update_used() {
size_t new_used = _space->used();
Atomic::store(&_last_used_in_bytes, new_used);
_used->set_value(new_used);
_used->set_value(_space->used());
}
void CSpaceCounters::update_all() {
update_used();
update_capacity();
}
jlong CSpaceCounters::UsedHelper::take_sample(){
// Sampling may occur during GC, possibly while GC is updating the space.
// The space can be in an inconsistent state during such an update. We
// don't want to block sampling for the duration of a GC. Instead, skip
// sampling in that case, using the last recorded value.
assert(!Heap_lock->owned_by_self(), "precondition");
if (Heap_lock->try_lock()) {
size_t new_used = _counters->_space->used();
Atomic::store(&_counters->_last_used_in_bytes, new_used);
Heap_lock->unlock();
}
return Atomic::load(&_counters->_last_used_in_bytes);
}

View File

@ -39,7 +39,6 @@ class CSpaceCounters: public CHeapObj<mtGC> {
PerfVariable* _capacity;
PerfVariable* _used;
PerfVariable* _max_capacity;
volatile size_t _last_used_in_bytes;
// Constant PerfData types don't need to retain a reference.
// However, it's a good idea to document them here.
@ -48,8 +47,6 @@ class CSpaceCounters: public CHeapObj<mtGC> {
ContiguousSpace* _space;
char* _name_space;
class UsedHelper;
public:
CSpaceCounters(const char* name, int ordinal, size_t max_size,
@ -64,14 +61,4 @@ class CSpaceCounters: public CHeapObj<mtGC> {
const char* name_space() const { return _name_space; }
};
class CSpaceCounters::UsedHelper : public PerfLongSampleHelper {
private:
CSpaceCounters* _counters;
public:
UsedHelper(CSpaceCounters* counters) : _counters(counters) { }
jlong take_sample() override;
};
#endif // SHARE_GC_SERIAL_CSPACECOUNTERS_HPP

View File

@ -536,6 +536,7 @@ static SpecialFlag const special_jvm_flags[] = {
// -------------- Obsolete Flags - sorted by expired_in --------------
{ "PerfDataSamplingInterval", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::jdk(26) },
{ "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() },
{ "ZGenerational", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::undefined() },
{ "ZMarkStackSpaceLimit", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::undefined() },

View File

@ -1728,11 +1728,6 @@ const int ObjectAlignmentInBytes = 8;
"The string %p in the file name (if present) " \
"will be replaced by pid") \
\
product(int, PerfDataSamplingInterval, 50, \
"Data sampling interval (in milliseconds)") \
range(PeriodicTask::min_interval, max_jint) \
constraint(PerfDataSamplingIntervalFunc, AfterErgo) \
\
product(bool, PerfDisableSharedMem, false, \
"Store performance data in standard memory") \
\

View File

@ -70,7 +70,6 @@
#include "runtime/java.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/task.hpp"
#include "runtime/threads.hpp"
@ -470,10 +469,6 @@ void before_exit(JavaThread* thread, bool halt) {
// PeriodicTasks to reduce the likelihood of races.
WatcherThread::stop();
// shut down the StatSampler task
StatSampler::disengage();
StatSampler::destroy();
NativeHeapTrimmer::cleanup();
// Stop concurrent GC threads

View File

@ -27,8 +27,10 @@
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
@ -38,7 +40,6 @@
#include "utilities/globalDefinitions.hpp"
PerfDataList* PerfDataManager::_all = nullptr;
PerfDataList* PerfDataManager::_sampled = nullptr;
PerfDataList* PerfDataManager::_constants = nullptr;
volatile bool PerfDataManager::_has_PerfData = 0;
@ -198,20 +199,6 @@ PerfLong::PerfLong(CounterNS ns, const char* namep, Units u, Variability v)
create_entry(T_LONG, sizeof(jlong));
}
PerfLongVariant::PerfLongVariant(CounterNS ns, const char* namep, Units u,
Variability v, PerfLongSampleHelper* helper)
: PerfLong(ns, namep, u, v),
_sample_helper(helper) {
sample();
}
void PerfLongVariant::sample() {
if (_sample_helper != nullptr) {
*(jlong*)_valuep = _sample_helper->take_sample();
}
}
PerfByteArray::PerfByteArray(CounterNS ns, const char* namep, Units u,
Variability v, jint length)
: PerfData(ns, namep, u, v), _length(length) {
@ -266,8 +253,8 @@ void PerfDataManager::destroy() {
Atomic::store(&_has_PerfData, false);
GlobalCounter::write_synchronize();
log_debug(perf, datacreation)("Total = %d, Sampled = %d, Constants = %d",
_all->length(), _sampled == nullptr ? 0 : _sampled->length(),
log_debug(perf, datacreation)("Total = %d, Constants = %d",
_all->length(),
_constants == nullptr ? 0 : _constants->length());
for (int index = 0; index < _all->length(); index++) {
@ -276,15 +263,13 @@ void PerfDataManager::destroy() {
}
delete(_all);
delete(_sampled);
delete(_constants);
_all = nullptr;
_sampled = nullptr;
_constants = nullptr;
}
void PerfDataManager::add_item(PerfData* p, bool sampled) {
void PerfDataManager::add_item(PerfData* p) {
MutexLocker ml(PerfDataManager_lock);
@ -306,24 +291,6 @@ void PerfDataManager::add_item(PerfData* p, bool sampled) {
_constants->append(p);
return;
}
if (sampled) {
if (_sampled == nullptr) {
_sampled = new PerfDataList(1);
}
_sampled->append(p);
}
}
PerfDataList* PerfDataManager::sampled() {
MutexLocker ml(PerfDataManager_lock);
if (_sampled == nullptr)
return nullptr;
PerfDataList* clone = _sampled->clone();
return clone;
}
char* PerfDataManager::counter_name(const char* ns, const char* name) {
@ -362,7 +329,7 @@ PerfStringConstant* PerfDataManager::create_string_constant(CounterNS ns,
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, false);
add_item(p);
return p;
}
@ -380,7 +347,7 @@ PerfLongConstant* PerfDataManager::create_long_constant(CounterNS ns,
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, false);
add_item(p);
return p;
}
@ -403,7 +370,7 @@ PerfStringVariable* PerfDataManager::create_string_variable(CounterNS ns,
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, false);
add_item(p);
return p;
}
@ -421,29 +388,7 @@ PerfLongVariable* PerfDataManager::create_long_variable(CounterNS ns,
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, false);
return p;
}
PerfLongVariable* PerfDataManager::create_long_variable(CounterNS ns,
const char* name,
PerfData::Units u,
PerfSampleHelper* sh,
TRAPS) {
// Sampled counters not supported if UsePerfData is false
if (!UsePerfData) return nullptr;
PerfLongVariable* p = new PerfLongVariable(ns, name, u, sh);
if (!p->is_valid()) {
// allocation of native resources failed.
delete p;
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, true);
add_item(p);
return p;
}
@ -461,31 +406,133 @@ PerfLongCounter* PerfDataManager::create_long_counter(CounterNS ns,
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
}
add_item(p, false);
add_item(p);
return p;
}
PerfLongCounter* PerfDataManager::create_long_counter(CounterNS ns,
const char* name,
PerfData::Units u,
PerfSampleHelper* sh,
TRAPS) {
/*
* Call into java.lang.System.getProperty to check that the value of the
* specified property matches
*/
void PerfDataManager::assert_system_property(const char* name, const char* value, TRAPS) {
#ifdef ASSERT
ResourceMark rm(THREAD);
// Sampled counters not supported if UsePerfData is false
if (!UsePerfData) return nullptr;
// setup the arguments to getProperty
Handle key_str = java_lang_String::create_from_str(name, CHECK);
PerfLongCounter* p = new PerfLongCounter(ns, name, u, sh);
// return value
JavaValue result(T_OBJECT);
if (!p->is_valid()) {
// allocation of native resources failed.
delete p;
THROW_NULL(vmSymbols::java_lang_OutOfMemoryError());
// public static String getProperty(String key, String def);
JavaCalls::call_static(&result, vmClasses::System_klass(),
vmSymbols::getProperty_name(),
vmSymbols::string_string_signature(), key_str, CHECK);
oop value_oop = result.get_oop();
assert(value_oop != nullptr, "property must have a value");
// convert Java String to utf8 string
char *system_value = java_lang_String::as_utf8_string(value_oop);
assert(strcmp(value, system_value) == 0, "property value mustn't differ from System.getProperty. Our value is: %s, System.getProperty is: %s",
value, system_value);
#endif // ASSERT
}
/*
* Adds a constant counter of the given property. Asserts the value does not
* differ from the value retrievable from System.getProperty(name)
*/
void PerfDataManager::add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS) {
// the property must exist
assert(value != nullptr, "property name should be have a value: %s", name);
assert_system_property(name, value, CHECK);
// create the property counter
PerfDataManager::create_string_constant(name_space, name, value, CHECK);
}
/*
* Adds a string constant of the given property. Retrieves the value via
* Arguments::get_property() and asserts the value for the does not differ from
* the value retrievable from System.getProperty()
*/
void PerfDataManager::add_property_constant(CounterNS name_space, const char* name, TRAPS) {
add_property_constant(name_space, name, Arguments::get_property(name), CHECK);
}
/*
* Adds a string constant of the given property. Retrieves the value via
* Arguments::get_property() and asserts the value for the does not differ from
* the value retrievable from System.getProperty()
*/
void PerfDataManager::add_optional_property_constant(CounterNS name_space, const char* name, TRAPS) {
const char* value = Arguments::get_property(name);
if (value != nullptr) {
add_property_constant(name_space, name, value, CHECK);
}
}
add_item(p, true);
void PerfDataManager::create_system_property_instrumentation(TRAPS) {
return p;
// Non-writeable, constant properties
add_property_constant(JAVA_PROPERTY, "java.vm.specification.name", "Java Virtual Machine Specification", CHECK);
add_property_constant(JAVA_PROPERTY, "java.version", JDK_Version::java_version(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.version", VM_Version::vm_release(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.name", VM_Version::vm_name(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.vendor", VM_Version::vm_vendor(), CHECK);
add_property_constant(JAVA_PROPERTY, "jdk.debug", VM_Version::jdk_debug_level(), CHECK);
// Get remaining property constants via Arguments::get_property,
// which does a linear search over the internal system properties list.
// SUN_PROPERTY properties
add_property_constant(SUN_PROPERTY, "sun.boot.library.path", CHECK);
// JAVA_PROPERTY properties
add_property_constant(JAVA_PROPERTY, "java.vm.specification.version", CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.specification.vendor", CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.info", CHECK);
add_property_constant(JAVA_PROPERTY, "java.library.path", CHECK);
add_property_constant(JAVA_PROPERTY, "java.class.path", CHECK);
add_property_constant(JAVA_PROPERTY, "java.home", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.path", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.upgrade.path", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.main", CHECK);
}
void PerfDataManager::create_misc_perfdata() {
ResourceMark rm;
EXCEPTION_MARK;
// numeric constants
// frequency of the native high resolution timer
create_constant(SUN_OS, "hrt.frequency", PerfData::U_Hertz,
os::elapsed_frequency(), CHECK);
// string constants
// create string instrumentation for various Java properties.
create_system_property_instrumentation(CHECK);
// HotSpot flags (from .hotspotrc) and args (from command line)
//
create_string_constant(JAVA_RT, "vmFlags", Arguments::jvm_flags(), CHECK);
create_string_constant(JAVA_RT, "vmArgs", Arguments::jvm_args(), CHECK);
// java class name/jar file and arguments to main class
// note: name is coordinated with launcher and Arguments.cpp
create_string_constant(SUN_RT, "javaCommand", Arguments::java_command(), CHECK);
// the Java VM Internal version string
create_string_constant(SUN_RT, "internalVersion",
VM_Version::internal_vm_info_string(), CHECK);
}
PerfDataList::PerfDataList(int length) {

View File

@ -200,43 +200,10 @@ enum CounterNS {
* are not encouraged to access the string constant's value via this
* pointer at this time due to security concerns.
*
* Creating a performance counter in an arbitrary name space that holds a
* value that is sampled by the StatSampler periodic task.
*
* PerfDataManager::create_counter("foo.sampled", PerfData::U_Events,
* &my_jlong, CHECK);
*
* In this example, the PerfData pointer can be ignored as the caller
* is relying on the StatSampler PeriodicTask to sample the given
* address at a regular interval. The interval is defined by the
* PerfDataSamplingInterval global variable, and is applied on
* a system wide basis, not on an per-counter basis.
*
* Creating a performance counter in an arbitrary name space that utilizes
* a helper object to return a value to the StatSampler via the take_sample()
* method.
*
* class MyTimeSampler : public PerfLongSampleHelper {
* public:
* jlong take_sample() { return os::elapsed_counter(); }
* };
*
* PerfDataManager::create_counter(SUN_RT, "helped",
* PerfData::U_Ticks,
* new MyTimeSampler(), CHECK);
*
* In this example, a subtype of PerfLongSampleHelper is instantiated
* and its take_sample() method is overridden to perform whatever
* operation is necessary to generate the data sample. This method
* will be called by the StatSampler at a regular interval, defined
* by the PerfDataSamplingInterval global variable.
*
* As before, PerfSampleHelper is an alias for PerfLongSampleHelper.
*
* For additional uses of PerfData subtypes, see the utility classes
* PerfTraceTime and PerfTraceTimedEvent below.
*
* Always-on non-sampled counters can be created independent of
* Always-on counters can be created independent of
* the UsePerfData flag. Counters will be created on the c-heap
* if UsePerfData is false.
*
@ -260,7 +227,6 @@ enum CounterNS {
*/
class PerfData : public CHeapObj<mtInternal> {
friend class StatSampler; // for access to protected void sample()
friend class PerfDataManager; // for access to protected destructor
friend class VMStructs;
@ -314,10 +280,6 @@ class PerfData : public CHeapObj<mtInternal> {
// facilitate its use by external processes.
void create_entry(BasicType dtype, size_t dsize, size_t dlen = 0);
// sample the data item given at creation time and write its value
// into the its corresponding PerfMemory location.
virtual void sample() = 0;
public:
// returns a boolean indicating the validity of this object.
@ -352,17 +314,6 @@ class PerfData : public CHeapObj<mtInternal> {
inline void* get_address() { return _valuep; }
};
/*
* PerfLongSampleHelper, and its alias PerfSamplerHelper, is a base class
* for helper classes that rely upon the StatSampler periodic task to
* invoke the take_sample() method and write the value returned to its
* appropriate location in the PerfData memory region.
*/
class PerfLongSampleHelper : public CHeapObj<mtInternal> {
public:
virtual jlong take_sample() = 0;
};
/*
* PerfLong is the base class for the various Long PerfData subtypes.
* it contains implementation details that are common among its derived
@ -390,10 +341,6 @@ class PerfLongConstant : public PerfLong {
friend class PerfDataManager; // for access to protected constructor
private:
// hide sample() - no need to sample constants
void sample() { }
protected:
PerfLongConstant(CounterNS ns, const char* namep, Units u,
@ -413,19 +360,12 @@ class PerfLongConstant : public PerfLong {
class PerfLongVariant : public PerfLong {
protected:
PerfLongSampleHelper* _sample_helper;
PerfLongVariant(CounterNS ns, const char* namep, Units u, Variability v,
jlong initial_value=0)
: PerfLong(ns, namep, u, v) {
if (is_valid()) *(jlong*)_valuep = initial_value;
}
PerfLongVariant(CounterNS ns, const char* namep, Units u, Variability v,
PerfLongSampleHelper* sample_helper);
void sample();
public:
inline void inc() { (*(jlong*)_valuep)++; }
inline void inc(jlong val) { (*(jlong*)_valuep) += val; }
@ -451,11 +391,6 @@ class PerfLongCounter : public PerfLongVariant {
jlong initial_value=0)
: PerfLongVariant(ns, namep, u, V_Monotonic,
initial_value) { }
PerfLongCounter(CounterNS ns, const char* namep, Units u,
PerfLongSampleHelper* sample_helper)
: PerfLongVariant(ns, namep, u, V_Monotonic,
sample_helper) { }
};
/*
@ -474,11 +409,6 @@ class PerfLongVariable : public PerfLongVariant {
: PerfLongVariant(ns, namep, u, V_Variable,
initial_value) { }
PerfLongVariable(CounterNS ns, const char* namep, Units u,
PerfLongSampleHelper* sample_helper)
: PerfLongVariant(ns, namep, u, V_Variable,
sample_helper) { }
public:
inline void set_value(jlong val) { (*(jlong*)_valuep) = val; }
};
@ -521,11 +451,6 @@ class PerfStringConstant : public PerfString {
friend class PerfDataManager; // for access to protected constructor
private:
// hide sample() - no need to sample constants
void sample() { }
protected:
// Restrict string constant lengths to be <= PerfMaxStringConstLength.
@ -550,9 +475,6 @@ class PerfStringVariable : public PerfString {
protected:
// sampling of string variables are not yet supported
void sample() { }
PerfStringVariable(CounterNS ns, const char* namep, jint max_length,
const char* initial_value)
: PerfString(ns, namep, V_Variable, max_length+1,
@ -643,26 +565,23 @@ class PerfDataList : public CHeapObj<mtInternal> {
* of the various PerfData types.
*/
class PerfDataManager : AllStatic {
friend class StatSampler; // for access to protected PerfDataList methods
private:
static PerfDataList* _all;
static PerfDataList* _sampled;
static PerfDataList* _constants;
static const char* _name_spaces[];
static volatile bool _has_PerfData;
// add a PerfData item to the list(s) of know PerfData objects
static void add_item(PerfData* p, bool sampled);
protected:
// return the list of all known PerfData items that are to be
// sampled by the StatSampler.
static PerfDataList* sampled();
static void add_item(PerfData* p);
static void create_system_property_instrumentation(TRAPS);
static void assert_system_property(const char* name, const char* value, TRAPS);
static void add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS);
static void add_property_constant(CounterNS name_space, const char* name, TRAPS);
static void add_optional_property_constant(CounterNS name_space, const char* name, TRAPS);
public:
// Creates miscellaneous perfdata constants
static void create_misc_perfdata();
// method to check for the existence of a PerfData item with
// the given name.
@ -747,23 +666,12 @@ class PerfDataManager : AllStatic {
return create_long_variable(ns, name, u, (jlong)0, THREAD);
};
static PerfLongVariable* create_long_variable(CounterNS ns,
const char* name,
PerfData::Units u,
PerfLongSampleHelper* sh,
TRAPS);
// Counter Types
static PerfLongCounter* create_long_counter(CounterNS ns, const char* name,
PerfData::Units u,
jlong ival, TRAPS);
static PerfLongCounter* create_long_counter(CounterNS ns, const char* name,
PerfData::Units u,
PerfLongSampleHelper* sh,
TRAPS);
// these creation methods are provided for ease of use. These allow
// Long performance data types to be created with a shorthand syntax.
@ -783,23 +691,11 @@ class PerfDataManager : AllStatic {
return create_long_variable(ns, name, u, (jlong)0, THREAD);
}
static PerfVariable* create_variable(CounterNS ns, const char* name,
PerfData::Units u,
PerfSampleHelper* sh, TRAPS) {
return create_long_variable(ns, name, u, sh, THREAD);
}
static PerfCounter* create_counter(CounterNS ns, const char* name,
PerfData::Units u, TRAPS) {
return create_long_counter(ns, name, u, (jlong)0, THREAD);
}
static PerfCounter* create_counter(CounterNS ns, const char* name,
PerfData::Units u,
PerfSampleHelper* sh, TRAPS) {
return create_long_counter(ns, name, u, sh, THREAD);
}
static void destroy();
static bool has_PerfData() { return Atomic::load_acquire(&_has_PerfData); }
};

View File

@ -31,13 +31,11 @@
// To reduce HotSpot build time, if you just need to declare a pointer to the
// following types, include this file instead of perfData.hpp.
class PerfLongSampleHelper;
class PerfLongConstant;
class PerfLongCounter;
class PerfLongVariable;
class PerfStringVariable;
typedef PerfLongSampleHelper PerfSampleHelper;
typedef PerfLongConstant PerfConstant;
typedef PerfLongCounter PerfCounter;
typedef PerfLongVariable PerfVariable;

View File

@ -34,7 +34,6 @@
#include "runtime/perfData.hpp"
#include "runtime/perfMemory.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/statSampler.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
@ -66,16 +65,16 @@ void perfMemory_exit() {
if (!UsePerfData) return;
if (!PerfMemory::is_usable()) return;
// Only destroy PerfData objects if we're at a safepoint and the
// StatSampler is not active. Otherwise, we risk removing PerfData
// objects that are currently being used by running JavaThreads
// or the StatSampler. This method is invoked while we are not at
// Only destroy PerfData objects if we're at a safepoint.
// Otherwise, we risk removing PerfData objects
// that are currently being used by running JavaThreads.
// This method is invoked while we are not at
// a safepoint during a VM abort so leaving the PerfData objects
// around may also help diagnose the failure. In rare cases,
// PerfData objects are used in parallel with a safepoint. See
// the work around in PerfDataManager::destroy().
//
if (SafepointSynchronize::is_at_safepoint() && !StatSampler::is_active()) {
if (SafepointSynchronize::is_at_safepoint()) {
PerfDataManager::destroy();
}

View File

@ -1,349 +0,0 @@
/*
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "classfile/javaClasses.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "runtime/perfData.inline.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/vm_version.hpp"
// --------------------------------------------------------
// StatSamplerTask
class StatSamplerTask : public PeriodicTask {
public:
StatSamplerTask(int interval_time) : PeriodicTask(interval_time) {}
void task() { StatSampler::collect_sample(); }
};
//----------------------------------------------------------
// Implementation of StatSampler
StatSamplerTask* StatSampler::_task = nullptr;
PerfDataList* StatSampler::_sampled = nullptr;
/*
* the initialize method is called from the engage() method
* and is responsible for initializing various global variables.
*/
void StatSampler::initialize() {
if (!UsePerfData) return;
// create performance data that could not be created prior
// to vm_init_globals() or otherwise have no logical home.
create_misc_perfdata();
// get copy of the sampled list
_sampled = PerfDataManager::sampled();
}
/*
* The engage() method is called at initialization time via
* Thread::create_vm() to initialize the StatSampler and
* register it with the WatcherThread as a periodic task.
*/
void StatSampler::engage() {
if (!UsePerfData) return;
if (!is_active()) {
initialize();
// start up the periodic task
_task = new StatSamplerTask(PerfDataSamplingInterval);
_task->enroll();
}
}
/*
* the disengage() method is responsible for deactivating the periodic
* task and, if logging was enabled, for logging the final sample. This
* method is called from before_exit() in java.cpp and is only called
* after the WatcherThread has been stopped.
*/
void StatSampler::disengage() {
if (!UsePerfData) return;
if (!is_active())
return;
// remove StatSamplerTask
_task->disenroll();
delete _task;
_task = nullptr;
// force a final sample
sample_data(_sampled);
}
/*
* the destroy method is responsible for releasing any resources used by
* the StatSampler prior to shutdown of the VM. this method is called from
* before_exit() in java.cpp and is only called after the WatcherThread
* has stopped.
*/
void StatSampler::destroy() {
if (!UsePerfData) return;
if (_sampled != nullptr) {
delete(_sampled);
_sampled = nullptr;
}
}
/*
* The sample_data() method is responsible for sampling the
* the data value for each PerfData instance in the given list.
*/
void StatSampler::sample_data(PerfDataList* list) {
assert(list != nullptr, "null list unexpected");
for (int index = 0; index < list->length(); index++) {
PerfData* item = list->at(index);
item->sample();
}
}
/*
* the collect_sample() method is the method invoked by the
* WatcherThread via the PeriodicTask::task() method. This method
* is responsible for collecting data samples from sampled
* PerfData instances every PerfDataSamplingInterval milliseconds.
* It is also responsible for logging the requested set of
* PerfData instances every _sample_count milliseconds. While
* logging data, it will output a column header after every _print_header
* rows of data have been logged.
*/
void StatSampler::collect_sample() {
// future - check for new PerfData objects. PerfData objects might
// get added to the PerfDataManager lists after we have already
// built our local copies.
//
// if (PerfDataManager::count() > previous) {
// // get a new copy of the sampled list
// if (_sampled != nullptr) {
// delete(_sampled);
// _sampled = nullptr;
// }
// _sampled = PerfDataManager::sampled();
// }
assert(_sampled != nullptr, "list not initialized");
sample_data(_sampled);
}
/*
* Call into java.lang.System.getProperty to check that the value of the
* specified property matches
*/
void StatSampler::assert_system_property(const char* name, const char* value, TRAPS) {
#ifdef ASSERT
ResourceMark rm(THREAD);
// setup the arguments to getProperty
Handle key_str = java_lang_String::create_from_str(name, CHECK);
// return value
JavaValue result(T_OBJECT);
// public static String getProperty(String key, String def);
JavaCalls::call_static(&result,
vmClasses::System_klass(),
vmSymbols::getProperty_name(),
vmSymbols::string_string_signature(),
key_str,
CHECK);
oop value_oop = result.get_oop();
assert(value_oop != nullptr, "property must have a value");
// convert Java String to utf8 string
char* system_value = java_lang_String::as_utf8_string(value_oop);
assert(strcmp(value, system_value) == 0, "property value mustn't differ from System.getProperty. Our value is: %s, System.getProperty is: %s",
value, system_value);
#endif // ASSERT
}
/*
* Adds a constant counter of the given property. Asserts the value does not
* differ from the value retrievable from System.getProperty(name)
*/
void StatSampler::add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS) {
// the property must exist
assert(value != nullptr, "property name should be have a value: %s", name);
assert_system_property(name, value, CHECK);
if (value != nullptr) {
// create the property counter
PerfDataManager::create_string_constant(name_space, name, value, CHECK);
}
}
/*
* Adds a string constant of the given property. Retrieves the value via
* Arguments::get_property() and asserts the value for the does not differ from
* the value retrievable from System.getProperty()
*/
void StatSampler::add_property_constant(CounterNS name_space, const char* name, TRAPS) {
add_property_constant(name_space, name, Arguments::get_property(name), CHECK);
}
/*
* Adds a string constant of the given property. Retrieves the value via
* Arguments::get_property() and asserts the value for the does not differ from
* the value retrievable from System.getProperty()
*/
void StatSampler::add_optional_property_constant(CounterNS name_space, const char* name, TRAPS) {
const char* value = Arguments::get_property(name);
if (value != nullptr) {
add_property_constant(name_space, name, value, CHECK);
}
}
/*
* Method to create PerfStringConstants containing the values of various
* system properties. Constants are created from information known to HotSpot,
* but are initialized as-if getting the values from System.getProperty()
* during bootstrap.
*
* Property counters have a counter name space prefix prepended to the
* property name.
*/
void StatSampler::create_system_property_instrumentation(TRAPS) {
// Non-writeable, constant properties
add_property_constant(JAVA_PROPERTY, "java.vm.specification.name", "Java Virtual Machine Specification", CHECK);
add_property_constant(JAVA_PROPERTY, "java.version", JDK_Version::java_version(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.version", VM_Version::vm_release(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.name", VM_Version::vm_name(), CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.vendor", VM_Version::vm_vendor(), CHECK);
add_property_constant(JAVA_PROPERTY, "jdk.debug", VM_Version::jdk_debug_level(), CHECK);
// Get remaining property constants via Arguments::get_property,
// which does a linear search over the internal system properties list.
// SUN_PROPERTY properties
add_property_constant(SUN_PROPERTY, "sun.boot.library.path", CHECK);
// JAVA_PROPERTY properties
add_property_constant(JAVA_PROPERTY, "java.vm.specification.version", CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.specification.vendor", CHECK);
add_property_constant(JAVA_PROPERTY, "java.vm.info", CHECK);
add_property_constant(JAVA_PROPERTY, "java.library.path", CHECK);
add_property_constant(JAVA_PROPERTY, "java.class.path", CHECK);
add_property_constant(JAVA_PROPERTY, "java.home", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.path", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.upgrade.path", CHECK);
add_optional_property_constant(JAVA_PROPERTY, "jdk.module.main", CHECK);
}
/*
* The create_misc_perfdata() method provides a place to create
* PerfData instances that would otherwise have no better place
* to exist.
*/
void StatSampler::create_misc_perfdata() {
ResourceMark rm;
EXCEPTION_MARK;
// numeric constants
// frequency of the native high resolution timer
PerfDataManager::create_constant(SUN_OS, "hrt.frequency",
PerfData::U_Hertz, os::elapsed_frequency(),
CHECK);
// string constants
// create string instrumentation for various Java properties.
create_system_property_instrumentation(CHECK);
// HotSpot flags (from .hotspotrc) and args (from command line)
//
PerfDataManager::create_string_constant(JAVA_RT, "vmFlags",
Arguments::jvm_flags(), CHECK);
PerfDataManager::create_string_constant(JAVA_RT, "vmArgs",
Arguments::jvm_args(), CHECK);
// java class name/jar file and arguments to main class
// note: name is coordinated with launcher and Arguments.cpp
PerfDataManager::create_string_constant(SUN_RT, "javaCommand",
Arguments::java_command(), CHECK);
// the Java VM Internal version string
PerfDataManager::create_string_constant(SUN_RT, "internalVersion",
VM_Version::internal_vm_info_string(),
CHECK);
// create sampled instrumentation objects
create_sampled_perfdata();
}
/*
* helper class to provide for sampling of the elapsed_counter value
* maintained in the OS class.
*/
class HighResTimeSampler : public PerfSampleHelper {
public:
jlong take_sample() { return os::elapsed_counter(); }
};
/*
* the create_sampled_perdata() method provides a place to instantiate
* sampled PerfData instances that would otherwise have no better place
* to exist.
*/
void StatSampler::create_sampled_perfdata() {
EXCEPTION_MARK;
// setup sampling of the elapsed time counter maintained in the
// the os class. This counter can be used as either a time stamp
// for each logged entry or as a liveness indicator for the VM.
PerfSampleHelper* psh = new HighResTimeSampler();
PerfDataManager::create_counter(SUN_OS, "hrt.ticks",
PerfData::U_Ticks, psh, CHECK);
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_RUNTIME_STATSAMPLER_HPP
#define SHARE_RUNTIME_STATSAMPLER_HPP
#include "runtime/perfData.hpp"
#include "runtime/task.hpp"
class StatSamplerTask;
/*
* The StatSampler class is responsible for periodically updating
* sampled PerfData instances and writing the sampled values to the
* PerfData memory region.
*
* In addition it is also responsible for providing a home for
* PerfData instances that otherwise have no better home.
*/
class StatSampler : AllStatic {
friend class StatSamplerTask;
private:
static StatSamplerTask* _task;
static PerfDataList* _sampled;
static void collect_sample();
static void create_misc_perfdata();
static void create_sampled_perfdata();
static void sample_data(PerfDataList* list);
static void assert_system_property(const char* name, const char* value, TRAPS);
static void add_property_constant(CounterNS name_space, const char* name, TRAPS);
static void add_optional_property_constant(CounterNS name_space, const char* name, TRAPS);
static void add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS);
static void create_system_property_instrumentation(TRAPS);
public:
// Start/stop the sampler
static void engage();
static void disengage();
static bool is_active() { return _task != nullptr; }
static void initialize();
static void destroy();
};
#endif // SHARE_RUNTIME_STATSAMPLER_HPP

View File

@ -82,13 +82,13 @@
#include "runtime/nonJavaThread.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/perfData.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/safepointMechanism.inline.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/serviceThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stackWatermarkSet.inline.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.inline.hpp"
@ -852,7 +852,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
}
#endif // INCLUDE_MANAGEMENT
StatSampler::engage();
if (UsePerfData) PerfDataManager::create_misc_perfdata();
if (CheckJNICalls) JniPeriodicChecker::engage();
call_postVMInitHook(THREAD);
@ -906,7 +906,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// + Call before_exit(), prepare for VM exit
// > run VM level shutdown hooks (they are registered through JVM_OnExit(),
// currently the only user of this mechanism is File.deleteOnExit())
// > stop StatSampler, watcher thread,
// > stop watcher thread,
// post thread end and vm death events to JVMTI,
// stop signal thread
// + Call JavaThread::exit(), it will:

View File

@ -244,11 +244,9 @@ public class PerfDataBuffer extends PerfDataBufferImpl {
* Method to provide a gross level of synchronization with the
* target monitored jvm.
*
* gross synchronization works by polling for the hotspot.rt.hrt.ticks
* counter, which is the last counter created by the StatSampler
* initialization code. The counter is updated when the watcher thread
* starts scheduling tasks, which is the last thing done in vm
* initialization.
* gross synchronization works by polling for the hotspot.rt.hrt.frequency
* constant, which is created by the PerfData initialization code. The
* creation of constants is one of the last things done in vm initialization.
*/
protected void synchWithTarget(Map<String, Monitor> map) throws MonitorException {
/*
@ -258,7 +256,7 @@ public class PerfDataBuffer extends PerfDataBufferImpl {
*/
long timeLimit = System.currentTimeMillis() + syncWaitMs;
String name = "hotspot.rt.hrt.ticks";
String name = "hotspot.rt.hrt.frequency";
LongMonitor ticks = (LongMonitor)pollFor(map, name, timeLimit);
/*

View File

@ -541,8 +541,6 @@ alias sun.gc.tlab.refillWaste // 17
// sun.os
alias sun.os.hrt.frequency // 1.5.0 b39
hotspot.rt.hrt.frequency // 1.4.1
alias sun.os.hrt.ticks // 1.5.0 b39
hotspot.rt.hrt.ticks // 1.4.1
// sun.perfdata
alias sun.perfdata.overflow // 1.5.0 b39

View File

@ -61,6 +61,10 @@ public class ExpressionExecuter implements ExpressionEvaluator {
return ((Literal)e).getValue();
}
if (e instanceof Timestamp) {
return ((Timestamp)e).getValue();
}
if (e instanceof Identifier) {
Identifier id = (Identifier)e;
if (map.containsKey(id.getName())) {

View File

@ -87,7 +87,7 @@ public class ExpressionResolver implements ExpressionEvaluator {
return id;
}
if (e instanceof Literal) {
if (e instanceof Literal || e instanceof Timestamp) {
return e;
}

View File

@ -222,6 +222,13 @@ public class Parser {
return reservedWords.contains(word);
}
/**
* determine if the given word is the timestamp key word
*/
private boolean isTimestamp(String word) {
return word.equals("jstat.timestamp");
}
/**
* determine if the give work is a reserved key word
*/
@ -297,7 +304,7 @@ public class Parser {
}
/**
* Primary -> Literal | Identifier | '(' Expression ')'
* Primary -> Literal | Timestamp | Identifier | '(' Expression ')'
*/
private Expression primary() throws ParserException, IOException {
Expression e = null;
@ -315,7 +322,7 @@ public class Parser {
"Reserved Word: " + lookahead.sval);
}
matchID();
e = new Identifier(s);
e = isTimestamp(s) ? new Timestamp() : new Identifier(s);
log(pdebug, "Parsed: ID -> " + s);
break;
case StreamTokenizer.TT_NUMBER:

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.jstat;
public class Timestamp extends Expression {
public Timestamp() {
super();
}
public Object getValue() {
return System.currentTimeMillis();
}
public String toString() {
return "jstat.timestamp";
}
}

View File

@ -26,7 +26,7 @@
option timestamp {
column {
header "^Timestamp"
data (sun.os.hrt.ticks/sun.os.hrt.frequency)
data ((jstat.timestamp - sun.rt.createVmBeginTime) / 1000)
scale sec
align right
width 15