thread_pool.cc revision 35883cc623fdf475a4ead1dafcba9e9becc1ed11
102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier#include "casts.h" 20e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "runtime.h" 30e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "stl_util.h" 40e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "thread.h" 50e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "thread_pool.h" 60e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 70e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiernamespace art { 80e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 90e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, 100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier size_t stack_size) 110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier : thread_pool_(thread_pool), 120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier name_(name), 130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier stack_size_(stack_size) { 140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const char* reason = "new thread pool worker thread"; 15bcc2926b9721f94c17ed98fae5264cc98f0e066fBrian Carlstrom pthread_attr_t attr; 160e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason); 170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), reason); 180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier CHECK_PTHREAD_CALL(pthread_create, (&pthread_, &attr, &Callback, this), reason); 190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason); 200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPoolWorker::~ThreadPoolWorker() { 230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier CHECK_PTHREAD_CALL(pthread_join, (pthread_, NULL), "thread pool worker shutdown"); 240e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPoolWorker::Run() { 270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Thread* self = Thread::Current(); 2802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* task = NULL; 2935883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier thread_pool_->creation_barier_.Wait(self); 300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier while ((task = thread_pool_->GetTask(self)) != NULL) { 310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier task->Run(self); 3202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task->Finalize(); 330e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 340e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 350e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 360e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid* ThreadPoolWorker::Callback(void* arg) { 370e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg); 380e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Runtime* runtime = Runtime::Current(); 39664bebf92eb2151b9b570ccd42ac4b6056c3ea9cMathieu Chartier CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, NULL, false)); 400e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Do work until its time to shut down. 410e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier worker->Run(); 420e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier runtime->DetachCurrentThread(); 430e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return NULL; 440e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 4602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid ThreadPool::AddTask(Thread* self, Task* task){ 470e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier MutexLock mu(self, task_queue_lock_); 480e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier tasks_.push_back(task); 490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // If we have any waiters, signal one. 500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier if (waiting_count_ != 0) { 510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier task_queue_condition_.Signal(self); 520e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 530e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 540e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 550e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPool::ThreadPool(size_t num_threads) 560e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier : task_queue_lock_("task queue lock"), 570e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier task_queue_condition_("task queue condition", task_queue_lock_), 580e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier completion_condition_("task completion condition", task_queue_lock_), 590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier started_(false), 600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier shutting_down_(false), 6135883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier waiting_count_(0), 6235883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier // Add one since the caller of constructor waits on the barrier too. 6335883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier creation_barier_(num_threads + 1) { 6435883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier Thread* self = Thread::Current(); 650e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier while (GetThreadCount() < num_threads) { 6602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier const std::string name = StringPrintf("Thread pool worker %zu", GetThreadCount()); 6702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier threads_.push_back(new ThreadPoolWorker(this, name, ThreadPoolWorker::kDefaultStackSize)); 680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 6935883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier // Wait for all of the threads to attach. 7035883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier creation_barier_.Wait(self); 710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 720e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 730e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPool::~ThreadPool() { 74e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier { 75e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier Thread* self = Thread::Current(); 76e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier MutexLock mu(self, task_queue_lock_); 77e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier // Tell any remaining workers to shut down. 78e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier shutting_down_ = true; 79e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier // Broadcast to everyone waiting. 80e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier task_queue_condition_.Broadcast(self); 8102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier completion_condition_.Broadcast(self); 82e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier } 830e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait for the threads to finish. 840e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier STLDeleteElements(&threads_); 850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 860e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 870e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPool::StartWorkers(Thread* self) { 880e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier MutexLock mu(self, task_queue_lock_); 890e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier started_ = true; 900e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier task_queue_condition_.Broadcast(self); 9102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier start_time_ = NanoTime(); 9202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier total_wait_time_ = 0; 930e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 940e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 950e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPool::StopWorkers(Thread* self) { 960e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier MutexLock mu(self, task_queue_lock_); 970e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier started_ = false; 980e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 990e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::GetTask(Thread* self) { 1010e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier MutexLock mu(self, task_queue_lock_); 10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while (!IsShuttingDown()) { 10302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* task = TryGetTaskLocked(self); 10402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (task != NULL) { 1050e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return task; 1060e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 1070e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 1080e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier waiting_count_++; 1090e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier if (waiting_count_ == GetThreadCount() && tasks_.empty()) { 1100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // We may be done, lets broadcast to the completion condition. 1110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier completion_condition_.Broadcast(self); 1120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 11302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier const uint64_t wait_start = NanoTime(); 1140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier task_queue_condition_.Wait(self); 11502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier const uint64_t wait_end = NanoTime(); 11602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier total_wait_time_ += wait_end - std::max(wait_start, start_time_); 1170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier waiting_count_--; 1180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 1190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 1200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // We are shutting down, return NULL to tell the worker thread to stop looping. 1210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return NULL; 1220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 1230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 12402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::TryGetTask(Thread* self) { 1250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier MutexLock mu(self, task_queue_lock_); 12602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return TryGetTaskLocked(self); 12702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 12802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 12902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::TryGetTaskLocked(Thread* self) { 13002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (started_ && !tasks_.empty()) { 13102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* task = tasks_.front(); 13202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier tasks_.pop_front(); 13302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return task; 13402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 13502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return NULL; 13602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 13702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 13802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid ThreadPool::Wait(Thread* self, bool do_work) { 13902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* task = NULL; 14002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while ((task = TryGetTask(self)) != NULL) { 14102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task->Run(self); 14202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task->Finalize(); 14302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 14402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 1450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait until each thread is waiting and the task list is empty. 14602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, task_queue_lock_); 14702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) { 1480e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier completion_condition_.Wait(self); 1490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 1500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} 1510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 15202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiersize_t ThreadPool::GetTaskCount(Thread* self){ 15302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, task_queue_lock_); 15402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return tasks_.size(); 15502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 15602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingWorker::WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, 15802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t stack_size) 15902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier : ThreadPoolWorker(thread_pool, name, stack_size), 16002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task_(NULL) { 16102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 16302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid WorkStealingWorker::Run() { 16502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Thread* self = Thread::Current(); 16602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* task = NULL; 16702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingThreadPool* thread_pool = down_cast<WorkStealingThreadPool*>(thread_pool_); 16802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while ((task = thread_pool_->GetTask(self)) != NULL) { 16902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* stealing_task = down_cast<WorkStealingTask*>(task); 17002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier { 17202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier CHECK(task_ == NULL); 17302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, thread_pool->work_steal_lock_); 17402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Register that we are running the task 17502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier ++stealing_task->ref_count_; 17602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task_ = stealing_task; 17702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 17802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier stealing_task->Run(self); 17902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Mark ourselves as not running a task so that nobody tries to steal from us. 18002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // There is a race condition that someone starts stealing from us at this point. This is okay 18102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // due to the reference counting. 18202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier task_ = NULL; 18302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 18402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier bool finalize; 18502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 18602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Steal work from tasks until there is none left to steal. Note: There is a race, but 18702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // all that happens when the race occurs is that we steal some work instead of processing a 18802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // task from the queue. 18902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while (thread_pool->GetTaskCount(self) == 0) { 19002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* steal_from_task = NULL; 19102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 19202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier { 19302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, thread_pool->work_steal_lock_); 19402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Try finding a task to steal from. 19502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier steal_from_task = thread_pool->FindTaskToStealFrom(self); 19602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (steal_from_task != NULL) { 19702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier CHECK_NE(stealing_task, steal_from_task) 19802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier << "Attempting to steal from completed self task"; 19902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier steal_from_task->ref_count_++; 20002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } else { 20102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier break; 20202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 20302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 20402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 20502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (steal_from_task != NULL) { 20602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Task which completed earlier is going to steal some work. 20702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier stealing_task->StealFrom(self, steal_from_task); 20802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 20902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier { 21002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // We are done stealing from the task, lets decrement its reference count. 21102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, thread_pool->work_steal_lock_); 21202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier finalize = !--steal_from_task->ref_count_; 21302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 21402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 21502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (finalize) { 21602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier steal_from_task->Finalize(); 21702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 21802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 21902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 22002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 22102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier { 22202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier MutexLock mu(self, thread_pool->work_steal_lock_); 22302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // If nobody is still referencing task_ we can finalize it. 22402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier finalize = !--stealing_task->ref_count_; 22502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 22602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 22702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (finalize) { 22802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier stealing_task->Finalize(); 22902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 23002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 23102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 23202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 23302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingWorker::~WorkStealingWorker() { 23402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 23502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 23602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 23702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingThreadPool::WorkStealingThreadPool(size_t num_threads) 23802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier : ThreadPool(0), 23902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier work_steal_lock_("work stealing lock"), 24002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier steal_index_(0) { 24102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier while (GetThreadCount() < num_threads) { 24202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier const std::string name = StringPrintf("Work stealing worker %zu", GetThreadCount()); 24302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier threads_.push_back(new WorkStealingWorker(this, name, ThreadPoolWorker::kDefaultStackSize)); 24402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 24502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 24602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 24702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom(Thread* self) { 24802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier const size_t thread_count = GetThreadCount(); 24902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier for (size_t i = 0; i < thread_count; ++i) { 25002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // TODO: Use CAS instead of lock. 25102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier ++steal_index_; 25202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (steal_index_ >= thread_count) { 25302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier steal_index_-= thread_count; 25402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 25502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 25602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingWorker* worker = down_cast<WorkStealingWorker*>(threads_[steal_index_]); 25702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* task = worker->task_; 25802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier if (task) { 25902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Not null, we can probably steal from this worker. 26002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return task; 26102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 26202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 26302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Couldn't find something to steal. 26402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return NULL; 26502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 26602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 26702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingThreadPool::~WorkStealingThreadPool() { 26802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 26902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier} 27002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 2710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} // namespace art 272