8220774: Add HandshakeALot diag option
Reviewed-by: dcubed, dholmes
This commit is contained in:
parent
afa3178149
commit
ed3542d53b
src/hotspot/share/runtime
test/hotspot/jtreg
@ -371,6 +371,10 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
|
||||
"Generate a lot of safepoints. This works with " \
|
||||
"GuaranteedSafepointInterval") \
|
||||
\
|
||||
diagnostic(bool, HandshakeALot, false, \
|
||||
"Generate a lot of handshakes. This works with " \
|
||||
"GuaranteedSafepointInterval") \
|
||||
\
|
||||
product_pd(bool, BackgroundCompilation, \
|
||||
"A thread requesting compilation is not blocked during " \
|
||||
"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) {
|
||||
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()) {
|
||||
// Traverse the execution stack
|
||||
|
@ -1874,6 +1874,9 @@ class JavaThread: public Thread {
|
||||
// RedefineClasses Support
|
||||
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
|
||||
char* name() const { return (char*)get_thread_name(); }
|
||||
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_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) {
|
||||
return &safepointALot_op;
|
||||
}
|
||||
if (!SafepointSynchronize::is_cleanup_needed()) {
|
||||
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;
|
||||
// Nothing to be done.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void VMThread::loop() {
|
||||
@ -491,19 +504,22 @@ void VMThread::loop() {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (timedout && (_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
|
||||
MutexUnlockerEx mul(VMOperationQueue_lock,
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
// Force a safepoint since we have not had one for at least
|
||||
// 'GuaranteedSafepointInterval' milliseconds. This will run all
|
||||
// the clean-up processing that needs to be done regularly at a
|
||||
// safepoint
|
||||
SafepointSynchronize::begin();
|
||||
#ifdef ASSERT
|
||||
if (timedout) {
|
||||
// Have to unlock VMOperationQueue_lock just in case no_op_safepoint()
|
||||
// has to do a handshake.
|
||||
MutexUnlockerEx mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
|
||||
if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
|
||||
// Force a safepoint since we have not had one for at least
|
||||
// 'GuaranteedSafepointInterval' milliseconds and we need to clean
|
||||
// something. This will run all the clean-up processing that needs
|
||||
// to be done at a safepoint.
|
||||
SafepointSynchronize::begin();
|
||||
#ifdef ASSERT
|
||||
if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot();
|
||||
#endif
|
||||
SafepointSynchronize::end();
|
||||
_cur_vm_operation = NULL;
|
||||
#endif
|
||||
SafepointSynchronize::end();
|
||||
_cur_vm_operation = NULL;
|
||||
}
|
||||
}
|
||||
_cur_vm_operation = _vm_queue->remove_next();
|
||||
|
||||
@ -615,10 +631,9 @@ void VMThread::loop() {
|
||||
VMOperationRequest_lock->notify_all();
|
||||
}
|
||||
|
||||
//
|
||||
// We want to make sure that we get to a safepoint regularly.
|
||||
//
|
||||
if ((_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
|
||||
// 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) {
|
||||
HandleMark hm(VMThread::vm_thread());
|
||||
SafepointSynchronize::begin();
|
||||
SafepointSynchronize::end();
|
||||
|
@ -123,7 +123,7 @@ class VMThread: public NamedThread {
|
||||
|
||||
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);
|
||||
|
||||
|
@ -80,7 +80,6 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8193639 solaris-all
|
||||
|
||||
# :hotspot_runtime
|
||||
|
||||
runtime/handshake/HandshakeWalkSuspendExitTest.java 8214174 generic-all
|
||||
runtime/NMT/CheckForProperDetailStackTrace.java 8218458 generic-all
|
||||
runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all
|
||||
runtime/containers/docker/TestCPUSets.java 8220672 generic-all
|
||||
|
@ -26,6 +26,7 @@
|
||||
* @bug 8167108
|
||||
* @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 -XX:+UnlockDiagnosticVMOptions -XX:GuaranteedSafepointInterval=1 -XX:+HandshakeALot SuspendAtExit
|
||||
*/
|
||||
|
||||
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,
|
||||
"-Djava.library.path=" + lib,
|
||||
"-XX:+SafepointALot",
|
||||
"-XX:+HandshakeALot",
|
||||
"-XX:GuaranteedSafepointInterval=20",
|
||||
"-Xlog:ergo*",
|
||||
"-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…
x
Reference in New Issue
Block a user