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" 25bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier#include "mem_map.h" 260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiernamespace art { 280e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPool; 300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 3114317f030db862bb2210135b9af510df429059fdIan Rogersclass Closure { 3214317f030db862bb2210135b9af510df429059fdIan Rogers public: 3314317f030db862bb2210135b9af510df429059fdIan Rogers virtual ~Closure() { } 3414317f030db862bb2210135b9af510df429059fdIan Rogers virtual void Run(Thread* self) = 0; 3514317f030db862bb2210135b9af510df429059fdIan Rogers}; 3614317f030db862bb2210135b9af510df429059fdIan Rogers 3702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass Task : public Closure { 3802c8cc6d1312a2b55533f02f6369dc7c94672f90Brian Carlstrom public: 39a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier // Called after Closure::Run has been called. 4002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Finalize() { } 4102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 4202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 43a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartierclass SelfDeletingTask : public Task { 44a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier public: 45a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier virtual ~SelfDeletingTask() { } 46a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier virtual void Finalize() { 47a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier delete this; 48a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier } 49a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier}; 50a5eae69589ff562ad66c57665882cd16f237321cMathieu Chartier 510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPoolWorker { 520e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 530e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier static const size_t kDefaultStackSize = 1 * MB; 540e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 550e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier size_t GetStackSize() const { 56bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier DCHECK(stack_.get() != nullptr); 57bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier return stack_->Size(); 580e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier virtual ~ThreadPoolWorker(); 610e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 6202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 630e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size); 640e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier static void* Callback(void* arg) LOCKS_EXCLUDED(Locks::mutator_lock_); 6502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Run(); 660e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 67d914eb2a839f7b40156ff0299a60e5cb80080b73Ian Rogers ThreadPool* const thread_pool_; 680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier const std::string name_; 69700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers std::unique_ptr<MemMap> stack_; 700e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier pthread_t pthread_; 710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 7202e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 730e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier friend class ThreadPool; 740e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier DISALLOW_COPY_AND_ASSIGN(ThreadPoolWorker); 750e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 760e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 770e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPool { 780e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public: 790e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Returns the number of threads in the thread pool. 800e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier size_t GetThreadCount() const { 810e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier return threads_.size(); 820e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier } 830e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 840e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Broadcast to the workers and tell them to empty out the work queue. 850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void StartWorkers(Thread* self); 860e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 870e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Do not allow workers to grab any new tasks. 880e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier void StopWorkers(Thread* self); 890e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 900e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Add a new task, the first available started worker will process it. Does not delete the task 910e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // after running it, it is the caller's responsibility. 9202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier void AddTask(Thread* self, Task* task); 930e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 94bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier explicit ThreadPool(const char* name, size_t num_threads); 950e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier virtual ~ThreadPool(); 960e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 970e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // Wait for all tasks currently on queue to get completed. 981d54e73444e017d3a65234e0f193846f3e27472bIan Rogers void Wait(Thread* self, bool do_work, bool may_hold_locks); 990e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t GetTaskCount(Thread* self); 1010e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Returns the total amount of workers waited for tasks. 10302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t GetWaitTime() const { 10402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return total_wait_time_; 10502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 10602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 1072775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier // Provides a way to bound the maximum number of worker threads, threads must be less the the 1082775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier // thread count of the thread pool. 1092775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier void SetMaxActiveWorkers(size_t threads); 1102775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier 11102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 112eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier // get a task to run, blocks if there are no tasks left 11302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual Task* GetTask(Thread* self); 11402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 1152cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier // Try to get a task, returning null if there is none available. 11602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Task* TryGetTask(Thread* self); 1176a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers Task* TryGetTaskLocked() EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_); 11802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 11902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Are we shutting down? 12002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier bool IsShuttingDown() const EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_) { 12102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return shutting_down_; 12202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 1230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 124bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier const std::string name_; 1250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier Mutex task_queue_lock_; 1260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_); 1270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier ConditionVariable completion_condition_ GUARDED_BY(task_queue_lock_); 1280e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile bool started_ GUARDED_BY(task_queue_lock_); 1290e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile bool shutting_down_ GUARDED_BY(task_queue_lock_); 1300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // How many worker threads are waiting on the condition. 1310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier volatile size_t waiting_count_ GUARDED_BY(task_queue_lock_); 13202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier std::deque<Task*> tasks_ GUARDED_BY(task_queue_lock_); 1330e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier // TODO: make this immutable/const? 1340e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier std::vector<ThreadPoolWorker*> threads_; 13502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Work balance detection. 13602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t start_time_ GUARDED_BY(task_queue_lock_); 13702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier uint64_t total_wait_time_; 13835883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier Barrier creation_barier_; 1392775ee4f82dff260663ca16adddc0b15327aaa42Mathieu Chartier size_t max_active_workers_ GUARDED_BY(task_queue_lock_); 1400e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 14102e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 1420e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier friend class ThreadPoolWorker; 14302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 1440e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier DISALLOW_COPY_AND_ASSIGN(ThreadPool); 1450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}; 1460e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 14702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingTask : public Task { 14802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 1490cd7ec2dcd8d7ba30bf3ca420b40dac52849876cBrian Carlstrom WorkStealingTask() : ref_count_(0) {} 15002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t GetRefCount() const { 15202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier return ref_count_; 15302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 15402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void StealFrom(Thread* self, WorkStealingTask* source) = 0; 15602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 15702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private: 15802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // How many people are referencing this task. 15902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t ref_count_; 16002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 16202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 16302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingWorker : public ThreadPoolWorker { 16502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 16602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual ~WorkStealingWorker(); 16702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 16802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier bool IsRunningTask() const { 1692cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier return task_ != nullptr; 17002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier } 17102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected: 17302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingTask* task_; 17402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size); 17602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual void Run(); 17702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 17802e25119b15a6f619f17db99f5d05124a5807ff3Mathieu Chartier private: 17902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingThreadPool; 18002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier DISALLOW_COPY_AND_ASSIGN(WorkStealingWorker); 18102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 18202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 18302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingThreadPool : public ThreadPool { 18402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public: 185bcd5e9daecad39f0dab3246808b4835caec29ea6Mathieu Chartier explicit WorkStealingThreadPool(const char* name, size_t num_threads); 18602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier virtual ~WorkStealingThreadPool(); 18702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 18802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private: 18902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier Mutex work_steal_lock_; 19002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Which thread we are stealing from (round robin). 19102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier size_t steal_index_; 19202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 19302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier // Find a task to steal from 1946a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers WorkStealingTask* FindTaskToStealFrom() EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_); 19502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 19602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier friend class WorkStealingWorker; 19702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}; 19802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier 1990e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier} // namespace art 2000e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier 201fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom#endif // ART_RUNTIME_THREAD_POOL_H_ 202