mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8220774: Add HandshakeALot diag option
Reviewed-by: dcubed, dholmes
This commit is contained in:
parent
afa3178149
commit
ed3542d53b
10 changed files with 171 additions and 125 deletions
|
@ -371,6 +371,10 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
|
||||||
"Generate a lot of safepoints. This works with " \
|
"Generate a lot of safepoints. This works with " \
|
||||||
"GuaranteedSafepointInterval") \
|
"GuaranteedSafepointInterval") \
|
||||||
\
|
\
|
||||||
|
diagnostic(bool, HandshakeALot, false, \
|
||||||
|
"Generate a lot of handshakes. This works with " \
|
||||||
|
"GuaranteedSafepointInterval") \
|
||||||
|
\
|
||||||
product_pd(bool, BackgroundCompilation, \
|
product_pd(bool, BackgroundCompilation, \
|
||||||
"A thread requesting compilation is not blocked during " \
|
"A thread requesting compilation is not blocked during " \
|
||||||
"compilation") \
|
"compilation") \
|
||||||
|
|
|
@ -2928,9 +2928,21 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
void JavaThread::verify_states_for_handshake() {
|
||||||
|
// This checks that the thread has a correct frame state during a handshake.
|
||||||
|
assert((!has_last_Java_frame() && java_call_counter() == 0) ||
|
||||||
|
(has_last_Java_frame() && java_call_counter() > 0),
|
||||||
|
"unexpected frame info: has_last_frame=%d, java_call_counter=%d",
|
||||||
|
has_last_Java_frame(), java_call_counter());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void JavaThread::nmethods_do(CodeBlobClosure* cf) {
|
void JavaThread::nmethods_do(CodeBlobClosure* cf) {
|
||||||
assert((!has_last_Java_frame() && java_call_counter() == 0) ||
|
assert((!has_last_Java_frame() && java_call_counter() == 0) ||
|
||||||
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
|
(has_last_Java_frame() && java_call_counter() > 0),
|
||||||
|
"unexpected frame info: has_last_frame=%d, java_call_counter=%d",
|
||||||
|
has_last_Java_frame(), java_call_counter());
|
||||||
|
|
||||||
if (has_last_Java_frame()) {
|
if (has_last_Java_frame()) {
|
||||||
// Traverse the execution stack
|
// Traverse the execution stack
|
||||||
|
|
|
@ -1874,6 +1874,9 @@ class JavaThread: public Thread {
|
||||||
// RedefineClasses Support
|
// RedefineClasses Support
|
||||||
void metadata_do(MetadataClosure* f);
|
void metadata_do(MetadataClosure* f);
|
||||||
|
|
||||||
|
// Debug method asserting thread states are correct during a handshake operation.
|
||||||
|
DEBUG_ONLY(void verify_states_for_handshake();)
|
||||||
|
|
||||||
// Misc. operations
|
// Misc. operations
|
||||||
char* name() const { return (char*)get_thread_name(); }
|
char* name() const { return (char*)get_thread_name(); }
|
||||||
void print_on(outputStream* st, bool print_extended_info) const;
|
void print_on(outputStream* st, bool print_extended_info) const;
|
||||||
|
|
|
@ -434,22 +434,35 @@ void VMThread::evaluate_operation(VM_Operation* op) {
|
||||||
static VM_None safepointALot_op("SafepointALot");
|
static VM_None safepointALot_op("SafepointALot");
|
||||||
static VM_Cleanup cleanup_op;
|
static VM_Cleanup cleanup_op;
|
||||||
|
|
||||||
VM_Operation* VMThread::no_op_safepoint(bool check_time) {
|
class HandshakeALotTC : public ThreadClosure {
|
||||||
|
public:
|
||||||
|
virtual void do_thread(Thread* thread) {
|
||||||
|
#ifdef ASSERT
|
||||||
|
assert(thread->is_Java_thread(), "must be");
|
||||||
|
JavaThread* jt = (JavaThread*)thread;
|
||||||
|
jt->verify_states_for_handshake();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VM_Operation* VMThread::no_op_safepoint() {
|
||||||
|
// Check for handshakes first since we may need to return a VMop.
|
||||||
|
if (HandshakeALot) {
|
||||||
|
HandshakeALotTC haltc;
|
||||||
|
Handshake::execute(&haltc);
|
||||||
|
}
|
||||||
|
// Check for a cleanup before SafepointALot to keep stats correct.
|
||||||
|
long interval_ms = SafepointTracing::time_since_last_safepoint_ms();
|
||||||
|
bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
|
||||||
|
(interval_ms >= GuaranteedSafepointInterval);
|
||||||
|
if (max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) {
|
||||||
|
return &cleanup_op;
|
||||||
|
}
|
||||||
if (SafepointALot) {
|
if (SafepointALot) {
|
||||||
return &safepointALot_op;
|
return &safepointALot_op;
|
||||||
}
|
}
|
||||||
if (!SafepointSynchronize::is_cleanup_needed()) {
|
// Nothing to be done.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if (check_time) {
|
|
||||||
long interval_ms = SafepointTracing::time_since_last_safepoint_ms();
|
|
||||||
bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
|
|
||||||
(interval_ms > GuaranteedSafepointInterval);
|
|
||||||
if (!max_time_exceeded) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &cleanup_op;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMThread::loop() {
|
void VMThread::loop() {
|
||||||
|
@ -491,19 +504,22 @@ void VMThread::loop() {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timedout && (_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
|
if (timedout) {
|
||||||
MutexUnlockerEx mul(VMOperationQueue_lock,
|
// Have to unlock VMOperationQueue_lock just in case no_op_safepoint()
|
||||||
Mutex::_no_safepoint_check_flag);
|
// has to do a handshake.
|
||||||
// Force a safepoint since we have not had one for at least
|
MutexUnlockerEx mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
|
||||||
// 'GuaranteedSafepointInterval' milliseconds. This will run all
|
if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
|
||||||
// the clean-up processing that needs to be done regularly at a
|
// Force a safepoint since we have not had one for at least
|
||||||
// safepoint
|
// 'GuaranteedSafepointInterval' milliseconds and we need to clean
|
||||||
SafepointSynchronize::begin();
|
// something. This will run all the clean-up processing that needs
|
||||||
#ifdef ASSERT
|
// to be done at a safepoint.
|
||||||
|
SafepointSynchronize::begin();
|
||||||
|
#ifdef ASSERT
|
||||||
if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot();
|
if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot();
|
||||||
#endif
|
#endif
|
||||||
SafepointSynchronize::end();
|
SafepointSynchronize::end();
|
||||||
_cur_vm_operation = NULL;
|
_cur_vm_operation = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_cur_vm_operation = _vm_queue->remove_next();
|
_cur_vm_operation = _vm_queue->remove_next();
|
||||||
|
|
||||||
|
@ -615,10 +631,9 @@ void VMThread::loop() {
|
||||||
VMOperationRequest_lock->notify_all();
|
VMOperationRequest_lock->notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// We want to make sure that we get to a safepoint regularly
|
||||||
// We want to make sure that we get to a safepoint regularly.
|
// even when executing VMops that don't require safepoints.
|
||||||
//
|
if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
|
||||||
if ((_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
|
|
||||||
HandleMark hm(VMThread::vm_thread());
|
HandleMark hm(VMThread::vm_thread());
|
||||||
SafepointSynchronize::begin();
|
SafepointSynchronize::begin();
|
||||||
SafepointSynchronize::end();
|
SafepointSynchronize::end();
|
||||||
|
|
|
@ -123,7 +123,7 @@ class VMThread: public NamedThread {
|
||||||
|
|
||||||
static VMOperationTimeoutTask* _timeout_task;
|
static VMOperationTimeoutTask* _timeout_task;
|
||||||
|
|
||||||
static VM_Operation* no_op_safepoint(bool check_time);
|
static VM_Operation* no_op_safepoint();
|
||||||
|
|
||||||
void evaluate_operation(VM_Operation* op);
|
void evaluate_operation(VM_Operation* op);
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8193639 solaris-all
|
||||||
|
|
||||||
# :hotspot_runtime
|
# :hotspot_runtime
|
||||||
|
|
||||||
runtime/handshake/HandshakeWalkSuspendExitTest.java 8214174 generic-all
|
|
||||||
runtime/NMT/CheckForProperDetailStackTrace.java 8218458 generic-all
|
runtime/NMT/CheckForProperDetailStackTrace.java 8218458 generic-all
|
||||||
runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all
|
runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all
|
||||||
runtime/containers/docker/TestCPUSets.java 8220672 generic-all
|
runtime/containers/docker/TestCPUSets.java 8220672 generic-all
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
* @bug 8167108
|
* @bug 8167108
|
||||||
* @summary Stress test java.lang.Thread.suspend() at thread exit.
|
* @summary Stress test java.lang.Thread.suspend() at thread exit.
|
||||||
* @run main/othervm -Xlog:thread+smr=debug SuspendAtExit
|
* @run main/othervm -Xlog:thread+smr=debug SuspendAtExit
|
||||||
|
* @run main/othervm -Xlog:thread+smr=debug -XX:+UnlockDiagnosticVMOptions -XX:GuaranteedSafepointInterval=1 -XX:+HandshakeALot SuspendAtExit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test HandshakeSuspendExitTest
|
||||||
|
* @summary This test tries to stress the handshakes with new and exiting threads while suspending them.
|
||||||
|
* @library /testlibrary /test/lib
|
||||||
|
* @build HandshakeSuspendExitTest
|
||||||
|
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:GuaranteedSafepointInterval=1 -XX:+HandshakeALot HandshakeSuspendExitTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class HandshakeSuspendExitTest implements Runnable {
|
||||||
|
|
||||||
|
static Thread[] _suspend_threads = new Thread[16];
|
||||||
|
static volatile boolean _exit_now = false;
|
||||||
|
static java.util.concurrent.Semaphore _sem = new java.util.concurrent.Semaphore(0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
_sem.release();
|
||||||
|
while (!_exit_now) {
|
||||||
|
// Leave last 2 threads running.
|
||||||
|
for (int i = 0; i < _suspend_threads.length - 2; i++) {
|
||||||
|
if (Thread.currentThread() != thr) {
|
||||||
|
thr.suspend();
|
||||||
|
thr.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_sem.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
HandshakeSuspendExitTest test = new HandshakeSuspendExitTest();
|
||||||
|
// Fire-up suspend threads.
|
||||||
|
for (int i = 0; i < _suspend_threads.length; i++) {
|
||||||
|
_suspend_threads[i] = new Thread(test);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < _suspend_threads.length; i++) {
|
||||||
|
_suspend_threads[i].start();
|
||||||
|
}
|
||||||
|
// Wait for all suspend-threads to start looping.
|
||||||
|
for (Thread thr : _suspend_threads) {
|
||||||
|
_sem.acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire-up exiting threads.
|
||||||
|
Thread[] exit_threads = new Thread[128];
|
||||||
|
for (int i = 0; i < exit_threads.length; i++) {
|
||||||
|
exit_threads[i] = new Thread();
|
||||||
|
exit_threads[i].start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to suspend them.
|
||||||
|
for (Thread thr : exit_threads) {
|
||||||
|
thr.suspend();
|
||||||
|
}
|
||||||
|
for (Thread thr : exit_threads) {
|
||||||
|
thr.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start exit and join.
|
||||||
|
_exit_now = true;
|
||||||
|
int waiting = _suspend_threads.length;
|
||||||
|
do {
|
||||||
|
// Resume any worker threads that might have suspended
|
||||||
|
// each other at exactly the same time so they can see
|
||||||
|
// _exit_now and check in via the semaphore.
|
||||||
|
for (Thread thr : _suspend_threads) {
|
||||||
|
thr.resume();
|
||||||
|
}
|
||||||
|
while (_sem.tryAcquire()) {
|
||||||
|
--waiting;
|
||||||
|
}
|
||||||
|
} while (waiting > 0);
|
||||||
|
for (Thread thr : _suspend_threads) {
|
||||||
|
thr.join();
|
||||||
|
}
|
||||||
|
for (Thread thr : exit_threads) {
|
||||||
|
thr.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,6 +62,7 @@ public class HandshakeTransitionTest {
|
||||||
true,
|
true,
|
||||||
"-Djava.library.path=" + lib,
|
"-Djava.library.path=" + lib,
|
||||||
"-XX:+SafepointALot",
|
"-XX:+SafepointALot",
|
||||||
|
"-XX:+HandshakeALot",
|
||||||
"-XX:GuaranteedSafepointInterval=20",
|
"-XX:GuaranteedSafepointInterval=20",
|
||||||
"-Xlog:ergo*",
|
"-Xlog:ergo*",
|
||||||
"-XX:ParallelGCThreads=1",
|
"-XX:ParallelGCThreads=1",
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018, 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @test HandshakeWalkSuspendExitTest
|
|
||||||
* @summary This test tries to stress the handshakes with new and exiting threads while suspending them.
|
|
||||||
* @library /testlibrary /test/lib
|
|
||||||
* @build HandshakeWalkSuspendExitTest
|
|
||||||
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
|
|
||||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
|
||||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI HandshakeWalkSuspendExitTest
|
|
||||||
*/
|
|
||||||
|
|
||||||
import jdk.test.lib.Asserts;
|
|
||||||
import sun.hotspot.WhiteBox;
|
|
||||||
|
|
||||||
public class HandshakeWalkSuspendExitTest implements Runnable {
|
|
||||||
|
|
||||||
static final int _test_threads = 8;
|
|
||||||
static final int _test_exit_threads = 128;
|
|
||||||
static Thread[] _threads = new Thread[_test_threads];
|
|
||||||
static volatile boolean exit_now = false;
|
|
||||||
static java.util.concurrent.Semaphore _sem = new java.util.concurrent.Semaphore(0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
WhiteBox wb = WhiteBox.getWhiteBox();
|
|
||||||
while (!exit_now) {
|
|
||||||
_sem.release();
|
|
||||||
// We only suspend threads on even index and not ourself.
|
|
||||||
// Otherwise we can accidentially suspend all threads.
|
|
||||||
for (int i = 0; i < _threads.length; i += 2) {
|
|
||||||
wb.handshakeWalkStack(null /* ignored */, true /* stackwalk all threads */);
|
|
||||||
if (Thread.currentThread() != _threads[i]) {
|
|
||||||
_threads[i].suspend();
|
|
||||||
_threads[i].resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < _threads.length; i += 2) {
|
|
||||||
wb.handshakeWalkStack(_threads[i] /* thread to stackwalk */, false /* stackwalk one thread */);
|
|
||||||
if (Thread.currentThread() != _threads[i]) {
|
|
||||||
_threads[i].suspend();
|
|
||||||
_threads[i].resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
|
||||||
HandshakeWalkSuspendExitTest test = new HandshakeWalkSuspendExitTest();
|
|
||||||
|
|
||||||
for (int i = 0; i < _threads.length; i++) {
|
|
||||||
_threads[i] = new Thread(test);
|
|
||||||
_threads[i].start();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < _test_threads; i++) {
|
|
||||||
_sem.acquire();
|
|
||||||
}
|
|
||||||
Thread[] exit_threads = new Thread[_test_exit_threads];
|
|
||||||
for (int i = 0; i < _test_exit_threads; i++) {
|
|
||||||
exit_threads[i] = new Thread(new Runnable() { public void run() {} });
|
|
||||||
exit_threads[i].start();
|
|
||||||
}
|
|
||||||
exit_now = true;
|
|
||||||
for (int i = 0; i < _threads.length; i++) {
|
|
||||||
_threads[i].join();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < exit_threads.length; i++) {
|
|
||||||
exit_threads[i].join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue