代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/openjdk-1.8.0 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 99b38421c0da651ded6d5bd4d39ce1a7f6675188 Mon Sep 17 00:00:00 2001
Date: Fri, 22 Jan 2021 16:14:06 +0800
Subject: 8205921: Optimizing best-of-2 work stealing queue
selection
Summary: <gc>: Improve gc performance, optimizing best-of-2 work stealing queue selection
LLT: jtreg
Bug url: https://bugs.openjdk.java.net/browse/JDK-8205921
---
.../concurrentMarkSweepGeneration.cpp | 29 ++---
.../concurrentMarkSweepGeneration.hpp | 3 -
.../gc_implementation/g1/concurrentMark.cpp | 4 +-
.../gc_implementation/g1/concurrentMark.hpp | 6 +-
.../g1/g1ParScanThreadState.cpp | 2 +-
.../g1/g1ParScanThreadState.hpp | 2 -
.../g1/g1ParScanThreadState.inline.hpp | 2 +-
.../parNew/parNewGeneration.cpp | 2 -
.../parNew/parNewGeneration.hpp | 2 -
.../parallelScavenge/pcTasks.cpp | 8 +-
.../parallelScavenge/psCompactionManager.hpp | 12 +-
.../parallelScavenge/psPromotionManager.hpp | 4 +-
.../parallelScavenge/psTasks.cpp | 3 +-
hotspot/src/share/vm/utilities/taskqueue.cpp | 18 ---
hotspot/src/share/vm/utilities/taskqueue.hpp | 105 ++++++++++++++----
16 files changed, 112 insertions(+), 90 deletions(-)
diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
index 02a29c2b0..53b75a4ca 100644
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
@@ -680,11 +680,6 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
warning("task_queues allocation failure.");
return;
}
- _hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC);
- if (_hash_seed == NULL) {
- warning("_hash_seed array allocation failure");
- return;
- }
typedef Padded<OopTaskQueue> PaddedOopTaskQueue;
for (i = 0; i < num_queues; i++) {
@@ -697,7 +692,6 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
}
for (i = 0; i < num_queues; i++) {
_task_queues->queue(i)->initialize();
- _hash_seed[i] = 17; // copied from ParNew
}
}
}
@@ -4391,7 +4385,6 @@ void CMSConcMarkingTask::do_work_steal(int i) {
oop obj_to_scan;
CMSBitMap* bm = &(_collector->_markBitMap);
CMSMarkStack* ovflw = &(_collector->_markStack);
- int* seed = _collector->hash_seed(i);
Par_ConcMarkingClosure cl(_collector, this, work_q, bm, ovflw);
while (true) {
cl.trim_queue(0);
@@ -4401,7 +4394,7 @@ void CMSConcMarkingTask::do_work_steal(int i) {
// overflow stack may already have been stolen from us.
// assert(work_q->size() > 0, "Work from overflow stack");
continue;
- } else if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
+ } else if (task_queues()->steal(i, /* reference */ obj_to_scan)) {
assert(obj_to_scan->is_oop(), "Should be an oop");
assert(bm->isMarked((HeapWord*)obj_to_scan), "Grey object");
obj_to_scan->oop_iterate(&cl);
@@ -5373,7 +5366,7 @@ class CMSParRemarkTask: public CMSParMarkTask {
Par_MarkRefsIntoAndScanClosure* cl);
// ... work stealing for the above
- void do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl, int* seed);
+ void do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl);
};
class RemarkKlassClosure : public KlassClosure {
@@ -5539,7 +5532,7 @@ void CMSParRemarkTask::work(uint worker_id) {
// ---------- ... and drain overflow list.
_timer.reset();
_timer.start();
- do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id));
+ do_work_steal(worker_id, &par_mrias_cl);
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
@@ -5696,8 +5689,7 @@ CMSParRemarkTask::do_dirty_card_rescan_tasks(
// . see if we can share work_queues with ParNew? XXX
void
-CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl,
- int* seed) {
+CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl) {
OopTaskQueue* work_q = work_queue(i);
NOT_PRODUCT(int num_steals = 0;)
oop obj_to_scan;
@@ -5728,7 +5720,7 @@ CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl,
// Verify that we have no work before we resort to stealing
assert(work_q->size() == 0, "Have work, shouldn't steal");
// Try to steal from other queues that have work
- if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
+ if (task_queues()->steal(i,/* reference */ obj_to_scan)) {
NOT_PRODUCT(num_steals++;)
assert(obj_to_scan->is_oop(), "Oops, not an oop!");
assert(bm->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
@@ -6141,8 +6133,7 @@ public:
void do_work_steal(int i,
CMSParDrainMarkingStackClosure* drain,
- CMSParKeepAliveClosure* keep_alive,
- int* seed);
+ CMSParKeepAliveClosure* keep_alive);
virtual void work(uint worker_id);
};
@@ -6160,8 +6151,7 @@ void CMSRefProcTaskProxy::work(uint worker_id) {
CMSIsAliveClosure is_alive_closure(_span, _mark_bit_map);
_task.work(worker_id, is_alive_closure, par_keep_alive, par_drain_stack);
if (_task.marks_oops_alive()) {
- do_work_steal(worker_id, &par_drain_stack, &par_keep_alive,
- _collector->hash_seed(worker_id));
+ do_work_steal(worker_id, &par_drain_stack, &par_keep_alive);
}
assert(work_queue(worker_id)->size() == 0, "work_queue should be empty");
assert(_collector->_overflow_list == NULL, "non-empty _overflow_list");
@@ -6196,8 +6186,7 @@ CMSParKeepAliveClosure::CMSParKeepAliveClosure(CMSCollector* collector,
// . see if we can share work_queues with ParNew? XXX
void CMSRefProcTaskProxy::do_work_steal(int i,
CMSParDrainMarkingStackClosure* drain,
- CMSParKeepAliveClosure* keep_alive,
- int* seed) {
+ CMSParKeepAliveClosure* keep_alive) {
OopTaskQueue* work_q = work_queue(i);
NOT_PRODUCT(int num_steals = 0;)
oop obj_to_scan;
@@ -6226,7 +6215,7 @@ void CMSRefProcTaskProxy::do_work_steal(int i,
// Verify that we have no work before we resort to stealing
assert(work_q->size() == 0, "Have work, shouldn't steal");
// Try to steal from other queues that have work
- if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
+ if (task_queues()->steal(i, /* reference */ obj_to_scan)) {
NOT_PRODUCT(num_steals++;)
assert(obj_to_scan->is_oop(), "Oops, not an oop!");
assert(_mark_bit_map->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
index 8b65d3426..ca3fee21b 100644
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
@@ -563,8 +563,6 @@ class CMSCollector: public CHeapObj<mtGC> {
Stack<oop, mtGC> _preserved_oop_stack;
Stack<markOop, mtGC> _preserved_mark_stack;
- int* _hash_seed;
-
// In support of multi-threaded concurrent phases
YieldingFlexibleWorkGang* _conc_workers;
@@ -741,7 +739,6 @@ class CMSCollector: public CHeapObj<mtGC> {
bool stop_world_and_do(CMS_op_type op);
OopTaskQueueSet* task_queues() { return _task_queues; }
- int* hash_seed(int i) { return &_hash_seed[i]; }
YieldingFlexibleWorkGang* conc_workers() { return _conc_workers; }
// Support for parallelizing Eden rescan in CMS remark phase
diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp
index f7b64a61b..d782c892d 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp
@@ -4431,7 +4431,7 @@ void CMTask::do_marking_step(double time_target_ms,
oop obj;
statsOnly( ++_steal_attempts );
- if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
+ if (_cm->try_stealing(_worker_id, obj)) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] stolen " PTR_FORMAT " successfully",
_worker_id, p2i((void*) obj));
@@ -4614,7 +4614,7 @@ CMTask::CMTask(uint worker_id,
_worker_id(worker_id), _cm(cm),
_objArray_processor(this),
_claimed(false),
- _nextMarkBitMap(NULL), _hash_seed(17),
+ _nextMarkBitMap(NULL),
_task_queue(task_queue),
_task_queues(task_queues),
_cm_oop_closure(NULL),
diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp
index c22c9b601..3404be2a3 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp
@@ -680,8 +680,8 @@ public:
}
// Attempts to steal an object from the task queues of other tasks
- bool try_stealing(uint worker_id, int* hash_seed, oop& obj) {
- return _task_queues->steal(worker_id, hash_seed, obj);
+ bool try_stealing(uint worker_id, oop& obj) {
+ return _task_queues->steal(worker_id, obj);
}
ConcurrentMark(G1CollectedHeap* g1h,
@@ -1007,8 +1007,6 @@ private:
// it was decreased).
size_t _real_refs_reached_limit;
- // used by the work stealing stuff
- int _hash_seed;
// if this is true, then the task has aborted for some reason
bool _has_aborted;
// set when the task aborts because it has met its time quota
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp
index e765620bc..394f20e82 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp
@@ -36,7 +36,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num,
_dcq(&g1h->dirty_card_queue_set()),
_ct_bs(g1h->g1_barrier_set()),
_g1_rem(g1h->g1_rem_set()),
- _hash_seed(17), _queue_num(queue_num),
+ _queue_num(queue_num),
_term_attempts(0),
_tenuring_threshold(g1h->g1_policy()->tenuring_threshold()),
_age_table(false), _scanner(g1h, rp),
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp
index d9403aa43..990b71d31 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp
@@ -59,7 +59,6 @@ class G1ParScanThreadState : public StackObj {
OopsInHeapRegionClosure* _evac_failure_cl;
- int _hash_seed;
uint _queue_num;
size_t _term_attempts;
@@ -129,7 +128,6 @@ class G1ParScanThreadState : public StackObj {
OopsInHeapRegionClosure* evac_failure_closure() { return _evac_failure_cl; }
- int* hash_seed() { return &_hash_seed; }
uint queue_num() { return _queue_num; }
size_t term_attempts() const { return _term_attempts; }
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp
index 1b03f8caa..7dedb1517 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp
@@ -131,7 +131,7 @@ inline void G1ParScanThreadState::dispatch_reference(StarTask ref) {
void G1ParScanThreadState::steal_and_trim_queue(RefToScanQueueSet *task_queues) {
StarTask stolen_task;
- while (task_queues->steal(queue_num(), hash_seed(), stolen_task)) {
+ while (task_queues->steal(queue_num(), stolen_task)) {
assert(verify_task(stolen_task), "sanity");
dispatch_reference(stolen_task);
diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
index 84cd4ed73..c07e9b812 100644
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
@@ -92,7 +92,6 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
_survivor_chunk_array =
(ChunkArray*) old_gen()->get_data_recorder(thread_num());
- _hash_seed = 17; // Might want to take time-based random value.
_start = os::elapsedTime();
_old_gen_closure.set_generation(old_gen_);
_old_gen_root_closure.set_generation(old_gen_);
@@ -560,7 +559,6 @@ void ParEvacuateFollowersClosure::do_void() {
// attempt to steal work from promoted.
if (task_queues()->steal(par_scan_state()->thread_num(),
- par_scan_state()->hash_seed(),
obj_to_scan)) {
bool res = work_q->push(obj_to_scan);
assert(res, "Empty queue should have room for a push.");
diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
index fa4265a2d..ea527fdb5 100644
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
@@ -95,7 +95,6 @@ class ParScanThreadState {
HeapWord *_young_old_boundary;
- int _hash_seed;
int _thread_num;
ageTable _ageTable;
@@ -161,7 +160,6 @@ class ParScanThreadState {
// Is new_obj a candidate for scan_partial_array_and_push_remainder method.
inline bool should_be_partially_scanned(oop new_obj, oop old_obj) const;
- int* hash_seed() { return &_hash_seed; }
int thread_num() { return _thread_num; }
// Allocate a to-space block of size "sz", or else return NULL.
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
index 35ea2992b..37610f3d1 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
@@ -217,14 +217,13 @@ void StealMarkingTask::do_it(GCTaskManager* manager, uint which) {
oop obj = NULL;
ObjArrayTask task;
- int random_seed = 17;
do {
- while (ParCompactionManager::steal_objarray(which, &random_seed, task)) {
+ while (ParCompactionManager::steal_objarray(which, task)) {
ObjArrayKlass* k = (ObjArrayKlass*)task.obj()->klass();
k->oop_follow_contents(cm, task.obj(), task.index());
cm->follow_marking_stacks();
}
- while (ParCompactionManager::steal(which, &random_seed, obj)) {
+ while (ParCompactionManager::steal(which, obj)) {
obj->follow_contents(cm);
cm->follow_marking_stacks();
}
@@ -280,13 +279,12 @@ void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) {
cm->drain_region_stacks();
size_t region_index = 0;
- int random_seed = 17;
// If we're the termination task, try 10 rounds of stealing before
// setting the termination flag
while(true) {
- if (ParCompactionManager::steal(which, &random_seed, region_index)) {
+ if (ParCompactionManager::steal(which, region_index)) {
PSParallelCompact::fill_and_update_region(cm, region_index);
cm->drain_region_stacks();
} else {
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp
index 7d7a9f495..a16a16762 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp
@@ -177,16 +177,16 @@ private:
// Access function for compaction managers
static ParCompactionManager* gc_thread_compaction_manager(int index);
- static bool steal(int queue_num, int* seed, oop& t) {
- return stack_array()->steal(queue_num, seed, t);
+ static bool steal(int queue_num, oop& t) {
+ return stack_array()->steal(queue_num, t);
}
- static bool steal_objarray(int queue_num, int* seed, ObjArrayTask& t) {
- return _objarray_queues->steal(queue_num, seed, t);
+ static bool steal_objarray(int queue_num, ObjArrayTask& t) {
+ return _objarray_queues->steal(queue_num, t);
}
- static bool steal(int queue_num, int* seed, size_t& region) {
- return region_array()->steal(queue_num, seed, region);
+ static bool steal(int queue_num, size_t& region) {
+ return region_array()->steal(queue_num, region);
}
// Process tasks remaining on any marking stack
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
index 6eef954b7..542d86943 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
@@ -164,8 +164,8 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
static PSPromotionManager* gc_thread_promotion_manager(int index);
static PSPromotionManager* vm_thread_promotion_manager();
- static bool steal_depth(int queue_num, int* seed, StarTask& t) {
- return stack_array_depth()->steal(queue_num, seed, t);
+ static bool steal_depth(int queue_num, StarTask& t) {
+ return stack_array_depth()->steal(queue_num, t);
}
PSPromotionManager();
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
index f829e9344..4fe869fd6 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp
@@ -151,10 +151,9 @@ void StealTask::do_it(GCTaskManager* manager, uint which) {
guarantee(pm->stacks_empty(),
"stacks should be empty at this point");
- int random_seed = 17;
while(true) {
StarTask p;
- if (PSPromotionManager::steal_depth(which, &random_seed, p)) {
+ if (PSPromotionManager::steal_depth(which, p)) {
TASKQUEUE_STATS_ONLY(pm->record_steal(p));
pm->process_popped_location_depth(p);
pm->drain_stacks_depth(true);
diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp
index 0f4dcc90b..37f4066ab 100644
--- a/hotspot/src/share/vm/utilities/taskqueue.cpp
+++ b/hotspot/src/share/vm/utilities/taskqueue.cpp
@@ -112,24 +112,6 @@ void TaskQueueStats::verify() const
#endif // ASSERT
#endif // TASKQUEUE_STATS
-int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
- const int a = 16807;
- const int m = 2147483647;
- const int q = 127773; /* m div a */
- const int r = 2836; /* m mod a */
- assert(sizeof(int) == 4, "I think this relies on that");
- int seed = *seed0;
- int hi = seed / q;
- int lo = seed % q;
- int test = a * lo - r * hi;
- if (test > 0)
- seed = test;
- else
- seed = test + m;
- *seed0 = seed;
- return seed;
-}
-
ParallelTaskTerminator::
ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
_n_threads(n_threads),
diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp
index 0f1376b49..77556a7d4 100644
--- a/hotspot/src/share/vm/utilities/taskqueue.hpp
+++ b/hotspot/src/share/vm/utilities/taskqueue.hpp
@@ -309,12 +309,30 @@ public:
void oops_do(OopClosure* f);
private:
+ DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
// Element array.
volatile E* _elems;
+
+ DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(E*));
+ // Queue owner local variables. Not to be accessed by other threads.
+
+ static const uint InvalidQueueId = uint(-1);
+ uint _last_stolen_queue_id; // The id of the queue we last stole from
+
+ int _seed; // Current random seed used for selecting a random queue during stealing.
+
+ DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(uint) + sizeof(int));
+public:
+ int next_random_queue_id();
+
+ void set_last_stolen_queue_id(uint id) { _last_stolen_queue_id = id; }
+ uint last_stolen_queue_id() const { return _last_stolen_queue_id; }
+ bool is_last_stolen_queue_id_valid() const { return _last_stolen_queue_id != InvalidQueueId; }
+ void invalidate_last_stolen_queue_id() { _last_stolen_queue_id = InvalidQueueId; }
};
template<class E, MEMFLAGS F, unsigned int N>
-GenericTaskQueue<E, F, N>::GenericTaskQueue() {
+GenericTaskQueue<E, F, N>::GenericTaskQueue() : _last_stolen_queue_id(InvalidQueueId), _seed(17 /* random number */) {
assert(sizeof(Age) == sizeof(size_t), "Depends on this.");
}
@@ -429,6 +447,30 @@ bool GenericTaskQueue<E, F, N>::pop_global(volatile E& t) {
return resAge == oldAge;
}
+inline int randomParkAndMiller(int *seed0) {
+ const int a = 16807;
+ const int m = 2147483647;
+ const int q = 127773; /* m div a */
+ const int r = 2836; /* m mod a */
+ STATIC_ASSERT(sizeof(int) == 4);
+ int seed = *seed0;
+ int hi = seed / q;
+ int lo = seed % q;
+ int test = a * lo - r * hi;
+ if (test > 0) {
+ seed = test;
+ } else {
+ seed = test + m;
+ }
+ *seed0 = seed;
+ return seed;
+}
+
+template<class E, MEMFLAGS F, unsigned int N>
+int GenericTaskQueue<E, F, N>::next_random_queue_id() {
+ return randomParkAndMiller(&_seed);
+}
+
template<class E, MEMFLAGS F, unsigned int N>
GenericTaskQueue<E, F, N>::~GenericTaskQueue() {}
@@ -498,8 +540,6 @@ bool OverflowTaskQueue<E, F, N>::try_push_to_taskqueue(E t) {
return taskqueue_t::push(t);
}
class TaskQueueSetSuper {
-protected:
- static int randomParkAndMiller(int* seed0);
public:
// Returns "true" if some TaskQueue in the set contains a task.
virtual bool peek() = 0;
@@ -520,27 +560,23 @@ private:
public:
typedef typename T::element_type E;
- GenericTaskQueueSet(int n) : _n(n) {
+ GenericTaskQueueSet(uint n) : _n(n) {
typedef T* GenericTaskQueuePtr;
_queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n, F);
- for (int i = 0; i < n; i++) {
+ for (uint i = 0; i < n; i++) {
_queues[i] = NULL;
}
}
- bool steal_best_of_2(uint queue_num, int* seed, E& t);
+ bool steal_best_of_2(uint queue_num, E& t);
void register_queue(uint i, T* q);
T* queue(uint n);
- // The thread with queue number "queue_num" (and whose random number seed is
- // at "seed") is trying to steal a task from some other queue. (It may try
- // several queues, according to some configuration parameter.) If some steal
- // succeeds, returns "true" and sets "t" to the stolen task, otherwise returns
- // false.
- bool steal(uint queue_num, int* seed, E& t);
-
+ // Try to steal a task from some other queue than queue_num. It may perform several attempts at doing so.
+ // Returns if stealing succeeds, and sets "t" to the stolen task.
+ bool steal(uint queue_num, E& t);
bool peek();
uint tasks() const;
size_t tasks();
@@ -560,9 +596,9 @@ GenericTaskQueueSet<T, F>::queue(uint i) {
}
template<class T, MEMFLAGS F> bool
-GenericTaskQueueSet<T, F>::steal(uint queue_num, int* seed, E& t) {
+GenericTaskQueueSet<T, F>::steal(uint queue_num, E& t) {
for (uint i = 0; i < 2 * _n; i++) {
- if (steal_best_of_2(queue_num, seed, t)) {
+ if (steal_best_of_2(queue_num, t)) {
TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true));
return true;
}
@@ -572,17 +608,46 @@ GenericTaskQueueSet<T, F>::steal(uint queue_num, int* seed, E& t) {
}
template<class T, MEMFLAGS F> bool
-GenericTaskQueueSet<T, F>::steal_best_of_2(uint queue_num, int* seed, E& t) {
+GenericTaskQueueSet<T, F>::steal_best_of_2(uint queue_num, E& t) {
if (_n > 2) {
+ T* const local_queue = _queues[queue_num];
uint k1 = queue_num;
- while (k1 == queue_num) k1 = TaskQueueSetSuper::randomParkAndMiller(seed) % _n;
+
+ if (local_queue->is_last_stolen_queue_id_valid()) {
+ k1 = local_queue->last_stolen_queue_id();
+ assert(k1 != queue_num, "Should not be the same");
+ } else {
+ while (k1 == queue_num) {
+ k1 = local_queue->next_random_queue_id() % _n;
+ }
+ }
+
uint k2 = queue_num;
- while (k2 == queue_num || k2 == k1) k2 = TaskQueueSetSuper::randomParkAndMiller(seed) % _n;
+ while (k2 == queue_num || k2 == k1) {
+ k2 = local_queue->next_random_queue_id() % _n;
+ }
// Sample both and try the larger.
uint sz1 = _queues[k1]->size();
uint sz2 = _queues[k2]->size();
- if (sz2 > sz1) return _queues[k2]->pop_global(t);
- else return _queues[k1]->pop_global(t);
+
+ uint sel_k = 0;
+ bool suc = false;
+
+ if (sz2 > sz1) {
+ sel_k = k2;
+ suc = _queues[k2]->pop_global(t);
+ } else if (sz1 > 0) {
+ sel_k = k1;
+ suc = _queues[k1]->pop_global(t);
+ }
+
+ if (suc) {
+ local_queue->set_last_stolen_queue_id(sel_k);
+ } else {
+ local_queue->invalidate_last_stolen_queue_id();
+ }
+
+ return suc;
} else if (_n == 2) {
// Just try the other one.
uint k = (queue_num + 1) % 2;
--
2.19.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。