Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8233281: Obsolete UseSemaphoreGCThreadsSynchronization
Reviewed-by: tschatzl, kbarrett, ayang
  • Loading branch information
stefank committed Aug 17, 2020
1 parent 0080bb6 commit cfc0f227aaf93c32b1e6d7cbe53e81c302020d2d
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 110 deletions.
@@ -174,10 +174,6 @@
"Number of parallel threads parallel gc will use") \
constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \
\
diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \
"Use semaphore synchronization for the GC Threads, " \
"instead of synchronization based on mutexes") \
\
product(bool, UseDynamicNumberOfGCThreads, true, \
"Dynamically choose the number of threads up to a maximum of " \
"ParallelGCThreads parallel collectors will use for garbage " \
@@ -109,7 +109,7 @@ static void run_foreground_task_if_needed(AbstractGangTask* task, uint num_worke
//
// Semaphores don't require the worker threads to re-claim the lock when they wake up.
// This helps lowering the latency when starting and stopping the worker threads.
class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
class GangTaskDispatcher : public CHeapObj<mtGC> {
// The task currently being dispatched to the GangWorkers.
AbstractGangTask* _task;

@@ -122,19 +122,23 @@ class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
Semaphore* _end_semaphore;

public:
SemaphoreGangTaskDispatcher() :
GangTaskDispatcher() :
_task(NULL),
_started(0),
_not_finished(0),
_start_semaphore(new Semaphore()),
_end_semaphore(new Semaphore())
{ }

~SemaphoreGangTaskDispatcher() {
~GangTaskDispatcher() {
delete _start_semaphore;
delete _end_semaphore;
}

// Coordinator API.

// Distributes the task out to num_workers workers.
// Returns when the task has been completed by all workers.
void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers, bool add_foreground_work) {
// No workers are allowed to read the state variables until they have been signaled.
_task = task;
@@ -155,6 +159,10 @@ class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {

}

// Worker API.

// Waits for a task to become available to the worker.
// Returns when the worker has been assigned a task.
WorkData worker_wait_for_task() {
// Wait for the coordinator to dispatch a task.
_start_semaphore->wait();
@@ -167,6 +175,7 @@ class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
return WorkData(_task, worker_id);
}

// Signal to the coordinator that the worker is done with the assigned task.
void worker_done_with_task() {
// Mark that the worker is done with the task.
// The worker is not allowed to read the state variables after this line.
@@ -179,91 +188,12 @@ class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
}
};

class MutexGangTaskDispatcher : public GangTaskDispatcher {
AbstractGangTask* _task;

volatile uint _started;
volatile uint _finished;
volatile uint _num_workers;

Monitor* _monitor;

public:
MutexGangTaskDispatcher() :
_task(NULL),
_started(0),
_finished(0),
_num_workers(0),
_monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)) {
}

~MutexGangTaskDispatcher() {
delete _monitor;
}

void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers, bool add_foreground_work) {
MonitorLocker ml(_monitor, Mutex::_no_safepoint_check_flag);

_task = task;
_num_workers = num_workers;

// Tell the workers to get to work.
_monitor->notify_all();

run_foreground_task_if_needed(task, num_workers, add_foreground_work);

// Wait for them to finish.
while (_finished < _num_workers) {
ml.wait();
}

_task = NULL;
_num_workers = 0;
_started = 0;
_finished = 0;
}

WorkData worker_wait_for_task() {
MonitorLocker ml(_monitor, Mutex::_no_safepoint_check_flag);

while (_num_workers == 0 || _started == _num_workers) {
_monitor->wait();
}

_started++;

// Subtract one to get a zero-indexed worker id.
uint worker_id = _started - 1;

return WorkData(_task, worker_id);
}

void worker_done_with_task() {
MonitorLocker ml(_monitor, Mutex::_no_safepoint_check_flag);

_finished++;

if (_finished == _num_workers) {
// This will wake up all workers and not only the coordinator.
_monitor->notify_all();
}
}
};

static GangTaskDispatcher* create_dispatcher() {
if (UseSemaphoreGCThreadsSynchronization) {
return new SemaphoreGangTaskDispatcher();
}

return new MutexGangTaskDispatcher();
}

WorkGang::WorkGang(const char* name,
uint workers,
bool are_GC_task_threads,
bool are_ConcurrentGC_threads) :
AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
_dispatcher(create_dispatcher())
_dispatcher(new GangTaskDispatcher())
{ }

WorkGang::~WorkGang() {
@@ -52,6 +52,7 @@ class AbstractGangWorker;
class Semaphore;
class ThreadClosure;
class WorkGang;
class GangTaskDispatcher;

// An abstract task to be worked on by a gang.
// You subclass this to supply your own work() method
@@ -80,29 +81,6 @@ struct WorkData {
WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {}
};

// Interface to handle the synchronization between the coordinator thread and the worker threads,
// when a task is dispatched out to the worker threads.
class GangTaskDispatcher : public CHeapObj<mtGC> {
public:
virtual ~GangTaskDispatcher() {}

// Coordinator API.

// Distributes the task out to num_workers workers.
// Returns when the task has been completed by all workers.
virtual void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers,
bool add_foreground_work) = 0;

// Worker API.

// Waits for a task to become available to the worker.
// Returns when the worker has been assigned a task.
virtual WorkData worker_wait_for_task() = 0;

// Signal to the coordinator that the worker is done with the assigned task.
virtual void worker_done_with_task() = 0;
};

// The work gang is the collection of workers to execute tasks.
// The number of workers run for a task is "_active_workers"
// while "_total_workers" is the number of available of workers.
@@ -552,6 +552,7 @@ static SpecialFlag const special_jvm_flags[] = {
#endif
{ "PrintVMQWaitTime", JDK_Version::jdk(15), JDK_Version::jdk(16), JDK_Version::jdk(17) },
{ "UseNewFieldLayout", JDK_Version::jdk(15), JDK_Version::jdk(16), JDK_Version::jdk(17) },
{ "UseSemaphoreGCThreadsSynchronization", JDK_Version::undefined(), JDK_Version::jdk(16), JDK_Version::jdk(17) },

#ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
// These entries will generate build errors. Their purpose is to test the macros.

0 comments on commit cfc0f22

Please sign in to comment.