8264788: Make SequentialSubTasksDone use-once

Reviewed-by: ayang, sjohanss
This commit is contained in:
Thomas Schatzl 2021-04-15 08:11:01 +00:00
parent 0793fcbbca
commit 125a8479a9
5 changed files with 23 additions and 91 deletions

View file

@ -2056,18 +2056,15 @@ public:
MarkFromRootsTask(uint active_workers) : MarkFromRootsTask(uint active_workers) :
AbstractGangTask("MarkFromRootsTask"), AbstractGangTask("MarkFromRootsTask"),
_strong_roots_scope(active_workers), _strong_roots_scope(active_workers),
_subtasks(), _subtasks(ParallelRootType::sentinel),
_terminator(active_workers, ParCompactionManager::oop_task_queues()), _terminator(active_workers, ParCompactionManager::oop_task_queues()),
_active_workers(active_workers) { _active_workers(active_workers) {
_subtasks.set_n_threads(active_workers);
_subtasks.set_n_tasks(ParallelRootType::sentinel);
} }
virtual void work(uint worker_id) { virtual void work(uint worker_id) {
for (uint task = 0; _subtasks.try_claim_task(task); /*empty*/ ) { for (uint task = 0; _subtasks.try_claim_task(task); /*empty*/ ) {
mark_from_roots_work(static_cast<ParallelRootType::Value>(task), worker_id); mark_from_roots_work(static_cast<ParallelRootType::Value>(task), worker_id);
} }
_subtasks.all_tasks_completed();
PCAddThreadRootsMarkingTaskClosure closure(worker_id); PCAddThreadRootsMarkingTaskClosure closure(worker_id);
Threads::possibly_parallel_threads_do(true /*parallel */, &closure); Threads::possibly_parallel_threads_do(true /*parallel */, &closure);

View file

@ -304,14 +304,12 @@ public:
bool is_empty) : bool is_empty) :
AbstractGangTask("ScavengeRootsTask"), AbstractGangTask("ScavengeRootsTask"),
_strong_roots_scope(active_workers), _strong_roots_scope(active_workers),
_subtasks(), _subtasks(ParallelRootType::sentinel),
_old_gen(old_gen), _old_gen(old_gen),
_gen_top(gen_top), _gen_top(gen_top),
_active_workers(active_workers), _active_workers(active_workers),
_is_empty(is_empty), _is_empty(is_empty),
_terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) { _terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) {
_subtasks.set_n_threads(active_workers);
_subtasks.set_n_tasks(ParallelRootType::sentinel);
} }
virtual void work(uint worker_id) { virtual void work(uint worker_id) {
@ -346,7 +344,6 @@ public:
for (uint root_type = 0; _subtasks.try_claim_task(root_type); /* empty */ ) { for (uint root_type = 0; _subtasks.try_claim_task(root_type); /* empty */ ) {
scavenge_roots_work(static_cast<ParallelRootType::Value>(root_type), worker_id); scavenge_roots_work(static_cast<ParallelRootType::Value>(root_type), worker_id);
} }
_subtasks.all_tasks_completed();
PSThreadRootsTaskClosure closure(worker_id); PSThreadRootsTaskClosure closure(worker_id);
Threads::possibly_parallel_threads_do(true /*parallel */, &closure); Threads::possibly_parallel_threads_do(true /*parallel */, &closure);

View file

@ -104,18 +104,15 @@ public:
while (_sub_tasks.try_claim_task(/* reference */ task_id)) { while (_sub_tasks.try_claim_task(/* reference */ task_id)) {
_preserved_marks_set->get(task_id)->restore_and_increment(_total_size_addr); _preserved_marks_set->get(task_id)->restore_and_increment(_total_size_addr);
} }
_sub_tasks.all_tasks_completed();
} }
ParRestoreTask(uint worker_num, ParRestoreTask(PreservedMarksSet* preserved_marks_set,
PreservedMarksSet* preserved_marks_set,
volatile size_t* total_size_addr) volatile size_t* total_size_addr)
: AbstractGangTask("Parallel Preserved Mark Restoration"), : AbstractGangTask("Parallel Preserved Mark Restoration"),
_preserved_marks_set(preserved_marks_set), _preserved_marks_set(preserved_marks_set),
_sub_tasks(preserved_marks_set->num()),
_total_size_addr(total_size_addr) { _total_size_addr(total_size_addr) {
_sub_tasks.set_n_threads(worker_num); }
_sub_tasks.set_n_tasks(preserved_marks_set->num());
}
}; };
void PreservedMarksSet::restore(WorkGang* workers) { void PreservedMarksSet::restore(WorkGang* workers) {
@ -127,7 +124,7 @@ void PreservedMarksSet::restore(WorkGang* workers) {
for (uint i = 0; i < _num; i += 1) { for (uint i = 0; i < _num; i += 1) {
total_size_before += get(i)->size(); total_size_before += get(i)->size();
} }
#endif // def ASSERT #endif // ASSERT
if (workers == NULL) { if (workers == NULL) {
for (uint i = 0; i < num(); i += 1) { for (uint i = 0; i < num(); i += 1) {
@ -135,7 +132,7 @@ void PreservedMarksSet::restore(WorkGang* workers) {
get(i)->restore(); get(i)->restore();
} }
} else { } else {
ParRestoreTask task(workers->active_workers(), this, &total_size); ParRestoreTask task(this, &total_size);
workers->run_task(&task); workers->run_task(&task);
} }

View file

@ -399,39 +399,10 @@ SubTasksDone::~SubTasksDone() {
// *** SequentialSubTasksDone // *** SequentialSubTasksDone
void SequentialSubTasksDone::clear() {
_n_tasks = _n_claimed = 0;
_n_threads = _n_completed = 0;
}
bool SequentialSubTasksDone::valid() {
return _n_threads > 0;
}
bool SequentialSubTasksDone::try_claim_task(uint& t) { bool SequentialSubTasksDone::try_claim_task(uint& t) {
t = _n_claimed; t = _num_claimed;
while (t < _n_tasks) { if (t < _num_tasks) {
uint res = Atomic::cmpxchg(&_n_claimed, t, t+1); t = Atomic::add(&_num_claimed, 1u) - 1;
if (res == t) {
return true;
}
t = res;
} }
return false; return t < _num_tasks;
}
bool SequentialSubTasksDone::all_tasks_completed() {
uint complete = _n_completed;
while (true) {
uint res = Atomic::cmpxchg(&_n_completed, complete, complete+1);
if (res == complete) {
break;
}
complete = res;
}
if (complete+1 == _n_threads) {
clear();
return true;
}
return false;
} }

View file

@ -346,57 +346,27 @@ public:
// sub-tasks from a set (possibly an enumeration), claim sub-tasks // sub-tasks from a set (possibly an enumeration), claim sub-tasks
// in sequential order. This is ideal for claiming dynamically // in sequential order. This is ideal for claiming dynamically
// partitioned tasks (like striding in the parallel remembered // partitioned tasks (like striding in the parallel remembered
// set scanning). Note that unlike the above class this is // set scanning).
// a stack object - is there any reason for it not to be?
class SequentialSubTasksDone : public StackObj { class SequentialSubTasksDone : public CHeapObj<mtInternal> {
protected:
uint _n_tasks; // Total number of tasks available.
volatile uint _n_claimed; // Number of tasks claimed.
// _n_threads is used to determine when a sub task is done.
// See comments on SubTasksDone::_n_threads
uint _n_threads; // Total number of parallel threads.
volatile uint _n_completed; // Number of completed threads.
void clear(); uint _num_tasks; // Total number of tasks available.
volatile uint _num_claimed; // Number of tasks claimed.
NONCOPYABLE(SequentialSubTasksDone);
public: public:
SequentialSubTasksDone() { SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { }
clear(); ~SequentialSubTasksDone() {
// Claiming may try to claim more tasks than there are.
assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks);
} }
~SequentialSubTasksDone() {}
// True iff the object is in a valid state.
bool valid();
// number of tasks
uint n_tasks() const { return _n_tasks; }
// Get/set the number of parallel threads doing the tasks to t.
// Should be called before the task starts but it is safe
// to call this once a task is running provided that all
// threads agree on the number of threads.
uint n_threads() { return _n_threads; }
void set_n_threads(uint t) { _n_threads = t; }
// Set the number of tasks to be claimed to t. As above,
// should be called before the tasks start but it is safe
// to call this once a task is running provided all threads
// agree on the number of tasks.
void set_n_tasks(uint t) { _n_tasks = t; }
// Attempt to claim the next unclaimed task in the sequence, // Attempt to claim the next unclaimed task in the sequence,
// returning true if successful, with t set to the index of the // returning true if successful, with t set to the index of the
// claimed task. Returns false if there are no more unclaimed tasks // claimed task. Returns false if there are no more unclaimed tasks
// in the sequence. // in the sequence. In this case t is undefined.
bool try_claim_task(uint& t); bool try_claim_task(uint& t);
// The calling thread asserts that it has attempted to claim
// all the tasks it possibly can in the sequence. Every thread
// claiming tasks must promise call this. Returns true if this
// is the last thread to complete so that the thread can perform
// cleanup if necessary.
bool all_tasks_completed();
}; };
#endif // SHARE_GC_SHARED_WORKGROUP_HPP #endif // SHARE_GC_SHARED_WORKGROUP_HPP