mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-11 07:28:36 +00:00
8295376: Improve debug agent virtual thread performance when no debugger is attached
Reviewed-by: sspitsyn, kevinw
This commit is contained in:
parent
76790ad242
commit
47d2c7b4cf
@ -1028,6 +1028,7 @@ parseOptions(char *options)
|
||||
/* Set vthread debugging level. */
|
||||
gdata->vthreadsSupported = JNI_TRUE;
|
||||
gdata->includeVThreads = JNI_FALSE;
|
||||
gdata->rememberVThreadsWhenDisconnected = JNI_FALSE;
|
||||
|
||||
/* Options being NULL will end up being an error. */
|
||||
if (options == NULL) {
|
||||
@ -1142,6 +1143,8 @@ parseOptions(char *options)
|
||||
} else {
|
||||
goto syntax_error;
|
||||
}
|
||||
// These two flags always set the same for now.
|
||||
gdata->rememberVThreadsWhenDisconnected = gdata->includeVThreads;
|
||||
current += strlen(current) + 1;
|
||||
} else if (strcmp(buf, "launch") == 0) {
|
||||
/*LINTED*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2022, 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
|
||||
@ -97,6 +97,7 @@ debugLoop_run(void)
|
||||
|
||||
standardHandlers_onConnect();
|
||||
threadControl_onConnect();
|
||||
eventHandler_onConnect();
|
||||
|
||||
/* Okay, start reading cmds! */
|
||||
while (shouldListen) {
|
||||
|
||||
@ -132,6 +132,10 @@ static jrawMonitorID callbackBlock;
|
||||
debugMonitorEnter(callbackBlock); \
|
||||
debugMonitorExit(callbackBlock); \
|
||||
} else { \
|
||||
/* Notify anyone waiting for callbacks to exit */ \
|
||||
if (active_callbacks == 0) { \
|
||||
debugMonitorNotifyAll(callbackLock); \
|
||||
} \
|
||||
debugMonitorExit(callbackLock); \
|
||||
} \
|
||||
} \
|
||||
@ -1509,8 +1513,11 @@ eventHandler_initialize(jbyte sessionID)
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
EXIT_ERROR(error,"Can't enable garbage collection finish events");
|
||||
}
|
||||
/* Only enable vthread events if vthread support is enabled. */
|
||||
if (gdata->vthreadsSupported) {
|
||||
/*
|
||||
* Only enable vthread START and END events if we want to remember
|
||||
* vthreads when no debugger is connected.
|
||||
*/
|
||||
if (gdata->vthreadsSupported && gdata->rememberVThreadsWhenDisconnected) {
|
||||
error = threadControl_setEventMode(JVMTI_ENABLE,
|
||||
EI_VIRTUAL_THREAD_START, NULL);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
@ -1582,6 +1589,33 @@ eventHandler_initialize(jbyte sessionID)
|
||||
eventHelper_initialize(sessionID);
|
||||
}
|
||||
|
||||
void
|
||||
eventHandler_onConnect() {
|
||||
debugMonitorEnter(handlerLock);
|
||||
|
||||
/*
|
||||
* Enable vthread START and END events if they are not already always enabled.
|
||||
* They are always enabled if we are remembering vthreads when no debugger is
|
||||
* connected. Otherwise they are only enabled when connected because they can
|
||||
* be very noisy and hurt performance a lot.
|
||||
*/
|
||||
if (gdata->vthreadsSupported && !gdata->rememberVThreadsWhenDisconnected) {
|
||||
jvmtiError error;
|
||||
error = threadControl_setEventMode(JVMTI_ENABLE,
|
||||
EI_VIRTUAL_THREAD_START, NULL);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
EXIT_ERROR(error,"Can't enable vthread start events");
|
||||
}
|
||||
error = threadControl_setEventMode(JVMTI_ENABLE,
|
||||
EI_VIRTUAL_THREAD_END, NULL);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
EXIT_ERROR(error,"Can't enable vthread end events");
|
||||
}
|
||||
}
|
||||
|
||||
debugMonitorExit(handlerLock);
|
||||
}
|
||||
|
||||
void
|
||||
eventHandler_reset(jbyte sessionID)
|
||||
{
|
||||
@ -1596,6 +1630,24 @@ eventHandler_reset(jbyte sessionID)
|
||||
*/
|
||||
threadControl_detachInvokes();
|
||||
|
||||
/* Disable vthread START and END events unless we are remembering vthreads
|
||||
* when no debugger is connected. We do this because these events can
|
||||
* be very noisy and hurt performance a lot.
|
||||
*/
|
||||
if (gdata->vthreadsSupported && !gdata->rememberVThreadsWhenDisconnected) {
|
||||
jvmtiError error;
|
||||
error = threadControl_setEventMode(JVMTI_DISABLE,
|
||||
EI_VIRTUAL_THREAD_START, NULL);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
EXIT_ERROR(error,"Can't disable vthread start events");
|
||||
}
|
||||
error = threadControl_setEventMode(JVMTI_DISABLE,
|
||||
EI_VIRTUAL_THREAD_END, NULL);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
EXIT_ERROR(error,"Can't disable vthread end events");
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the event helper thread, purging all queued and
|
||||
* in-process commands.
|
||||
*/
|
||||
@ -1612,6 +1664,23 @@ eventHandler_reset(jbyte sessionID)
|
||||
debugMonitorExit(handlerLock);
|
||||
}
|
||||
|
||||
void
|
||||
eventHandler_waitForActiveCallbacks()
|
||||
{
|
||||
/*
|
||||
* Wait for active callbacks to complete. It is ok if more callbacks come in
|
||||
* after this point. This is being done so threadControl_reset() can safely
|
||||
* remove all vthreads without worry that they might be referenced in an active
|
||||
* callback. The only callbacks enabled at this point are the permanent ones,
|
||||
* and they never involve vthreads.
|
||||
*/
|
||||
debugMonitorEnter(callbackLock);
|
||||
while (active_callbacks > 0) {
|
||||
debugMonitorWait(callbackLock);
|
||||
}
|
||||
debugMonitorExit(callbackLock);
|
||||
}
|
||||
|
||||
void
|
||||
eventHandler_lock(void)
|
||||
{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2022, 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
|
||||
@ -71,7 +71,9 @@ void eventHandler_freeClassBreakpoints(jclass clazz);
|
||||
/***** HandlerNode manipulation *****/
|
||||
|
||||
void eventHandler_initialize(jbyte sessionID);
|
||||
void eventHandler_onConnect();
|
||||
void eventHandler_reset(jbyte sessionID);
|
||||
void eventHandler_waitForActiveCallbacks();
|
||||
|
||||
void eventHandler_lock(void);
|
||||
void eventHandler_unlock(void);
|
||||
|
||||
@ -510,6 +510,19 @@ removeResumed(JNIEnv *env, ThreadList *list)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
removeVThreads(JNIEnv *env)
|
||||
{
|
||||
ThreadList *list = &runningVThreads;
|
||||
ThreadNode *node = list->first;
|
||||
while (node != NULL) {
|
||||
ThreadNode *temp = node->next;
|
||||
removeNode(list, node);
|
||||
clearThread(env, node);
|
||||
node = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node)
|
||||
{
|
||||
@ -2754,6 +2767,30 @@ threadControl_reset(void)
|
||||
debugMonitorNotifyAll(threadLock);
|
||||
debugMonitorExit(threadLock);
|
||||
eventHandler_unlock();
|
||||
|
||||
/*
|
||||
* Unless we are remembering all vthreads when the debugger is not connected,
|
||||
* we free them all up here.
|
||||
*/
|
||||
if (!gdata->rememberVThreadsWhenDisconnected) {
|
||||
/*
|
||||
* First we need to wait for all active callbacks to complete. They were resumed
|
||||
* above by the resetHelper. We can't remove the vthreads until after they complete,
|
||||
* because the vthread ThreadNodes might be referenced as the callbacks unwind.
|
||||
* We do this outside of any locking, because the callbacks may need to acquire locks
|
||||
* in order to complete. It's ok if there are more callbacks after this point because
|
||||
* the only callbacks enabled are the permanent ones, and they never involve vthreads.
|
||||
*/
|
||||
eventHandler_waitForActiveCallbacks();
|
||||
/*
|
||||
* Now that event callbacks have exited, we can reacquire the threadLock, which
|
||||
* is needed before before calling removeVThreads().
|
||||
*/
|
||||
debugMonitorEnter(threadLock);
|
||||
removeVThreads(env);
|
||||
debugMonitorExit(threadLock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
jvmtiEventMode
|
||||
|
||||
@ -86,6 +86,7 @@ typedef struct {
|
||||
jboolean assertFatal;
|
||||
jboolean vthreadsSupported; /* If true, debugging support for vthreads is enabled. */
|
||||
jboolean includeVThreads; /* If true, VM.AllThreads includes vthreads. */
|
||||
jboolean rememberVThreadsWhenDisconnected;
|
||||
jboolean doerrorexit;
|
||||
jboolean modifiedUtf8;
|
||||
jboolean quiet;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user