10e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier/* 20e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Copyright (C) 2012 The Android Open Source Project 30e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 40e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Licensed under the Apache License, Version 2.0 (the "License"); 50e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * you may not use this file except in compliance with the License. 60e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * You may obtain a copy of the License at 70e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 80e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * http://www.apache.org/licenses/LICENSE-2.0 90e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * 100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * Unless required by applicable law or agreed to in writing, software 110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * distributed under the License is distributed on an "AS IS" BASIS, 120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * See the License for the specific language governing permissions and 140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier * limitations under the License. 150e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier */ 160e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 17fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom#ifndef ART_RUNTIME_THREAD_POOL_H_ 18fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom#define ART_RUNTIME_THREAD_POOL_H_ 190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include <deque> 210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include <vector> 220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 2335883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier#include "barrier.h" 2476b6167407c2b6f5d40ad895b2793a6b037f54b2Elliott Hughes#include "base/mutex.h" 2502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier#include "closure.h" 260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "locks.h" 270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 280e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiernamespace art { 290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPool; 310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 3202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass Task : public Closure { 3302c8cc6d1312a2b55533f02f6369dc7c94672f90Brian Carlstrom public: 3402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Called when references reaches 0. 3502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Finalize() { } 3602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 3702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 380e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPoolWorker { 390e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 400e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier static const size_t kDefaultStackSize = 1 * MB; 410e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 420e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier size_t GetStackSize() const { 430e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return stack_size_; 440e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 460e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier virtual ~ThreadPoolWorker(); 470e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 4802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size); 500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier static void* Callback(void* arg) LOCKS_EXCLUDED(Locks::mutator_lock_); 5102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Run(); 520e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 53d914eb2a839f7b40156ff0299a60e5cb80080b73Ian Rogers ThreadPool* const thread_pool_; 540e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const std::string name_; 550e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const size_t stack_size_; 560e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier pthread_t pthread_; 570e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 5802e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier friend class ThreadPool; 600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier DISALLOW_COPY_AND_ASSIGN(ThreadPoolWorker); 610e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 620e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 630e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPool { 640e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 650e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Returns the number of threads in the thread pool. 660e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier size_t GetThreadCount() const { 670e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return threads_.size(); 680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 690e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 700e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Broadcast to the workers and tell them to empty out the work queue. 710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void StartWorkers(Thread* self); 720e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 730e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Do not allow workers to grab any new tasks. 740e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void StopWorkers(Thread* self); 750e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 760e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Add a new task, the first available started worker will process it. Does not delete the task 770e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // after running it, it is the caller's responsibility. 7802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier void AddTask(Thread* self, Task* task); 790e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 8093ba893c20532990a430741e0a97212900094e8cBrian Carlstrom explicit ThreadPool(size_t num_threads); 810e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier virtual ~ThreadPool(); 820e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 830e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait for all tasks currently on queue to get completed. 841d54e73444e017d3a65234e0f193846f3e27472bIan Rogers void Wait(Thread* self, bool do_work, bool may_hold_locks); 850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 8602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t GetTaskCount(Thread* self); 870e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 8802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Returns the total amount of workers waited for tasks. 8902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t GetWaitTime() const { 9002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return total_wait_time_; 9102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 9202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 932775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier // Provides a way to bound the maximum number of worker threads, threads must be less the the 942775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier // thread count of the thread pool. 952775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier void SetMaxActiveWorkers(size_t threads); 962775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier 9702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 980e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Get a task to run, blocks if there are no tasks left 9902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual Task* GetTask(Thread* self); 10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 10102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Try to get a task, returning NULL if there is none available. 10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* TryGetTask(Thread* self); 10302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* TryGetTaskLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_); 10402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 10502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Are we shutting down? 10602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier bool IsShuttingDown() const EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_) { 10702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return shutting_down_; 10802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 1090e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 1100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Mutex task_queue_lock_; 1110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_); 1120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ConditionVariable completion_condition_ GUARDED_BY(task_queue_lock_); 1130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile bool started_ GUARDED_BY(task_queue_lock_); 1140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile bool shutting_down_ GUARDED_BY(task_queue_lock_); 1150e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // How many worker threads are waiting on the condition. 1160e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile size_t waiting_count_ GUARDED_BY(task_queue_lock_); 11702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier std::deque<Task*> tasks_ GUARDED_BY(task_queue_lock_); 1180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // TODO: make this immutable/const? 1190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier std::vector<ThreadPoolWorker*> threads_; 12002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Work balance detection. 12102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t start_time_ GUARDED_BY(task_queue_lock_); 12202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t total_wait_time_; 12335883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier Barrier creation_barier_; 1242775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier size_t max_active_workers_ GUARDED_BY(task_queue_lock_); 1250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 12602e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 1270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier friend class ThreadPoolWorker; 12802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 1290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier DISALLOW_COPY_AND_ASSIGN(ThreadPool); 1300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 1310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 13202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingTask : public Task { 13302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 1340cd7ec2dcd8d7ba30bf3ca420b40dac52849876cBrian Carlstrom WorkStealingTask() : ref_count_(0) {} 13502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 13602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t GetRefCount() const { 13702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return ref_count_; 13802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 13902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 14002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void StealFrom(Thread* self, WorkStealingTask* source) = 0; 14102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 14202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private: 14302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // How many people are referencing this task. 14402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t ref_count_; 14502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 14602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 14702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 14802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 14902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingWorker : public ThreadPoolWorker { 15002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 15102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual ~WorkStealingWorker(); 15202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier bool IsRunningTask() const { 15402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return task_ != NULL; 15502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 15602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 15802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* task_; 15902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size); 16102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Run(); 16202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16302e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 16402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingThreadPool; 16502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier DISALLOW_COPY_AND_ASSIGN(WorkStealingWorker); 16602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 16702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingThreadPool : public ThreadPool { 16902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 17093ba893c20532990a430741e0a97212900094e8cBrian Carlstrom explicit WorkStealingThreadPool(size_t num_threads); 17102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual ~WorkStealingThreadPool(); 17202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private: 17402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Mutex work_steal_lock_; 17502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Which thread we are stealing from (round robin). 17602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t steal_index_; 17702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Find a task to steal from 17902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* FindTaskToStealFrom(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_); 18002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 18102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 18202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 18302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 1840e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} // namespace art 1850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 186fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom#endif // ART_RUNTIME_THREAD_POOL_H_ 187