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