8330969: scalability issue with loaded JVMTI agent

Reviewed-by: amenkov, cjplummer
This commit is contained in:
Serguei Spitsyn 2024-05-01 08:40:48 +00:00
parent f215899a08
commit 663acd2e17
5 changed files with 31 additions and 28 deletions

View File

@ -1633,19 +1633,16 @@ private:
}
// This function is called only if _enable == true.
// Iterates over all JavaThread's, counts VTMS transitions and restores
// jt->jvmti_thread_state() and jt->jvmti_vthread() for VTMS transition protocol.
int count_transitions_and_correct_jvmti_thread_states() {
int count = 0;
// Iterates over all JavaThread's, restores jt->jvmti_thread_state() and
// jt->jvmti_vthread() for VTMS transition protocol.
void correct_jvmti_thread_states() {
for (JavaThread* jt : ThreadsListHandle()) {
if (jt->is_in_VTMS_transition()) {
count++;
jt->set_VTMS_transition_mark(true);
continue; // no need in JvmtiThreadState correction below if in transition
}
correct_jvmti_thread_state(jt);
}
return count;
}
public:
@ -1655,9 +1652,9 @@ public:
}
void doit() {
int count = _enable ? count_transitions_and_correct_jvmti_thread_states() : 0;
JvmtiVTMSTransitionDisabler::set_VTMS_transition_count(count);
if (_enable) {
correct_jvmti_thread_states();
}
JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(_enable);
}
};

View File

@ -214,9 +214,6 @@ JvmtiThreadState::periodic_clean_up() {
// Virtual Threads Mount State transition (VTMS transition) mechanism
//
// VTMS transitions cannot be disabled while this counter is positive.
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_count = 0;
// VTMS transitions for one virtual thread are disabled while it is positive
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0;
@ -238,11 +235,14 @@ volatile bool JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_permanently =
#ifdef ASSERT
void
JvmtiVTMSTransitionDisabler::print_info() {
log_error(jvmti)("_VTMS_transition_count: %d\n", _VTMS_transition_count);
log_error(jvmti)("_VTMS_transition_disable_for_one_count: %d\n", _VTMS_transition_disable_for_one_count);
log_error(jvmti)("_VTMS_transition_disable_for_all_count: %d\n\n", _VTMS_transition_disable_for_all_count);
int attempts = 10000;
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) {
if (java_thread->VTMS_transition_mark()) {
log_error(jvmti)("jt: %p VTMS_transition_mark: %d\n",
(void*)java_thread, java_thread->VTMS_transition_mark());
}
ResourceMark rm;
// Handshake with target.
PrintStackTraceClosure pstc;
@ -358,11 +358,13 @@ JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() {
// Block while some mount/unmount transitions are in progress.
// Debug version fails and prints diagnostic information.
while (_VTMS_transition_count > 0) {
if (ml.wait(10)) {
attempts--;
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
while (jt->VTMS_transition_mark()) {
if (ml.wait(10)) {
attempts--;
}
DEBUG_ONLY(if (attempts == 0) break;)
}
DEBUG_ONLY(if (attempts == 0) break;)
}
assert(!thread->is_VTMS_transition_disabler(), "VTMS_transition sanity check");
#ifdef ASSERT
@ -427,8 +429,9 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun
assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check");
// Avoid using MonitorLocker on performance critical path, use
// two-level synchronization with lock-free operations on counters.
Atomic::inc(&_VTMS_transition_count); // Try to enter VTMS transition section optmistically.
// two-level synchronization with lock-free operations on state bits.
assert(!thread->VTMS_transition_mark(), "sanity check");
thread->set_VTMS_transition_mark(true); // Try to enter VTMS transition section optmistically.
java_lang_Thread::set_is_in_VTMS_transition(vt, true);
if (!sync_protocol_enabled()) {
@ -448,9 +451,9 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun
thread->is_suspended() ||
JvmtiVTSuspender::is_vthread_suspended(thread_id)
) {
// Slow path: undo unsuccessful optimistic counter incrementation.
// Slow path: undo unsuccessful optimistic set of the VTMS_transition_mark.
// It can cause an extra waiting cycle for VTMS transition disablers.
Atomic::dec(&_VTMS_transition_count);
thread->set_VTMS_transition_mark(false);
java_lang_Thread::set_is_in_VTMS_transition(vth(), false);
while (true) {
@ -470,7 +473,7 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun
DEBUG_ONLY(if (attempts == 0) break;)
continue; // ~ThreadBlockInVM has handshake-based suspend point.
}
Atomic::inc(&_VTMS_transition_count);
thread->set_VTMS_transition_mark(true);
java_lang_Thread::set_is_in_VTMS_transition(vth(), true);
break;
}
@ -495,7 +498,8 @@ JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mou
thread->set_is_in_VTMS_transition(false);
oop vt = JNIHandles::resolve_external_guard(vthread);
java_lang_Thread::set_is_in_VTMS_transition(vt, false);
Atomic::dec(&_VTMS_transition_count);
assert(thread->VTMS_transition_mark(), "sanity check");
thread->set_VTMS_transition_mark(false);
if (!sync_protocol_enabled()) {
return;

View File

@ -82,9 +82,8 @@ class JvmtiVTMSTransitionDisabler {
static volatile int _VTMS_transition_disable_for_one_count; // transitions for one virtual thread are disabled while it is positive
static volatile int _VTMS_transition_disable_for_all_count; // transitions for all virtual threads are disabled while it is positive
static volatile bool _SR_mode; // there is an active suspender or resumer
static volatile int _VTMS_transition_count; // current number of VTMS transitions
static volatile int _sync_protocol_enabled_count; // current number of JvmtiVTMSTransitionDisablers enabled sync protocol
static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTraansitionDisabler protocol is enabled permanently
static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently
bool _is_SR; // is suspender or resumer
jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread
@ -100,8 +99,6 @@ class JvmtiVTMSTransitionDisabler {
static bool VTMS_notify_jvmti_events() { return _VTMS_notify_jvmti_events; }
static void set_VTMS_notify_jvmti_events(bool val) { _VTMS_notify_jvmti_events = val; }
static void set_VTMS_transition_count(bool val) { _VTMS_transition_count = val; }
static void inc_sync_protocol_enabled_count() { Atomic::inc(&_sync_protocol_enabled_count); }
static void dec_sync_protocol_enabled_count() { Atomic::dec(&_sync_protocol_enabled_count); }
static int sync_protocol_enabled_count() { return Atomic::load(&_sync_protocol_enabled_count); }

View File

@ -450,6 +450,7 @@ JavaThread::JavaThread() :
_is_in_VTMS_transition(false),
_is_in_tmp_VTMS_transition(false),
_is_disable_suspend(false),
_VTMS_transition_mark(false),
#ifdef ASSERT
_is_VTMS_transition_disabler(false),
#endif

View File

@ -317,6 +317,7 @@ class JavaThread: public Thread {
bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition
bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition
bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only
bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers
#ifdef ASSERT
bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions
#endif
@ -664,6 +665,9 @@ private:
bool is_disable_suspend() const { return _is_disable_suspend; }
void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; };
bool VTMS_transition_mark() const { return Atomic::load(&_VTMS_transition_mark); }
void set_VTMS_transition_mark(bool val) { Atomic::store(&_VTMS_transition_mark, val); }
#ifdef ASSERT
bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; }
void set_is_VTMS_transition_disabler(bool val);