--- old/src/hotspot/share/gc/shared/gc_globals.hpp 2018-06-21 16:45:13.281299202 -0400 +++ new/src/hotspot/share/gc/shared/gc_globals.hpp 2018-06-21 16:45:13.018297908 -0400 @@ -201,6 +201,9 @@ experimental(bool, UseZGC, false, \ "Use the Z garbage collector") \ \ + experimental(bool, UseOptimizedBestOfTwo, true, \ + "Use optimized best of two task stealing algorithm") \ + \ product(uint, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \ --- old/src/hotspot/share/gc/shared/taskqueue.hpp 2018-06-21 16:45:13.786301687 -0400 +++ new/src/hotspot/share/gc/shared/taskqueue.hpp 2018-06-21 16:45:13.535300452 -0400 @@ -396,9 +396,12 @@ template class GenericTaskQueueSet: public TaskQueueSetSuperImpl { + static const uint INVALID_QUEUE_ID = uint(-1); + private: - uint _n; - T** _queues; + uint _n; + T** _queues; + uint* _last_stolen_queues; public: typedef typename T::element_type E; --- old/src/hotspot/share/gc/shared/taskqueue.inline.hpp 2018-06-21 16:45:14.283304132 -0400 +++ new/src/hotspot/share/gc/shared/taskqueue.inline.hpp 2018-06-21 16:45:14.029302882 -0400 @@ -37,14 +37,22 @@ inline GenericTaskQueueSet::GenericTaskQueueSet(int n) : _n(n) { typedef T* GenericTaskQueuePtr; _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n, F); + assert(_n < INVALID_QUEUE_ID, "Sanity"); + + _last_stolen_queues = NEW_C_HEAP_ARRAY(uint, n, F); + + for (int i = 0; i < n; i++) { _queues[i] = NULL; + _last_stolen_queues[i] = INVALID_QUEUE_ID; } } template inline GenericTaskQueueSet::~GenericTaskQueueSet() { FREE_C_HEAP_ARRAY(T*, _queues); + FREE_C_HEAP_ARRAY(uint, _last_stolen_queues); + } template @@ -254,14 +262,22 @@ GenericTaskQueueSet::steal_best_of_2(uint queue_num, int* seed, E& t) { if (_n > 2) { uint k1 = queue_num; + if (UseOptimizedBestOfTwo && _last_stolen_queues[queue_num] != INVALID_QUEUE_ID) { + k1 = _last_stolen_queues[queue_num]; + } while (k1 == queue_num) k1 = TaskQueueSetSuper::randomParkAndMiller(seed) % _n; uint k2 = queue_num; while (k2 == queue_num || k2 == k1) k2 = TaskQueueSetSuper::randomParkAndMiller(seed) % _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); + if (sz2 > sz1) { + _last_stolen_queues[queue_num] = k2; + return _queues[k2]->pop_global(t); + } else { + _last_stolen_queues[queue_num] = k1; + return _queues[k1]->pop_global(t); + } } else if (_n == 2) { // Just try the other one. uint k = (queue_num + 1) % 2;