зеркало из https://github.com/mozilla/gecko-dev.git
Bug 976848 - Add a 32-bit xorshift to ThreadPoolWorker for thread-local PRNG for workstealing. (r=nmatsakis)
This commit is contained in:
Родитель
5de4470f00
Коммит
b4130cd003
|
@ -33,6 +33,14 @@ DecomposeSliceBounds(uint32_t bounds, uint16_t *from, uint16_t *to)
|
|||
MOZ_ASSERT(*from <= *to);
|
||||
}
|
||||
|
||||
ThreadPoolWorker::ThreadPoolWorker(uint32_t workerId, uint32_t rngSeed, ThreadPool *pool)
|
||||
: workerId_(workerId),
|
||||
pool_(pool),
|
||||
sliceBounds_(0),
|
||||
state_(CREATED),
|
||||
schedulerRNGState_(rngSeed)
|
||||
{ }
|
||||
|
||||
bool
|
||||
ThreadPoolWorker::hasWork() const
|
||||
{
|
||||
|
@ -101,6 +109,18 @@ ThreadPoolWorker::stealFrom(ThreadPoolWorker *victim, uint16_t *sliceId)
|
|||
return true;
|
||||
}
|
||||
|
||||
ThreadPoolWorker *
|
||||
ThreadPoolWorker::randomWorker()
|
||||
{
|
||||
// Perform 32-bit xorshift.
|
||||
uint32_t x = schedulerRNGState_;
|
||||
x ^= x << XORSHIFT_A;
|
||||
x ^= x >> XORSHIFT_B;
|
||||
x ^= x << XORSHIFT_C;
|
||||
schedulerRNGState_ = x;
|
||||
return pool_->workers_[x % pool_->numWorkers()];
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPoolWorker::start()
|
||||
{
|
||||
|
@ -195,14 +215,10 @@ ThreadPoolWorker::getSlice(ForkJoinContext *cx, uint16_t *sliceId)
|
|||
if (!pool_->workStealing())
|
||||
return false;
|
||||
|
||||
ThreadPoolWorker *victim;
|
||||
do {
|
||||
if (!pool_->hasWork())
|
||||
return false;
|
||||
|
||||
// Add one to add the main thread into the mix.
|
||||
victim = pool_->workers_[rand() % pool_->numWorkers()];
|
||||
} while (!stealFrom(victim, sliceId));
|
||||
} while (!stealFrom(randomWorker(), sliceId));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -276,6 +292,8 @@ ThreadPool::workStealing() const
|
|||
return true;
|
||||
}
|
||||
|
||||
extern uint64_t random_next(uint64_t *, int);
|
||||
|
||||
bool
|
||||
ThreadPool::lazyStartWorkers(JSContext *cx)
|
||||
{
|
||||
|
@ -295,8 +313,10 @@ ThreadPool::lazyStartWorkers(JSContext *cx)
|
|||
// Note that numWorkers() is the number of *desired* workers,
|
||||
// but workers_.length() is the number of *successfully
|
||||
// initialized* workers.
|
||||
uint64_t rngState = 0;
|
||||
for (uint32_t workerId = 0; workerId < numWorkers(); workerId++) {
|
||||
ThreadPoolWorker *worker = cx->new_<ThreadPoolWorker>(workerId, this);
|
||||
uint32_t rngSeed = uint32_t(random_next(&rngState, 32));
|
||||
ThreadPoolWorker *worker = cx->new_<ThreadPoolWorker>(workerId, rngSeed, this);
|
||||
if (!worker || !workers_.append(worker)) {
|
||||
terminateWorkersAndReportOOM(cx);
|
||||
return false;
|
||||
|
|
|
@ -48,6 +48,10 @@ class ThreadPoolWorker
|
|||
CREATED, ACTIVE, TERMINATED
|
||||
} state_;
|
||||
|
||||
// Per-worker scheduler RNG state used for picking a random worker during
|
||||
// work stealing.
|
||||
uint32_t schedulerRNGState_;
|
||||
|
||||
// The thread's main function.
|
||||
static void HelperThreadMain(void *arg);
|
||||
void helperLoop();
|
||||
|
@ -57,13 +61,21 @@ class ThreadPoolWorker
|
|||
bool popSliceBack(uint16_t *sliceId);
|
||||
bool stealFrom(ThreadPoolWorker *victim, uint16_t *sliceId);
|
||||
|
||||
// Get a worker at random from the pool using our own thread-local RNG
|
||||
// state. This is a weak, but very fast, random function [1]. We choose
|
||||
// [a,b,c] = 11,21,13.
|
||||
//
|
||||
// [1] http://www.jstatsoft.org/v08/i14/paper
|
||||
public:
|
||||
ThreadPoolWorker(uint32_t workerId, ThreadPool *pool)
|
||||
: workerId_(workerId),
|
||||
pool_(pool),
|
||||
sliceBounds_(0),
|
||||
state_(CREATED)
|
||||
{ }
|
||||
static const uint32_t XORSHIFT_A = 11;
|
||||
static const uint32_t XORSHIFT_B = 21;
|
||||
static const uint32_t XORSHIFT_C = 13;
|
||||
|
||||
private:
|
||||
ThreadPoolWorker *randomWorker();
|
||||
|
||||
public:
|
||||
ThreadPoolWorker(uint32_t workerId, uint32_t rngSeed, ThreadPool *pool);
|
||||
|
||||
uint32_t id() const { return workerId_; }
|
||||
bool isMainThread() const { return id() == 0; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче