This commit is contained in:
Jesper Wilhelmsson 2015-05-11 16:30:26 +02:00
commit 042902811c
14 changed files with 137 additions and 178 deletions

View File

@ -4799,8 +4799,8 @@ jint os::init_2(void) {
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseHugeTLBFS)) {
UseLargePages = false;
} else {
warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing");
} else if (UseAdaptiveSizePolicy || UseAdaptiveNUMAChunkSizing) {
warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing (-XX:-UseAdaptiveSizePolicy -XX:-UseAdaptiveNUMAChunkSizing)");
UseAdaptiveSizePolicy = false;
UseAdaptiveNUMAChunkSizing = false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2015, 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
@ -77,7 +77,7 @@ void ConcurrentG1RefineThread::initialize() {
}
void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1CollectorPolicy* g1p = g1h->g1_policy();
if (g1p->adaptive_young_list_length()) {
@ -89,8 +89,8 @@ void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
// we try to yield every time we visit 10 regions
if (regions_visited == 10) {
if (sts.should_yield()) {
sts.yield();
if (sts_join.should_yield()) {
sts_join.yield();
// we just abandon the iteration
break;
}
@ -188,7 +188,7 @@ void ConcurrentG1RefineThread::run() {
}
{
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
do {
int curr_buffer_num = (int)dcqs.completed_buffers_num();

View File

@ -193,13 +193,8 @@ public:
_cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {}
void work(uint worker_id) {
if (_suspendible) {
SuspendibleThreadSet::join();
}
SuspendibleThreadSetJoiner sts_join(_suspendible);
G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer, true);
if (_suspendible) {
SuspendibleThreadSet::leave();
}
}
};
@ -275,7 +270,6 @@ bool CMMarkStack::allocate(size_t capacity) {
_capacity = (jint) capacity;
_saved_index = -1;
_should_expand = false;
NOT_PRODUCT(_max_depth = 0);
return true;
}
@ -331,54 +325,6 @@ CMMarkStack::~CMMarkStack() {
}
}
void CMMarkStack::par_push(oop ptr) {
while (true) {
if (isFull()) {
_overflow = true;
return;
}
// Otherwise...
jint index = _index;
jint next_index = index+1;
jint res = Atomic::cmpxchg(next_index, &_index, index);
if (res == index) {
_base[index] = ptr;
// Note that we don't maintain this atomically. We could, but it
// doesn't seem necessary.
NOT_PRODUCT(_max_depth = MAX2(_max_depth, next_index));
return;
}
// Otherwise, we need to try again.
}
}
void CMMarkStack::par_adjoin_arr(oop* ptr_arr, int n) {
while (true) {
if (isFull()) {
_overflow = true;
return;
}
// Otherwise...
jint index = _index;
jint next_index = index + n;
if (next_index > _capacity) {
_overflow = true;
return;
}
jint res = Atomic::cmpxchg(next_index, &_index, index);
if (res == index) {
for (int i = 0; i < n; i++) {
int ind = index + i;
assert(ind < _capacity, "By overflow test above.");
_base[ind] = ptr_arr[i];
}
NOT_PRODUCT(_max_depth = MAX2(_max_depth, next_index));
return;
}
// Otherwise, we need to try again.
}
}
void CMMarkStack::par_push_arr(oop* ptr_arr, int n) {
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
jint start = _index;
@ -394,7 +340,6 @@ void CMMarkStack::par_push_arr(oop* ptr_arr, int n) {
assert(ind < _capacity, "By overflow test above.");
_base[ind] = ptr_arr[i];
}
NOT_PRODUCT(_max_depth = MAX2(_max_depth, next_index));
}
bool CMMarkStack::par_pop_arr(oop* ptr_arr, int max, int* n) {
@ -1006,19 +951,17 @@ void ConcurrentMark::checkpointRootsInitialPost() {
*/
void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
bool barrier_aborted;
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] entering first barrier", worker_id);
}
if (concurrent()) {
SuspendibleThreadSet::leave();
{
SuspendibleThreadSetLeaver sts_leave(concurrent());
barrier_aborted = !_first_overflow_barrier_sync.enter();
}
bool barrier_aborted = !_first_overflow_barrier_sync.enter();
if (concurrent()) {
SuspendibleThreadSet::join();
}
// at this point everyone should have synced up and not be doing any
// more work
@ -1065,19 +1008,17 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
}
void ConcurrentMark::enter_second_sync_barrier(uint worker_id) {
bool barrier_aborted;
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] entering second barrier", worker_id);
}
if (concurrent()) {
SuspendibleThreadSet::leave();
{
SuspendibleThreadSetLeaver sts_leave(concurrent());
barrier_aborted = !_second_overflow_barrier_sync.enter();
}
bool barrier_aborted = !_second_overflow_barrier_sync.enter();
if (concurrent()) {
SuspendibleThreadSet::join();
}
// at this point everything should be re-initialized and ready to go
if (verbose_low()) {
@ -1128,40 +1069,41 @@ public:
double start_vtime = os::elapsedVTime();
SuspendibleThreadSet::join();
{
SuspendibleThreadSetJoiner sts_join;
assert(worker_id < _cm->active_tasks(), "invariant");
CMTask* the_task = _cm->task(worker_id);
the_task->record_start_time();
if (!_cm->has_aborted()) {
do {
double start_vtime_sec = os::elapsedVTime();
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
assert(worker_id < _cm->active_tasks(), "invariant");
CMTask* the_task = _cm->task(worker_id);
the_task->record_start_time();
if (!_cm->has_aborted()) {
do {
double start_vtime_sec = os::elapsedVTime();
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
the_task->do_marking_step(mark_step_duration_ms,
true /* do_termination */,
false /* is_serial*/);
the_task->do_marking_step(mark_step_duration_ms,
true /* do_termination */,
false /* is_serial*/);
double end_vtime_sec = os::elapsedVTime();
double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
_cm->clear_has_overflown();
double end_vtime_sec = os::elapsedVTime();
double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
_cm->clear_has_overflown();
_cm->do_yield_check(worker_id);
_cm->do_yield_check(worker_id);
jlong sleep_time_ms;
if (!_cm->has_aborted() && the_task->has_aborted()) {
sleep_time_ms =
(jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0);
SuspendibleThreadSet::leave();
os::sleep(Thread::current(), sleep_time_ms, false);
SuspendibleThreadSet::join();
}
} while (!_cm->has_aborted() && the_task->has_aborted());
jlong sleep_time_ms;
if (!_cm->has_aborted() && the_task->has_aborted()) {
sleep_time_ms =
(jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0);
{
SuspendibleThreadSetLeaver sts_leave;
os::sleep(Thread::current(), sleep_time_ms, false);
}
}
} while (!_cm->has_aborted() && the_task->has_aborted());
}
the_task->record_end_time();
guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant");
}
the_task->record_end_time();
guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant");
SuspendibleThreadSet::leave();
double end_vtime = os::elapsedVTime();
_cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);

View File

@ -180,25 +180,12 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC {
jint _index; // one more than last occupied index
jint _capacity; // max #elements
jint _saved_index; // value of _index saved at start of GC
NOT_PRODUCT(jint _max_depth;) // max depth plumbed during run
bool _overflow;
bool _should_expand;
DEBUG_ONLY(bool _drain_in_progress;)
DEBUG_ONLY(bool _drain_in_progress_yields;)
public:
CMMarkStack(ConcurrentMark* cm);
~CMMarkStack();
#ifndef PRODUCT
jint max_depth() const {
return _max_depth;
}
#endif
bool allocate(size_t capacity);
oop pop() {
if (!isEmpty()) {
return _base[--_index] ;
@ -206,27 +193,11 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC {
return NULL;
}
// If overflow happens, don't do the push, and record the overflow.
// *Requires* that "ptr" is already marked.
void push(oop ptr) {
if (isFull()) {
// Record overflow.
_overflow = true;
return;
} else {
_base[_index++] = ptr;
NOT_PRODUCT(_max_depth = MAX2(_max_depth, _index));
}
}
// Non-block impl. Note: concurrency is allowed only with other
// "par_push" operations, not with "pop" or "drain". We would need
// parallel versions of them if such concurrency was desired.
void par_push(oop ptr);
public:
CMMarkStack(ConcurrentMark* cm);
~CMMarkStack();
// Pushes the first "n" elements of "ptr_arr" on the stack.
// Non-block impl. Note: concurrency is allowed only with other
// "par_adjoin_arr" or "push" operations, not with "pop" or "drain".
void par_adjoin_arr(oop* ptr_arr, int n);
bool allocate(size_t capacity);
// Pushes the first "n" elements of "ptr_arr" on the stack.
// Locking impl: concurrency is allowed only with
@ -254,7 +225,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC {
bool drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after = false);
bool isEmpty() { return _index == 0; }
bool isFull() { return _index == _capacity; }
int maxElems() { return _capacity; }
bool overflow() { return _overflow; }
@ -378,7 +348,6 @@ class ConcurrentMark: public CHeapObj<mtGC> {
friend class ConcurrentMarkThread;
friend class CMTask;
friend class CMBitMapClosure;
friend class CMGlobalObjectClosure;
friend class CMRemarkTask;
friend class CMConcurrentMarkingTask;
friend class G1ParNoteEndTask;
@ -473,8 +442,8 @@ protected:
// All of these times are in ms
NumberSeq _init_times;
NumberSeq _remark_times;
NumberSeq _remark_mark_times;
NumberSeq _remark_weak_ref_times;
NumberSeq _remark_mark_times;
NumberSeq _remark_weak_ref_times;
NumberSeq _cleanup_times;
double _total_counting_time;
double _total_rs_scrub_time;
@ -623,19 +592,9 @@ protected:
public:
// Manipulation of the global mark stack.
// Notice that the first mark_stack_push is CAS-based, whereas the
// two below are Mutex-based. This is OK since the first one is only
// called during evacuation pauses and doesn't compete with the
// other two (which are called by the marking tasks during
// concurrent marking or remark).
bool mark_stack_push(oop p) {
_markStack.par_push(p);
if (_markStack.overflow()) {
set_has_overflown();
return false;
}
return true;
}
// The push and pop operations are used by tasks for transfers
// between task-local queues and the global mark stack, and use
// locking for concurrency safety.
bool mark_stack_push(oop* arr, int n) {
_markStack.par_push_arr(arr, n);
if (_markStack.overflow()) {

View File

@ -192,7 +192,7 @@ void ConcurrentMarkThread::run() {
} else {
// We don't want to update the marking status if a GC pause
// is already underway.
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
g1h->set_marking_complete();
}
@ -262,7 +262,7 @@ void ConcurrentMarkThread::run() {
// not needed any more as the concurrent mark state has been
// already reset).
{
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
if (!cm()->has_aborted()) {
g1_policy->record_concurrent_mark_cleanup_completed();
}
@ -291,7 +291,7 @@ void ConcurrentMarkThread::run() {
// Java thread is waiting for a full GC to happen (e.g., it
// called System.gc() with +ExplicitGCInvokesConcurrent).
{
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
g1h->increment_old_marking_cycles_completed(true /* concurrent */);
g1h->register_concurrent_cycle_end();
}

View File

@ -1877,13 +1877,18 @@ jint G1CollectedHeap::initialize() {
// Carve out the G1 part of the heap.
ReservedSpace g1_rs = heap_rs.first_part(max_byte_size);
size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size();
G1RegionToSpaceMapper* heap_storage =
G1RegionToSpaceMapper::create_mapper(g1_rs,
g1_rs.size(),
UseLargePages ? os::large_page_size() : os::vm_page_size(),
page_size,
HeapRegion::GrainBytes,
1,
mtJavaHeap);
os::trace_page_sizes("G1 Heap", collector_policy()->min_heap_byte_size(),
max_byte_size, page_size,
heap_rs.base(),
heap_rs.size());
heap_storage->set_mapping_changed_listener(&_listener);
// Create storage for the BOT, card table, card counts table (hot card cache) and the bitmaps.

View File

@ -74,7 +74,7 @@ void G1StringDedupThread::run() {
{
// Include thread in safepoints
SuspendibleThreadSetJoiner sts;
SuspendibleThreadSetJoiner sts_join;
stat.mark_exec();
@ -88,9 +88,9 @@ void G1StringDedupThread::run() {
G1StringDedupTable::deduplicate(java_string, stat);
// Safepoint this thread if needed
if (sts.should_yield()) {
if (sts_join.should_yield()) {
stat.mark_block();
sts.yield();
sts_join.yield();
stat.mark_unblock();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, 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
@ -33,16 +33,20 @@ bool SuspendibleThreadSet::_suspend_all = false;
double SuspendibleThreadSet::_suspend_all_start = 0.0;
void SuspendibleThreadSet::join() {
assert(!Thread::current()->is_suspendible_thread(), "Thread already joined");
MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
while (_suspend_all) {
ml.wait(Mutex::_no_safepoint_check_flag);
}
_nthreads++;
DEBUG_ONLY(Thread::current()->set_suspendible_thread();)
}
void SuspendibleThreadSet::leave() {
assert(Thread::current()->is_suspendible_thread(), "Thread not joined");
MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
assert(_nthreads > 0, "Invalid");
DEBUG_ONLY(Thread::current()->clear_suspendible_thread();)
_nthreads--;
if (_suspend_all) {
ml.notify_all();
@ -50,6 +54,7 @@ void SuspendibleThreadSet::leave() {
}
void SuspendibleThreadSet::yield() {
assert(Thread::current()->is_suspendible_thread(), "Must have joined");
if (_suspend_all) {
MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
if (_suspend_all) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, 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
@ -36,19 +36,22 @@
// suspending thread later calls desynchronize(), allowing the suspended
// threads to continue.
class SuspendibleThreadSet : public AllStatic {
friend class SuspendibleThreadSetJoiner;
friend class SuspendibleThreadSetLeaver;
private:
static uint _nthreads;
static uint _nthreads_stopped;
static bool _suspend_all;
static double _suspend_all_start;
public:
// Add the current thread to the set. May block if a suspension is in progress.
static void join();
// Removes the current thread from the set.
static void leave();
public:
// Returns true if an suspension is in progress.
static bool should_yield() { return _suspend_all; }
@ -63,22 +66,52 @@ public:
};
class SuspendibleThreadSetJoiner : public StackObj {
private:
bool _active;
public:
SuspendibleThreadSetJoiner() {
SuspendibleThreadSet::join();
SuspendibleThreadSetJoiner(bool active = true) : _active(active) {
if (_active) {
SuspendibleThreadSet::join();
}
}
~SuspendibleThreadSetJoiner() {
SuspendibleThreadSet::leave();
if (_active) {
SuspendibleThreadSet::leave();
}
}
bool should_yield() {
return SuspendibleThreadSet::should_yield();
if (_active) {
return SuspendibleThreadSet::should_yield();
} else {
return false;
}
}
void yield() {
assert(_active, "Thread has not joined the suspendible thread set");
SuspendibleThreadSet::yield();
}
};
class SuspendibleThreadSetLeaver : public StackObj {
private:
bool _active;
public:
SuspendibleThreadSetLeaver(bool active = true) : _active(active) {
if (_active) {
SuspendibleThreadSet::leave();
}
}
~SuspendibleThreadSetLeaver() {
if (_active) {
SuspendibleThreadSet::join();
}
}
};
#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP

View File

@ -53,7 +53,7 @@ void PeriodicTask::real_time_tick(int delay_time) {
if (ProfilerCheckIntervals) {
_ticks++;
_timer.stop();
int ms = (int)(_timer.seconds() * 1000.0);
int ms = (int)_timer.milliseconds();
_timer.reset();
_timer.start();
if (ms >= PeriodicTask::max_interval) ms = PeriodicTask::max_interval - 1;

View File

@ -190,6 +190,7 @@ Thread::Thread() {
set_stack_size(0);
set_self_raw_id(0);
set_lgrp_id(-1);
DEBUG_ONLY(clear_suspendible_thread();)
// allocated data structures
set_osthread(NULL);

View File

@ -204,11 +204,25 @@ class Thread: public ThreadShadow {
private:
int _num_nested_signal;
DEBUG_ONLY(bool _suspendible_thread;)
public:
void enter_signal_handler() { _num_nested_signal++; }
void leave_signal_handler() { _num_nested_signal--; }
bool is_inside_signal_handler() const { return _num_nested_signal > 0; }
#ifdef ASSERT
void set_suspendible_thread() {
_suspendible_thread = true;
}
void clear_suspendible_thread() {
_suspendible_thread = false;
}
bool is_suspendible_thread() { return _suspendible_thread; }
#endif
private:
// Active_handles points to a block of handles
JNIHandleBlock* _active_handles;

View File

@ -28,9 +28,12 @@
#include "utilities/ostream.hpp"
double TimeHelper::counter_to_seconds(jlong counter) {
double count = (double) counter;
double freq = (double) os::elapsed_frequency();
return counter/freq;
return counter / freq;
}
double TimeHelper::counter_to_millis(jlong counter) {
return counter_to_seconds(counter) * 1000.0;
}
void elapsedTimer::add(elapsedTimer t) {
@ -56,8 +59,7 @@ double elapsedTimer::seconds() const {
}
jlong elapsedTimer::milliseconds() const {
jlong ticks_per_ms = os::elapsed_frequency() / 1000;
return _counter / ticks_per_ms;
return TimeHelper::counter_to_millis(_counter);
}
jlong elapsedTimer::active_ticks() const {
@ -86,11 +88,8 @@ double TimeStamp::seconds() const {
jlong TimeStamp::milliseconds() const {
assert(is_updated(), "must not be clear");
jlong new_count = os::elapsed_counter();
jlong count = new_count - _counter;
jlong ticks_per_ms = os::elapsed_frequency() / 1000;
return count / ticks_per_ms;
return TimeHelper::counter_to_millis(new_count - _counter);
}
jlong TimeStamp::ticks_since_update() const {

View File

@ -123,6 +123,7 @@ class TraceCPUTime: public StackObj {
class TimeHelper {
public:
static double counter_to_seconds(jlong counter);
static double counter_to_millis(jlong counter);
};
#endif // SHARE_VM_RUNTIME_TIMER_HPP