thread_pool.h revision d914eb2a839f7b40156ff0299a60e5cb80080b73
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
170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#ifndef ART_SRC_THREAD_POOL_H_
180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#define ART_SRC_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 {
3302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierpublic:
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
580e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  friend class ThreadPool;
590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  DISALLOW_COPY_AND_ASSIGN(ThreadPoolWorker);
600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier};
610e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
620e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartierclass ThreadPool {
630e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier public:
640e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Returns the number of threads in the thread pool.
650e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  size_t GetThreadCount() const {
660e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    return threads_.size();
670e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
690e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Broadcast to the workers and tell them to empty out the work queue.
700e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  void StartWorkers(Thread* self);
710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
720e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Do not allow workers to grab any new tasks.
730e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  void StopWorkers(Thread* self);
740e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
750e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Add a new task, the first available started worker will process it. Does not delete the task
760e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // after running it, it is the caller's responsibility.
7702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  void AddTask(Thread* self, Task* task);
780e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
790e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  ThreadPool(size_t num_threads);
800e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  virtual ~ThreadPool();
810e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
820e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Wait for all tasks currently on queue to get completed.
8302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  void Wait(Thread* self, bool do_work = true);
840e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
8502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  size_t GetTaskCount(Thread* self);
860e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
8702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Returns the total amount of workers waited for tasks.
8802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  uint64_t GetWaitTime() const {
8902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    return total_wait_time_;
9002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
9102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
9202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected:
930e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Get a task to run, blocks if there are no tasks left
9402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  virtual Task* GetTask(Thread* self);
9502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
9602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Try to get a task, returning NULL if there is none available.
9702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Task* TryGetTask(Thread* self);
9802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Task* TryGetTaskLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_);
9902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Are we shutting down?
10102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  bool IsShuttingDown() const EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_) {
10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    return shutting_down_;
10302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
1040e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
1050e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  Mutex task_queue_lock_;
1060e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_);
1070e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  ConditionVariable completion_condition_ GUARDED_BY(task_queue_lock_);
1080e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  volatile bool started_ GUARDED_BY(task_queue_lock_);
1090e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  volatile bool shutting_down_ GUARDED_BY(task_queue_lock_);
1100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // How many worker threads are waiting on the condition.
1110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  volatile size_t waiting_count_ GUARDED_BY(task_queue_lock_);
11202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  std::deque<Task*> tasks_ GUARDED_BY(task_queue_lock_);
1130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // TODO: make this immutable/const?
1140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  std::vector<ThreadPoolWorker*> threads_;
11502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Work balance detection.
11602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  uint64_t start_time_ GUARDED_BY(task_queue_lock_);
11702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  uint64_t total_wait_time_;
11835883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier  Barrier creation_barier_;
1190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
1200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  friend class ThreadPoolWorker;
12102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  friend class WorkStealingWorker;
1220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  DISALLOW_COPY_AND_ASSIGN(ThreadPool);
1230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier};
1240e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
12502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingTask : public Task {
12602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public:
12702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingTask() : ref_count_(0) {
12802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
12902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
13002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
13102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  size_t GetRefCount() const {
13202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    return ref_count_;
13302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
13402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
13502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  virtual void StealFrom(Thread* self, WorkStealingTask* source) = 0;
13602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
13702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private:
13802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // How many people are referencing this task.
13902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  size_t ref_count_;
14002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
14102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  friend class WorkStealingWorker;
14202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier};
14302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
14402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingWorker : public ThreadPoolWorker {
14502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public:
14602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  virtual ~WorkStealingWorker();
14702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
14802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  bool IsRunningTask() const {
14902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    return task_ != NULL;
15002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
15102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
15202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier protected:
15302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingTask* task_;
15402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
15502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
15602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  virtual void Run();
15702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
15802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  friend class WorkStealingThreadPool;
15902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  DISALLOW_COPY_AND_ASSIGN(WorkStealingWorker);
16002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier};
16102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
16202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartierclass WorkStealingThreadPool : public ThreadPool {
16302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier public:
16402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingThreadPool(size_t num_threads);
16502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  virtual ~WorkStealingThreadPool();
16602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
16702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier private:
16802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Mutex work_steal_lock_;
16902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Which thread we are stealing from (round robin).
17002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  size_t steal_index_;
17102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
17202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Find a task to steal from
17302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingTask* FindTaskToStealFrom(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_);
17402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
17502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  friend class WorkStealingWorker;
17602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier};
17702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
1780e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}  // namespace art
1790e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
1800e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#endif  // ART_SRC_THREAD_POOL_H_
181