8357671: JFR: Remove JfrTraceIdEpoch synchronizing

Reviewed-by: egahlin
This commit is contained in:
Markus Grönlund 2025-06-04 08:19:24 +00:00
parent edf92721c2
commit 955bfcd550
7 changed files with 23 additions and 51 deletions

View File

@ -497,15 +497,10 @@ typedef CompositeOperation<MutexedWriteOperation, ReleaseOperation> WriteRelease
typedef VirtualThreadLocalCheckpointWriteOp<JfrCheckpointManager::Buffer> VirtualThreadLocalCheckpointOperation; typedef VirtualThreadLocalCheckpointWriteOp<JfrCheckpointManager::Buffer> VirtualThreadLocalCheckpointOperation;
typedef MutexedWriteOp<VirtualThreadLocalCheckpointOperation> VirtualThreadLocalWriteOperation; typedef MutexedWriteOp<VirtualThreadLocalCheckpointOperation> VirtualThreadLocalWriteOperation;
void JfrCheckpointManager::begin_epoch_shift() { void JfrCheckpointManager::shift_epoch() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
JfrTraceIdEpoch::begin_epoch_shift();
}
void JfrCheckpointManager::end_epoch_shift() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
DEBUG_ONLY(const u1 current_epoch = JfrTraceIdEpoch::current();) DEBUG_ONLY(const u1 current_epoch = JfrTraceIdEpoch::current();)
JfrTraceIdEpoch::end_epoch_shift(); JfrTraceIdEpoch::shift_epoch();
assert(current_epoch != JfrTraceIdEpoch::current(), "invariant"); assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
JfrStringPool::on_epoch_shift(); JfrStringPool::on_epoch_shift();
} }

View File

