8169517: WhiteBox should provide concurrent GC phase control

Added WhiteBox API and G1 implementation.

Reviewed-by: shade, dfazunen
This commit is contained in:
Kim Barrett 2017-04-13 16:38:39 -04:00
parent 4fd1cd9f86
commit 5fb44c25c7
19 changed files with 1301 additions and 34 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
/*
* Copyright (c) 2001, 2017, 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
@ -32,21 +32,53 @@
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/suspendibleThreadSet.hpp"
#include "gc/g1/vm_operations_g1.hpp"
#include "gc/shared/concurrentGCPhaseManager.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/debug.hpp"
// ======= Concurrent Mark Thread ========
// Check order in EXPAND_CURRENT_PHASES
STATIC_ASSERT(ConcurrentGCPhaseManager::UNCONSTRAINED_PHASE <
ConcurrentGCPhaseManager::IDLE_PHASE);
#define EXPAND_CONCURRENT_PHASES(expander) \
expander(ANY, = ConcurrentGCPhaseManager::UNCONSTRAINED_PHASE, NULL) \
expander(IDLE, = ConcurrentGCPhaseManager::IDLE_PHASE, NULL) \
expander(CONCURRENT_CYCLE,, "Concurrent Cycle") \
expander(CLEAR_CLAIMED_MARKS,, "Concurrent Clear Claimed Marks") \
expander(SCAN_ROOT_REGIONS,, "Concurrent Scan Root Regions") \
expander(CONCURRENT_MARK,, "Concurrent Mark") \
expander(MARK_FROM_ROOTS,, "Concurrent Mark From Roots") \
expander(BEFORE_REMARK,, NULL) \
expander(REMARK,, NULL) \
expander(CREATE_LIVE_DATA,, "Concurrent Create Live Data") \
expander(COMPLETE_CLEANUP,, "Concurrent Complete Cleanup") \
expander(CLEANUP_FOR_NEXT_MARK,, "Concurrent Cleanup for Next Mark") \
/* */
class G1ConcurrentPhase : public AllStatic {
public:
enum {
#define CONCURRENT_PHASE_ENUM(tag, value, ignore_title) tag value,
EXPAND_CONCURRENT_PHASES(CONCURRENT_PHASE_ENUM)
#undef CONCURRENT_PHASE_ENUM
PHASE_ID_LIMIT
};
};
// The CM thread is created when the G1 garbage collector is used
ConcurrentMarkThread::ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_cm(cm),
_state(Idle),
_phase_manager_stack(),
_vtime_accum(0.0),
_vtime_mark_accum(0.0) {
@ -97,8 +129,9 @@ class G1ConcPhaseTimer : public GCTraceConcTimeImpl<LogLevel::Info, LOG_TAGS(gc,
public:
G1ConcPhaseTimer(G1ConcurrentMark* cm, const char* title) :
GCTraceConcTimeImpl<LogLevel::Info, LogTag::_gc, LogTag::_marking>(title),
_cm(cm) {
GCTraceConcTimeImpl<LogLevel::Info, LogTag::_gc, LogTag::_marking>(title),
_cm(cm)
{
_cm->gc_timer_cm()->register_gc_concurrent_start(title);
}
@ -107,12 +140,106 @@ class G1ConcPhaseTimer : public GCTraceConcTimeImpl<LogLevel::Info, LOG_TAGS(gc,
}
};
static const char* const concurrent_phase_names[] = {
#define CONCURRENT_PHASE_NAME(tag, ignore_value, ignore_title) XSTR(tag),
EXPAND_CONCURRENT_PHASES(CONCURRENT_PHASE_NAME)
#undef CONCURRENT_PHASE_NAME
NULL // terminator
};
// Verify dense enum assumption. +1 for terminator.
STATIC_ASSERT(G1ConcurrentPhase::PHASE_ID_LIMIT + 1 ==
ARRAY_SIZE(concurrent_phase_names));
// Returns the phase number for name, or a negative value if unknown.
static int lookup_concurrent_phase(const char* name) {
const char* const* names = concurrent_phase_names;
for (uint i = 0; names[i] != NULL; ++i) {
if (strcmp(name, names[i]) == 0) {
return static_cast<int>(i);
}
}
return -1;
}
// The phase must be valid and must have a title.
static const char* lookup_concurrent_phase_title(int phase) {
static const char* const titles[] = {
#define CONCURRENT_PHASE_TITLE(ignore_tag, ignore_value, title) title,
EXPAND_CONCURRENT_PHASES(CONCURRENT_PHASE_TITLE)
#undef CONCURRENT_PHASE_TITLE
};
// Verify dense enum assumption.
STATIC_ASSERT(G1ConcurrentPhase::PHASE_ID_LIMIT == ARRAY_SIZE(titles));
assert(0 <= phase, "precondition");
assert((uint)phase < ARRAY_SIZE(titles), "precondition");
const char* title = titles[phase];
assert(title != NULL, "precondition");
return title;
}
class G1ConcPhaseManager : public StackObj {
G1ConcurrentMark* _cm;
ConcurrentGCPhaseManager _manager;
public:
G1ConcPhaseManager(int phase, ConcurrentMarkThread* thread) :
_cm(thread->cm()),
_manager(phase, thread->phase_manager_stack())
{ }
~G1ConcPhaseManager() {
// Deactivate the manager if marking aborted, to avoid blocking on
// phase exit when the phase has been requested.
if (_cm->has_aborted()) {
_manager.deactivate();
}
}
void set_phase(int phase, bool force) {
_manager.set_phase(phase, force);
}
};
// Combine phase management and timing into one convenient utility.
class G1ConcPhase : public StackObj {
G1ConcPhaseTimer _timer;
G1ConcPhaseManager _manager;
public:
G1ConcPhase(int phase, ConcurrentMarkThread* thread) :
_timer(thread->cm(), lookup_concurrent_phase_title(phase)),
_manager(phase, thread)
{ }
};
const char* const* ConcurrentMarkThread::concurrent_phases() const {
return concurrent_phase_names;
}
bool ConcurrentMarkThread::request_concurrent_phase(const char* phase_name) {
int phase = lookup_concurrent_phase(phase_name);
if (phase < 0) return false;
while (!ConcurrentGCPhaseManager::wait_for_phase(phase,
phase_manager_stack())) {
assert(phase != G1ConcurrentPhase::ANY, "Wait for ANY phase must succeed");
if ((phase != G1ConcurrentPhase::IDLE) && !during_cycle()) {
// If idle and the goal is !idle, start a collection.
G1CollectedHeap::heap()->collect(GCCause::_wb_conc_mark);
}
}
return true;
}
void ConcurrentMarkThread::run_service() {
_vtime_start = os::elapsedVTime();
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1Policy* g1_policy = g1h->g1_policy();
G1ConcPhaseManager cpmanager(G1ConcurrentPhase::IDLE, this);
while (!should_terminate()) {
// wait until started is set.
sleepBeforeNextCycle();
@ -120,6 +247,8 @@ void ConcurrentMarkThread::run_service() {
break;
}
cpmanager.set_phase(G1ConcurrentPhase::CONCURRENT_CYCLE, false /* force */);
GCIdMark gc_id_mark;
cm()->concurrent_cycle_start();
@ -133,7 +262,7 @@ void ConcurrentMarkThread::run_service() {
double cycle_start = os::elapsedVTime();
{
G1ConcPhaseTimer t(_cm, "Concurrent Clear Claimed Marks");
G1ConcPhase p(G1ConcurrentPhase::CLEAR_CLAIMED_MARKS, this);
ClassLoaderDataGraph::clear_claimed_marks();
}
@ -146,47 +275,68 @@ void ConcurrentMarkThread::run_service() {
// correctness issue.
{
G1ConcPhaseTimer t(_cm, "Concurrent Scan Root Regions");
G1ConcPhase p(G1ConcurrentPhase::SCAN_ROOT_REGIONS, this);
_cm->scan_root_regions();
}
// It would be nice to use the GCTraceConcTime class here but
// It would be nice to use the G1ConcPhase class here but
// the "end" logging is inside the loop and not at the end of
// a scope. Mimicking the same log output as GCTraceConcTime instead.
jlong mark_start = os::elapsed_counter();
log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
// a scope. Also, the timer doesn't support nesting.
// Mimicking the same log output instead.
{
G1ConcPhaseManager mark_manager(G1ConcurrentPhase::CONCURRENT_MARK, this);
jlong mark_start = os::elapsed_counter();
const char* cm_title =
lookup_concurrent_phase_title(G1ConcurrentPhase::CONCURRENT_MARK);
log_info(gc, marking)("%s (%.3fs)",
cm_title,
TimeHelper::counter_to_seconds(mark_start));
for (uint iter = 1; !cm()->has_aborted(); ++iter) {
// Concurrent marking.
{
G1ConcPhase p(G1ConcurrentPhase::MARK_FROM_ROOTS, this);
_cm->mark_from_roots();
}
if (cm()->has_aborted()) break;
for (uint iter = 1; true; ++iter) {
if (!cm()->has_aborted()) {
G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots");
_cm->mark_from_roots();
}
// Provide a control point after mark_from_roots.
{
G1ConcPhaseManager p(G1ConcurrentPhase::BEFORE_REMARK, this);
}
if (cm()->has_aborted()) break;
double mark_end_time = os::elapsedVTime();
jlong mark_end = os::elapsed_counter();
_vtime_mark_accum += (mark_end_time - cycle_start);
if (!cm()->has_aborted()) {
// Delay remark pause for MMU.
double mark_end_time = os::elapsedVTime();
jlong mark_end = os::elapsed_counter();
_vtime_mark_accum += (mark_end_time - cycle_start);
delay_to_keep_mmu(g1_policy, true /* remark */);
log_info(gc, marking)("Concurrent Mark (%.3fs, %.3fs) %.3fms",
if (cm()->has_aborted()) break;
// Pause Remark.
log_info(gc, marking)("%s (%.3fs, %.3fs) %.3fms",
cm_title,
TimeHelper::counter_to_seconds(mark_start),
TimeHelper::counter_to_seconds(mark_end),
TimeHelper::counter_to_millis(mark_end - mark_start));
mark_manager.set_phase(G1ConcurrentPhase::REMARK, false);
CMCheckpointRootsFinalClosure final_cl(_cm);
VM_CGC_Operation op(&final_cl, "Pause Remark");
VMThread::execute(&op);
if (cm()->has_aborted()) {
break;
} else if (!cm()->restart_for_overflow()) {
break; // Exit loop if no restart requested.
} else {
// Loop to restart for overflow.
mark_manager.set_phase(G1ConcurrentPhase::CONCURRENT_MARK, false);
log_info(gc, marking)("%s Restart for Mark Stack Overflow (iteration #%u)",
cm_title, iter);
}
}
if (!cm()->restart_for_overflow() || cm()->has_aborted()) {
break;
}
log_info(gc, marking)("Concurrent Mark Restart due to overflow"
" (iteration #%u", iter);
}
if (!cm()->has_aborted()) {
G1ConcPhaseTimer t(_cm, "Concurrent Create Live Data");
G1ConcPhase p(G1ConcurrentPhase::CREATE_LIVE_DATA, this);
cm()->create_live_data();
}
@ -220,8 +370,8 @@ void ConcurrentMarkThread::run_service() {
// place, it would wait for us to process the regions
// reclaimed by cleanup.
G1ConcPhaseTimer t(_cm, "Concurrent Complete Cleanup");
// Now do the concurrent cleanup operation.
G1ConcPhase p(G1ConcurrentPhase::COMPLETE_CLEANUP, this);
_cm->complete_cleanup();
// Notify anyone who's waiting that there are no more free
@ -276,7 +426,7 @@ void ConcurrentMarkThread::run_service() {
// We may have aborted just before the remark. Do not bother clearing the
// bitmap then, as it has been done during mark abort.
if (!cm()->has_aborted()) {
G1ConcPhaseTimer t(_cm, "Concurrent Cleanup for Next Mark");
G1ConcPhase p(G1ConcurrentPhase::CLEANUP_FOR_NEXT_MARK, this);
_cm->cleanup_for_next_mark();
} else {
assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear");
@ -293,6 +443,8 @@ void ConcurrentMarkThread::run_service() {
cm()->concurrent_cycle_end();
}
cpmanager.set_phase(G1ConcurrentPhase::IDLE, cm()->has_aborted() /* force */);
}
_cm->root_regions()->cancel_scan();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2017, 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
@ -25,6 +25,7 @@
#ifndef SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_HPP
#define SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_HPP
#include "gc/shared/concurrentGCPhaseManager.hpp"
#include "gc/shared/concurrentGCThread.hpp"
// The Concurrent Mark GC Thread triggers the parallel G1CMConcurrentMarkingTasks
@ -50,6 +51,9 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
volatile State _state;
// WhiteBox testing support.
ConcurrentGCPhaseManager::Stack _phase_manager_stack;
void sleepBeforeNextCycle();
void delay_to_keep_mmu(G1Policy* g1_policy, bool remark);
@ -83,6 +87,14 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
// as the CM thread might take some time to wake up before noticing
// that started() is set and set in_progress().
bool during_cycle() { return !idle(); }
// WhiteBox testing support.
const char* const* concurrent_phases() const;
bool request_concurrent_phase(const char* phase);
ConcurrentGCPhaseManager::Stack* phase_manager_stack() {
return &_phase_manager_stack;
}
};
#endif // SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_HPP

View File

@ -2487,6 +2487,18 @@ void G1CollectedHeap::verify(VerifyOption vo) {
_verifier->verify(vo);
}
bool G1CollectedHeap::supports_concurrent_phase_control() const {
return true;
}
const char* const* G1CollectedHeap::concurrent_phases() const {
return _cmThread->concurrent_phases();
}
bool G1CollectedHeap::request_concurrent_phase(const char* phase) {
return _cmThread->request_concurrent_phase(phase);
}
class PrintRegionClosure: public HeapRegionClosure {
outputStream* _st;
public:

View File

@ -1438,6 +1438,11 @@ public:
// full GC.
void verify(VerifyOption vo);
// WhiteBox testing support.
virtual bool supports_concurrent_phase_control() const;
virtual const char* const* concurrent_phases() const;
virtual bool request_concurrent_phase(const char* phase);
// The methods below are here for convenience and dispatch the
// appropriate method depending on value of the given VerifyOption
// parameter. The values for that parameter, and their meanings,

View File

@ -158,6 +158,22 @@ void CollectedHeap::trace_heap_after_gc(const GCTracer* gc_tracer) {
trace_heap(GCWhen::AfterGC, gc_tracer);
}
// WhiteBox API support for concurrent collectors. These are the
// default implementations, for collectors which don't support this
// feature.
bool CollectedHeap::supports_concurrent_phase_control() const {
return false;
}
const char* const* CollectedHeap::concurrent_phases() const {
static const char* const result[] = { NULL };
return result;
}
bool CollectedHeap::request_concurrent_phase(const char* phase) {
return false;
}
// Memory state functions.

View File

@ -579,6 +579,31 @@ class CollectedHeap : public CHeapObj<mtInternal> {
// Heap verification
virtual void verify(VerifyOption option) = 0;
// Return true if concurrent phase control (via
// request_concurrent_phase_control) is supported by this collector.
// The default implementation returns false.
virtual bool supports_concurrent_phase_control() const;
// Return a NULL terminated array of concurrent phase names provided
// by this collector. Supports Whitebox testing. These are the
// names recognized by request_concurrent_phase(). The default
// implementation returns an array of one NULL element.
virtual const char* const* concurrent_phases() const;
// Request the collector enter the indicated concurrent phase, and
// wait until it does so. Supports WhiteBox testing. Only one
// request may be active at a time. Phases are designated by name;
// the set of names and their meaning is GC-specific. Once the
// requested phase has been reached, the collector will attempt to
// avoid transitioning to a new phase until a new request is made.
// [Note: A collector might not be able to remain in a given phase.
// For example, a full collection might cancel an in-progress
// concurrent collection.]
//
// Returns true when the phase is reached. Returns false for an
// unknown phase. The default implementation returns false.
virtual bool request_concurrent_phase(const char* phase);
// Non product verification and debugging.
#ifndef PRODUCT
// Support for PromotionFailureALot. Return true if it's time to cause a

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2017, 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.
*
*/
#include "precompiled.hpp"
#include "gc/shared/concurrentGCPhaseManager.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.hpp"
#define assert_ConcurrentGC_thread() \
assert(Thread::current()->is_ConcurrentGC_thread(), "precondition")
#define assert_not_enter_unconstrained(phase) \
assert((phase) != UNCONSTRAINED_PHASE, "Cannot enter \"unconstrained\" phase")
#define assert_manager_is_tos(manager, stack, kind) \
assert((manager) == (stack)->_top, kind " manager is not top of stack")
ConcurrentGCPhaseManager::Stack::Stack() :
_requested_phase(UNCONSTRAINED_PHASE),
_top(NULL)
{ }
ConcurrentGCPhaseManager::ConcurrentGCPhaseManager(int phase, Stack* stack) :
_phase(phase),
_active(true),
_prev(NULL),
_stack(stack)
{
assert_ConcurrentGC_thread();
assert_not_enter_unconstrained(phase);
assert(stack != NULL, "precondition");
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
if (stack->_top != NULL) {
assert(stack->_top->_active, "precondition");
_prev = stack->_top;
}
stack->_top = this;
ml.notify_all();
}
ConcurrentGCPhaseManager::~ConcurrentGCPhaseManager() {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
wait_when_requested_impl();
_stack->_top = _prev;
ml.notify_all();
}
bool ConcurrentGCPhaseManager::is_requested() const {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
return _active && (_stack->_requested_phase == _phase);
}
bool ConcurrentGCPhaseManager::wait_when_requested_impl() const {
assert_ConcurrentGC_thread();
assert_lock_strong(CGCPhaseManager_lock);
bool waited = false;
while (_active && (_stack->_requested_phase == _phase)) {
waited = true;
CGCPhaseManager_lock->wait(Mutex::_no_safepoint_check_flag);
}
return waited;
}
bool ConcurrentGCPhaseManager::wait_when_requested() const {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
return wait_when_requested_impl();
}
void ConcurrentGCPhaseManager::set_phase(int phase, bool force) {
assert_ConcurrentGC_thread();
assert_not_enter_unconstrained(phase);
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
if (!force) wait_when_requested_impl();
_phase = phase;
ml.notify_all();
}
void ConcurrentGCPhaseManager::deactivate() {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
_active = false;
ml.notify_all();
}
bool ConcurrentGCPhaseManager::wait_for_phase(int phase, Stack* stack) {
assert(Thread::current()->is_Java_thread(), "precondition");
assert(stack != NULL, "precondition");
MonitorLockerEx ml(CGCPhaseManager_lock);
// Update request and notify service of change.
if (stack->_requested_phase != phase) {
stack->_requested_phase = phase;
ml.notify_all();
}
if (phase == UNCONSTRAINED_PHASE) {
return true;
}
// Wait until phase or IDLE is active.
while (true) {
bool idle = false;
for (ConcurrentGCPhaseManager* manager = stack->_top;
manager != NULL;
manager = manager->_prev) {
if (manager->_phase == phase) {
return true; // phase is active.
} else if (manager->_phase == IDLE_PHASE) {
idle = true; // Note idle active, continue search for phase.
}
}
if (idle) {
return false; // idle is active and phase is not.
} else {
ml.wait(); // Wait for phase change.
}
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2017, 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.
*
*/
#ifndef SHARE_VM_GC_CONCURRENTGCPHASEMANAGER_HPP
#define SHARE_VM_GC_CONCURRENTGCPHASEMANAGER_HPP
#include "memory/allocation.hpp"
// Manage concurrent phase information, to support WhiteBox testing.
// Managers are stack allocated. Managers may be nested, to support
// nested subphases.
class ConcurrentGCPhaseManager : public StackObj {
public:
// Special phase ids used by all GC's that use this facility.
static const int UNCONSTRAINED_PHASE = 0; // Unconstrained or no request.
static const int IDLE_PHASE = 1; // Concurrent processing is idle.
// Stack of phase managers.
class Stack VALUE_OBJ_CLASS_SPEC {
friend class ConcurrentGCPhaseManager;
public:
// Create an empty stack of phase managers.
Stack();
private:
int _requested_phase;
ConcurrentGCPhaseManager* _top;
// Non-copyable - never defined.
Stack(const Stack&);
Stack& operator=(const Stack&);
};
// Construct and push a new manager on the stack, activating phase.
// Notifies callers in wait_for_phase of the phase change.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - phase != UNCONSTRAINED_PHASE
// - stack != NULL
// - other managers on stack must all be active.
ConcurrentGCPhaseManager(int phase, Stack* stack);
// Pop this manager off the stack, deactivating phase. Before
// changing phases, if is_requested() is true, wait until the
// request is changed. After changing phases, notifies callers of
// wait_for_phase of the phase change.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - this must be the current top of the manager stack
~ConcurrentGCPhaseManager();
// Returns true if this phase is active and is currently requested.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - this must be the current top of manager stack
bool is_requested() const;
// Wait until is_requested() is false. Returns true if waited.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - this must be the current top of manager stack
bool wait_when_requested() const;
// Directly step from one phase to another, without needing to pop a
// manager from the stack and allocate a new one. Before changing
// phases, if is_requested() is true and force is false, wait until
// the request is changed. After changing phases, notifies callers
// of wait_for_phase of the phase change.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - phase != UNCONSTRAINED_PHASE
// - this must be the current top of manager stack
void set_phase(int phase, bool force);
// Deactivate the manager. An inactive manager no longer blocks
// transitions out of the associated phase when that phase has been
// requested.
//
// Preconditions:
// - Calling thread must be a ConcurrentGC thread
// - this must be the current top of manager stack
void deactivate();
// Used to implement CollectorPolicy::request_concurrent_phase().
// Updates request to the new phase, and notifies threads blocked on
// the old request of the change. Returns true if the phase is
// UNCONSTRAINED_PHASE. Otherwise, waits until an active phase is
// the requested phase (returning true) or IDLE_PHASE (returning
// false if not also the requested phase).
//
// Preconditions:
// - Calling thread must be a Java thread
// - stack must be non-NULL
static bool wait_for_phase(int phase, Stack* stack);
private:
int _phase;
bool _active;
ConcurrentGCPhaseManager* _prev;
Stack* _stack;
// Non-copyable - never defined.
ConcurrentGCPhaseManager(const ConcurrentGCPhaseManager&);
ConcurrentGCPhaseManager& operator=(const ConcurrentGCPhaseManager&);
bool wait_when_requested_impl() const;
};
#endif // include guard

View File

@ -357,6 +357,43 @@ WB_ENTRY(jlong, WB_GetHeapAlignment(JNIEnv* env, jobject o))
return (jlong)alignment;
WB_END
WB_ENTRY(jboolean, WB_SupportsConcurrentGCPhaseControl(JNIEnv* env, jobject o))
return Universe::heap()->supports_concurrent_phase_control();
WB_END
WB_ENTRY(jobjectArray, WB_GetConcurrentGCPhases(JNIEnv* env, jobject o))
const char* const* phases = Universe::heap()->concurrent_phases();
jint nphases = 0;
for ( ; phases[nphases] != NULL; ++nphases) ;
ResourceMark rm(thread);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
jobjectArray result = env->NewObjectArray(nphases, clazz, NULL);
CHECK_JNI_EXCEPTION_(env, NULL);
// If push fails, return with pending exception.
if (env->PushLocalFrame(nphases) < 0) return NULL;
for (jint i = 0; i < nphases; ++i) {
jstring phase = env->NewStringUTF(phases[i]);
CHECK_JNI_EXCEPTION_(env, NULL);
env->SetObjectArrayElement(result, i, phase);
CHECK_JNI_EXCEPTION_(env, NULL);
}
env->PopLocalFrame(NULL);
return result;
WB_END
WB_ENTRY(jboolean, WB_RequestConcurrentGCPhase(JNIEnv* env, jobject o, jstring name))
Handle h_name(THREAD, JNIHandles::resolve(name));
ResourceMark rm;
const char* c_name = java_lang_String::as_utf8_string(h_name());
return Universe::heap()->request_concurrent_phase(c_name);
WB_END
#if INCLUDE_ALL_GCS
WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
if (UseG1GC) {
@ -1969,6 +2006,11 @@ static JNINativeMethod methods[] = {
{CC"currentGC", CC"()I", (void*)&WB_CurrentGC},
{CC"allSupportedGC", CC"()I", (void*)&WB_AllSupportedGC},
{CC"gcSelectedByErgo", CC"()Z", (void*)&WB_GCSelectedByErgo},
{CC"supportsConcurrentGCPhaseControl", CC"()Z", (void*)&WB_SupportsConcurrentGCPhaseControl},
{CC"getConcurrentGCPhases", CC"()[Ljava/lang/String;",
(void*)&WB_GetConcurrentGCPhases},
{CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
(void*)&WB_RequestConcurrentGCPhase},
};
#undef CC

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -81,6 +81,7 @@ Mutex* MarkStackFreeList_lock = NULL;
Mutex* MarkStackChunkList_lock = NULL;
Mutex* ParGCRareEvent_lock = NULL;
Mutex* DerivedPointerTableGC_lock = NULL;
Monitor* CGCPhaseManager_lock = NULL;
Mutex* Compile_lock = NULL;
Monitor* MethodCompileQueue_lock = NULL;
Monitor* CompileThread_lock = NULL;
@ -203,6 +204,9 @@ void mutex_init() {
}
def(ParGCRareEvent_lock , PaddedMutex , leaf , true, Monitor::_safepoint_check_sometimes);
def(DerivedPointerTableGC_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never);
#ifdef INCLUDE_ALL_GCS
def(CGCPhaseManager_lock , PaddedMonitor, leaf, false, Monitor::_safepoint_check_sometimes);
#endif
def(CodeCache_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never);
def(RawMonitor_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never);
def(OopMapCacheAlloc_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -57,6 +57,7 @@ extern Mutex* MethodData_lock; // a lock on installation of me
extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info
extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derived pointer table
extern Monitor* CGCPhaseManager_lock; // a lock to protect a concurrent GC's phase management
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute
extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate
extern Monitor* Safepoint_lock; // a lock used by the safepoint abstraction

View File

@ -0,0 +1,247 @@
/*
* Copyright (c) 2017, 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.
*/
package gc.concurrent_phase_control;
/*
* Utility class that uses the WhiteBox concurrent GC phase control to
* step through a provided sequence of phases, and verify that the
* phases were actually reached as expected.
*
* To use:
*
* (1) The main test class has a main function which calls this helper
* class's check() function with appropriate arguments for the
* collector being tested.
*
* (2) The test program must provide access to WhiteBox, as it is used
* by this support class.
*
* (4) The main test class should be invoked as a driver. This
* helper class's check() function will run its Executor class in a
* subprocess, in order to capture its output for analysis.
*/
import sun.hotspot.WhiteBox;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public final class CheckControl {
// gcName: The name of the GC, logged as "Using <name>" near the
// beginning of the log output.
//
// gcOptions: Command line options for invoking the desired
// collector and logging options to produce output that can be
// matched against the regex patterns in the gcPhaseInfo pairs.
//
// gcPhaseInfo: An array of pairs of strings. Each pair is a
// phase name and a regex pattern for recognizing the associated
// log message. The regex pattern can be null if no log message
// is associated with the named phase. The test will iterate
// through the array, requesting each phase in turn.
public static void check(String gcName,
String[] gcOptions,
String[][] gcPhaseInfo) throws Exception {
String[] stepPhases = new String[gcPhaseInfo.length];
for (int i = 0; i < gcPhaseInfo.length; ++i) {
stepPhases[i] = gcPhaseInfo[i][0];
}
String messages = executeTest(gcName, gcOptions, stepPhases);
checkPhaseControl(messages, gcPhaseInfo);
}
private static void fail(String message) throws Exception {
throw new RuntimeException(message);
}
private static final String requestPrefix = "Requesting concurrent phase: ";
private static final String reachedPrefix = "Reached concurrent phase: ";
private static String executeTest(String gcName,
String[] gcOptions,
String[] gcStepPhases) throws Exception {
System.out.println("\n---------- Testing ---------");
final String[] wb_arguments = {
"-Xbootclasspath/a:.",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI"
};
List<String> arglist = new ArrayList<String>();
Collections.addAll(arglist, wb_arguments);
Collections.addAll(arglist, gcOptions);
arglist.add(Executor.class.getName());
Collections.addAll(arglist, gcStepPhases);
String[] arguments = arglist.toArray(new String[arglist.size()]);
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
String messages = output.getStdout();
System.out.println(messages);
output.shouldHaveExitValue(0);
output.shouldContain("Using " + gcName);
return messages;
}
private static void checkPhaseControl(String messages,
String[][] gcPhaseInfo)
throws Exception
{
// Iterate through the phase sequence for the test, verifying
// output contains appropriate sequences of request message,
// log message for phase, and request reached message. Note
// that a log message for a phase may occur later than the
// associated request reached message, or even the following
// request message.
Pattern nextReqP = Pattern.compile(requestPrefix);
Matcher nextReqM = nextReqP.matcher(messages);
Pattern nextReachP = Pattern.compile(reachedPrefix);
Matcher nextReachM = nextReachP.matcher(messages);
String pendingPhaseMessage = null;
int pendingPhaseMessagePosition = -1;
int position = 0;
for (String[] phase: gcPhaseInfo) {
String phaseName = phase[0];
String phaseMsg = phase[1];
System.out.println("Checking phase " + phaseName);
// Update the "next" matchers to refer to the next
// corresponding pair of request and reached messages.
if (!nextReqM.find()) {
fail("Didn't find next phase request");
} else if ((position != 0) && (nextReqM.start() < nextReachM.end())) {
fail("Next request before previous reached");
} else if (!nextReachM.find()) {
fail("Didn't find next phase reached");
} else if (nextReachM.start() <= nextReqM.end()) {
fail("Next request/reached misordered");
}
// Find the expected request message, and ensure it is the next.
Pattern reqP = Pattern.compile(requestPrefix + phaseName);
Matcher reqM = reqP.matcher(messages);
if (!reqM.find(position)) {
fail("Didn't find request for " + phaseName);
} else if (reqM.start() != nextReqM.start()) {
fail("Request mis-positioned for " + phaseName);
}
// Find the expected reached message, and ensure it is the next.
Pattern reachP = Pattern.compile(reachedPrefix + phaseName);
Matcher reachM = reachP.matcher(messages);
if (!reachM.find(position)) {
fail("Didn't find reached for " + phaseName);
} else if (reachM.start() != nextReachM.start()) {
fail("Reached mis-positioned for " + phaseName);
}
// If there is a pending log message (see below), ensure
// it was before the current reached message.
if (pendingPhaseMessage != null) {
if (pendingPhaseMessagePosition >= reachM.start()) {
fail("Log message after next reached message: " +
pendingPhaseMessage);
}
}
// If the phase has an associated logging message, verify
// such a logging message is present following the
// request, and otherwise positioned appropriately. The
// complication here is that the logging message
// associated with a request might follow the reached
// message, and even the next request message, if there is
// a later request. But it must preceed the next
// logging message and the next reached message.
boolean clearPendingPhaseMessage = true;
if (phaseMsg != null) {
Pattern logP = Pattern.compile("GC\\(\\d+\\)\\s+" + phaseMsg);
Matcher logM = logP.matcher(messages);
if (!logM.find(reqM.end())) {
fail("Didn't find message " + phaseMsg);
}
if (pendingPhaseMessage != null) {
if (pendingPhaseMessagePosition >= logM.start()) {
fail("Log messages out of order: " +
pendingPhaseMessage + " should preceed " +
phaseMsg);
}
}
if (reachM.end() <= logM.start()) {
clearPendingPhaseMessage = false;
pendingPhaseMessage = phaseMsg;
pendingPhaseMessagePosition = logM.end();
}
}
if (clearPendingPhaseMessage) {
pendingPhaseMessage = null;
pendingPhaseMessagePosition = -1;
}
// Update position for start of next phase search.
position = reachM.end();
}
// It's okay for there to be a leftover pending phase message.
// We know it was found before the end of the log.
}
private static final class Executor {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static void step(String phase) {
System.out.println(requestPrefix + phase);
WB.requestConcurrentGCPhase(phase);
System.out.println(reachedPrefix + phase);
}
public static void main(String[] phases) throws Exception {
// Iterate through set sequence of phases, reporting each.
for (String phase: phases) {
step(phase);
}
// Wait a little to allow a delayed logging message for
// the final request/reached to be printed before exiting
// the program.
Thread.sleep(250);
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2017, 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.
*/
package gc.concurrent_phase_control;
/*
* Utility class that provides verification of expected behavior of
* the Concurrent GC Phase Control WB API when the current GC supports
* phase control. The invoking test must provide WhiteBox access.
*/
import sun.hotspot.WhiteBox;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CheckSupported {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static Set<String> toSet(List<String> list, String which)
throws Exception
{
Set<String> result = new HashSet<String>(list);
if (result.size() < list.size()) {
throw new RuntimeException(which + " phases contains duplicates");
}
return result;
}
private static void checkPhases(String[] expectedPhases) throws Exception {
String[] actualPhases = WB.getConcurrentGCPhases();
List<String> expectedList = Arrays.asList(expectedPhases);
List<String> actualList = Arrays.asList(actualPhases);
Set<String> expected = toSet(expectedList, "Expected");
Set<String> actual = toSet(actualList, "Actual");
expected.removeAll(actualList);
actual.removeAll(expectedList);
boolean match = true;
if (!expected.isEmpty()) {
match = false;
System.out.println("Unexpected phases:");
for (String s: expected) {
System.out.println(" " + s);
}
}
if (!actual.isEmpty()) {
match = false;
System.out.println("Expected but missing phases:");
for (String s: actual) {
System.out.println(" " + s);
}
}
if (!match) {
throw new RuntimeException("Mismatch between expected and actual phases");
}
}
public static void check(String gcName, String[] phases) throws Exception {
// Verify supported.
if (!WB.supportsConcurrentGCPhaseControl()) {
throw new RuntimeException(
gcName + " unexpectedly missing phase control support");
}
checkPhases(phases);
// Verify IllegalArgumentException thrown by request attempt
// with unknown phase.
boolean illegalArgumentThrown = false;
try {
WB.requestConcurrentGCPhase("UNKNOWN PHASE");
} catch (IllegalArgumentException e) {
// Expected.
illegalArgumentThrown = true;
} catch (Exception e) {
throw new RuntimeException(
gcName + ": Unexpected exception when requesting unknown phase: " + e.toString());
}
if (!illegalArgumentThrown) {
throw new RuntimeException(
gcName + ": No exception when requesting unknown phase");
}
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2017, 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.
*/
package gc.concurrent_phase_control;
/*
* Utility class that provides verification of expected behavior of
* the Concurrent GC Phase Control WB API when the current GC does not
* support phase control. The invoking test must provide WhiteBox access.
*/
import sun.hotspot.WhiteBox;
public class CheckUnsupported {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
public static void check(String gcName) throws Exception {
// Verify unsupported.
if (WB.supportsConcurrentGCPhaseControl()) {
throw new RuntimeException(
gcName + " unexpectedly supports phase control");
}
// Verify phase sequence is empty.
String[] phases = WB.getConcurrentGCPhases();
if (phases.length > 0) {
throw new RuntimeException(
gcName + " unexpectedly has non-empty phases");
}
// Verify IllegalStateException thrown by request attempt.
boolean illegalStateThrown = false;
try {
WB.requestConcurrentGCPhase("UNKNOWN PHASE");
} catch (IllegalStateException e) {
// Expected.
illegalStateThrown = true;
} catch (Exception e) {
throw new RuntimeException(
gcName + ": Unexpected exception when requesting phase: "
+ e.toString());
}
if (!illegalStateThrown) {
throw new RuntimeException(
gcName + ": No exception when requesting phase");
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2017, 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 TestConcurrentPhaseControlCMS
* @bug 8169517
* @requires vm.gc.ConcMarkSweep
* @summary Verify CMS GC doesn't support WhiteBox concurrent phase control.
* @key gc
* @modules java.base
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UseConcMarkSweepGC
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestConcurrentPhaseControlCMS
*/
import gc.concurrent_phase_control.CheckUnsupported;
public class TestConcurrentPhaseControlCMS {
public static void main(String[] args) throws Exception {
CheckUnsupported.check("CMS");
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2017, 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 TestConcurrentPhaseControlG1
* @bug 8169517
* @requires vm.gc.G1
* @summary Test of WhiteBox concurrent GC phase control for G1.
* @key gc
* @modules java.base
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run driver TestConcurrentPhaseControlG1
*/
import gc.concurrent_phase_control.CheckControl;
public class TestConcurrentPhaseControlG1 {
// Pairs of phase name and regex to match log stringm for stepping through,
private static final String[][] g1PhaseInfo = {
// Step through the phases in order.
{"IDLE", null},
{"CONCURRENT_CYCLE", "Concurrent Cycle"},
{"IDLE", null}, // Resume IDLE before testing subphases
{"CLEAR_CLAIMED_MARKS", "Concurrent Clear Claimed Marks"},
{"SCAN_ROOT_REGIONS", "Concurrent Scan Root Regions"},
// ^F so not "From Roots", ^R so not "Restart"
{"CONCURRENT_MARK", "Concurrent Mark [^FR]"},
{"IDLE", null}, // Resume IDLE before testing subphases
{"MARK_FROM_ROOTS", "Concurrent Mark From Roots"},
{"BEFORE_REMARK", null},
{"REMARK", "Pause Remark"},
{"CREATE_LIVE_DATA", "Concurrent Create Live Data"},
// "COMPLETE_CLEANUP", -- optional phase, not reached by this test
{"CLEANUP_FOR_NEXT_MARK", "Concurrent Cleanup for Next Mark"},
// Clear request
{"IDLE", null},
{"ANY", null},
// Request a phase.
{"MARK_FROM_ROOTS", "Concurrent Mark From Roots"},
// Request an earlier phase, to ensure loop rather than stuck at idle.
{"SCAN_ROOT_REGIONS", "Concurrent Scan Root Regions"},
// Clear request, to unblock service.
{"IDLE", null},
{"ANY", null},
};
private static final String[] g1Options =
new String[]{"-XX:+UseG1GC", "-Xlog:gc,gc+marking"};
private static final String g1Name = "G1";
public static void main(String[] args) throws Exception {
CheckControl.check(g1Name, g1Options, g1PhaseInfo);
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, 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 TestConcurrentPhaseControlG1Basics
* @bug 8169517
* @requires vm.gc.G1
* @summary Verify G1 supports concurrent phase control and has the
* expected set of phases.
* @key gc
* @modules java.base
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UseG1GC
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestConcurrentPhaseControlG1Basics
*/
import gc.concurrent_phase_control.CheckSupported;
public class TestConcurrentPhaseControlG1Basics {
private static final String[] phases = {
"ANY",
"IDLE",
"CONCURRENT_CYCLE",
"CLEAR_CLAIMED_MARKS",
"SCAN_ROOT_REGIONS",
"CONCURRENT_MARK",
"MARK_FROM_ROOTS",
"BEFORE_REMARK",
"REMARK",
"CREATE_LIVE_DATA",
"COMPLETE_CLEANUP",
"CLEANUP_FOR_NEXT_MARK",
};
public static void main(String[] args) throws Exception {
CheckSupported.check("G1", phases);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2017, 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 TestConcurrentPhaseControlParallel
* @bug 8169517
* @requires vm.gc.Parallel
* @summary Verify Parallel GC doesn't support WhiteBox concurrent phase control.
* @key gc
* @modules java.base
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UseParallelGC
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestConcurrentPhaseControlParallel
*/
import gc.concurrent_phase_control.CheckUnsupported;
public class TestConcurrentPhaseControlParallel {
public static void main(String[] args) throws Exception {
CheckUnsupported.check("Parallel");
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2017, 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 TestConcurrentPhaseControlSerial
* @bug 8169517
* @requires vm.gc.Serial
* @summary Verify Serial GC doesn't support WhiteBox concurrent phase control.
* @key gc
* @modules java.base
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UseSerialGC
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestConcurrentPhaseControlSerial
*/
import gc.concurrent_phase_control.CheckUnsupported;
public class TestConcurrentPhaseControlSerial {
public static void main(String[] args) throws Exception {
CheckUnsupported.check("Serial");
}
}