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