@ -96,8 +96,7 @@ class JfrCheckpointManager : public JfrCHeapObj {
void clear_type_set(); void clear_type_set();
void write_type_set(); void write_type_set();
void begin_epoch_shift(); void shift_epoch();
void end_epoch_shift();
static void on_unloading_classes(); static void on_unloading_classes();
void on_rotation(); void on_rotation();

View File

@ -31,7 +31,7 @@
/* /*
* The epoch generation is the range [1-32767]. * The epoch generation is the range [1-32767].
* *
* When the epoch value is stored in a thread object, * When the epoch value is stored in a vthread object,
* the most significant bit of the u2 is used to denote * the most significant bit of the u2 is used to denote
* thread exclusion, i.e 1 << 15 == 32768 denotes exclusion. * thread exclusion, i.e 1 << 15 == 32768 denotes exclusion.
*/ */
@ -39,32 +39,17 @@ u2 JfrTraceIdEpoch::_generation = 0;
JfrSignal JfrTraceIdEpoch::_tag_state; JfrSignal JfrTraceIdEpoch::_tag_state;
bool JfrTraceIdEpoch::_method_tracer_state = false; bool JfrTraceIdEpoch::_method_tracer_state = false;
bool JfrTraceIdEpoch::_epoch_state = false; bool JfrTraceIdEpoch::_epoch_state = false;
bool JfrTraceIdEpoch::_synchronizing = false;
static constexpr const u2 epoch_generation_overflow = excluded_bit; static constexpr const u2 epoch_generation_overflow = excluded_bit;
void JfrTraceIdEpoch::begin_epoch_shift() { void JfrTraceIdEpoch::shift_epoch() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
_synchronizing = true;
OrderAccess::fence();
}
void JfrTraceIdEpoch::end_epoch_shift() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
assert(_synchronizing, "invariant");
_epoch_state = !_epoch_state; _epoch_state = !_epoch_state;
++_generation; if (++_generation == epoch_generation_overflow) {
if (epoch_generation_overflow == _generation) {
_generation = 1; _generation = 1;
} }
assert(_generation != 0, "invariant"); assert(_generation != 0, "invariant");
assert(_generation < epoch_generation_overflow, "invariant"); assert(_generation < epoch_generation_overflow, "invariant");
OrderAccess::storestore();
_synchronizing = false;
}
bool JfrTraceIdEpoch::is_synchronizing() {
return Atomic::load_acquire(&_synchronizing);
} }
void JfrTraceIdEpoch::set_method_tracer_tag_state() { void JfrTraceIdEpoch::set_method_tracer_tag_state() {

View File

@ -26,7 +26,6 @@
#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP
#include "jfr/utilities/jfrSignal.hpp" #include "jfr/utilities/jfrSignal.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "memory/allStatic.hpp" #include "memory/allStatic.hpp"
#define BIT 1 #define BIT 1
@ -41,16 +40,17 @@
#define EPOCH_0_METHOD_AND_CLASS_BITS (METHOD_AND_CLASS_BITS << EPOCH_0_SHIFT) #define EPOCH_0_METHOD_AND_CLASS_BITS (METHOD_AND_CLASS_BITS << EPOCH_0_SHIFT)
#define EPOCH_1_METHOD_AND_CLASS_BITS (METHOD_AND_CLASS_BITS << EPOCH_1_SHIFT) #define EPOCH_1_METHOD_AND_CLASS_BITS (METHOD_AND_CLASS_BITS << EPOCH_1_SHIFT)
// Epoch alternation on each rotation allow for concurrent tagging. /*
// The epoch shift happens only during a safepoint. * An epoch shift or alternation on each rotation enables concurrent tagging.
// * The epoch shift happens only during a safepoint.
// _synchronizing is a transition state, the purpose of which is to *
// have JavaThreads that run _thread_in_native (i.e. Compiler threads) * _generation - mainly used with virtual threads, but also for the generational string pool in Java.
// respect the current epoch shift in-progress during the safepoint. * _tag_state - signals an incremental modification to artifact tagging (klasses, methods, CLDs, etc)
// * purpose of which is to trigger a collection of artifacts.
// _changed_tag_state == true signals an incremental modification to artifact tagging * _method_tracer_state - a special notification state only used with method timing and tracing.
// (klasses, methods, CLDs, etc), purpose of which is to trigger collection of artifacts. * _epoch_state - the fundamental binary epoch state that shifts on each rotation during a safepoint.
// */
class JfrTraceIdEpoch : AllStatic { class JfrTraceIdEpoch : AllStatic {
friend class JfrCheckpointManager; friend class JfrCheckpointManager;
private: private:
@ -58,10 +58,8 @@ class JfrTraceIdEpoch : AllStatic {
static JfrSignal _tag_state; static JfrSignal _tag_state;
static bool _method_tracer_state; static bool _method_tracer_state;
static bool _epoch_state; static bool _epoch_state;
static bool _synchronizing;
static void begin_epoch_shift(); static void shift_epoch();
static void end_epoch_shift();
public: public:
static bool epoch() { static bool epoch() {

View File

@ -484,13 +484,12 @@ void JfrRecorderService::invoke_safepoint_clear() {
void JfrRecorderService::safepoint_clear() { void JfrRecorderService::safepoint_clear() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
_checkpoint_manager.begin_epoch_shift();
_storage.clear(); _storage.clear();
_checkpoint_manager.notify_threads(); _checkpoint_manager.notify_threads();
_chunkwriter.set_time_stamp(); _chunkwriter.set_time_stamp();
JfrDeprecationManager::on_safepoint_clear(); JfrDeprecationManager::on_safepoint_clear();
JfrStackTraceRepository::clear(); JfrStackTraceRepository::clear();
_checkpoint_manager.end_epoch_shift(); _checkpoint_manager.shift_epoch();
} }
void JfrRecorderService::post_safepoint_clear() { void JfrRecorderService::post_safepoint_clear() {
@ -593,14 +592,13 @@ void JfrRecorderService::invoke_safepoint_write() {
void JfrRecorderService::safepoint_write() { void JfrRecorderService::safepoint_write() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
_checkpoint_manager.begin_epoch_shift();
JfrStackTraceRepository::clear_leak_profiler(); JfrStackTraceRepository::clear_leak_profiler();
_checkpoint_manager.on_rotation(); _checkpoint_manager.on_rotation();
_storage.write_at_safepoint(); _storage.write_at_safepoint();
_chunkwriter.set_time_stamp(); _chunkwriter.set_time_stamp();
JfrDeprecationManager::on_safepoint_write(); JfrDeprecationManager::on_safepoint_write();
write_stacktrace(_stack_trace_repository, _chunkwriter, true); write_stacktrace(_stack_trace_repository, _chunkwriter, true);
_checkpoint_manager.end_epoch_shift(); _checkpoint_manager.shift_epoch();
} }
void JfrRecorderService::post_safepoint_write() { void JfrRecorderService::post_safepoint_write() {

View File

@ -44,8 +44,6 @@
static int generation_offset = invalid_offset; static int generation_offset = invalid_offset;
static jobject string_pool = nullptr; static jobject string_pool = nullptr;
static unsigned short generation = 0;
static bool setup_string_pool_offsets(TRAPS) { static bool setup_string_pool_offsets(TRAPS) {
const char class_name[] = "jdk/jfr/internal/StringPool"; const char class_name[] = "jdk/jfr/internal/StringPool";
Symbol* const k_sym = SymbolTable::new_symbol(class_name); Symbol* const k_sym = SymbolTable::new_symbol(class_name);
@ -281,9 +279,8 @@ void JfrStringPool::register_full(BufferPtr buffer, Thread* thread) {
void JfrStringPool::on_epoch_shift() { void JfrStringPool::on_epoch_shift() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant");
assert(!JfrTraceIdEpoch::is_synchronizing(), "invariant");
assert(string_pool != nullptr, "invariant"); assert(string_pool != nullptr, "invariant");
oop mirror = JfrJavaSupport::resolve_non_null(string_pool); oop mirror = JfrJavaSupport::resolve_non_null(string_pool);
assert(mirror != nullptr, "invariant"); assert(mirror != nullptr, "invariant");
mirror->short_field_put(generation_offset, generation++); mirror->short_field_put(generation_offset, JfrTraceIdEpoch::epoch_generation());
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -51,7 +51,7 @@ public final class StringPool {
private static int preCacheOld = 0; private static int preCacheOld = 0;
/* max size bytes */ /* max size bytes */
private static long currentSizeUTF16; private static long currentSizeUTF16;
/* string pool generation (0-65535) set by the JVM on epoch shift. Not private to avoid being optimized away. */ /* The string pool epoch generation is the range [1-32767] set by the JVM on epoch shift. Not private to avoid being optimized away. */
static short generation = 0; static short generation = 0;
/* internalSid is a composite id [48-bit externalSid][16-bit generation]. */ /* internalSid is a composite id [48-bit externalSid][16-bit generation]. */