workqueue.cc 5.3 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.

// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "paddle/fluid/framework/new_executor/workqueue.h"
#include "paddle/fluid/framework/new_executor/nonblocking_threadpool.h"
L
liutiexing 已提交
9 10
#include "paddle/fluid/framework/new_executor/workqueue_utils.h"
#include "paddle/fluid/platform/enforce.h"
11 12 13

namespace paddle {
namespace framework {
L
liutiexing 已提交
14
namespace {
15

L
liutiexing 已提交
16
class WorkQueueImpl : public WorkQueue {
17
 public:
L
liutiexing 已提交
18 19 20 21 22 23 24 25
  explicit WorkQueueImpl(const WorkQueueOptions& options)
      : WorkQueue(options), queue_(nullptr), tracker_(nullptr) {
    if (options_.track_task) {
      tracker_ = new TaskTracker;
    }
    queue_ = new NonblockingThreadPool(options_.num_threads,
                                       options_.allow_spinning);
  }
26

L
liutiexing 已提交
27 28 29 30
  virtual ~WorkQueueImpl() {
    delete tracker_;
    delete queue_;
  }
31 32

  void AddTask(std::function<void()> fn) override {
L
liutiexing 已提交
33 34 35 36 37 38 39 40
    if (tracker_ != nullptr) {
      fn = [
        task = std::move(fn), raii = CounterGuard<TaskTracker>(tracker_)
      ]() mutable {
        task();
      };
    }
    queue_->AddTask(std::move(fn));
41 42
  }

L
liutiexing 已提交
43 44 45 46 47 48 49 50
  void WaitQueueEmpty() override {
    if (tracker_ == nullptr) {
      PADDLE_THROW(
          platform::errors::Unavailable("set WorkQueueOptions.track_task = "
                                        "true before call this interface."));
    }
    tracker_->WaitTaskNumToZero();
  }
51

L
liutiexing 已提交
52
  size_t NumThreads() const override { return queue_->NumThreads(); }
53 54

 private:
L
liutiexing 已提交
55 56
  NonblockingThreadPool* queue_;
  TaskTracker* tracker_;
57 58
};

L
liutiexing 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
class WorkQueueGroupImpl : public WorkQueueGroup {
 public:
  explicit WorkQueueGroupImpl(
      const std::vector<WorkQueueOptions>& queue_options);

  ~WorkQueueGroupImpl();

  void AddTask(size_t queue_idx, std::function<void()> fn) override;

  void WaitQueueGroupEmpty() override;

  size_t QueueNumThreads(size_t queue_idx) const override;

  size_t QueueGroupNumThreads() const override;

 private:
  std::vector<NonblockingThreadPool*> queues_;
  NonblockingThreadPool* queues_storage_;
  TaskTracker* tracker_;
};

WorkQueueGroupImpl::WorkQueueGroupImpl(
    const std::vector<WorkQueueOptions>& queues_options)
    : WorkQueueGroup(queues_options),
      queues_storage_(nullptr),
      tracker_(nullptr) {
  size_t num_queues = queues_options_.size();
  queues_.resize(num_queues);
  void* buffer = malloc(sizeof(NonblockingThreadPool) * num_queues);
  queues_storage_ = reinterpret_cast<NonblockingThreadPool*>(buffer);
  for (size_t idx = 0; idx < num_queues; ++idx) {
    const auto& options = queues_options_[idx];
    if (options.track_task && tracker_ == nullptr) {
      tracker_ = new TaskTracker;
    }
    queues_[idx] = new (&queues_storage_[idx])
        NonblockingThreadPool(options.num_threads, options.allow_spinning);
  }
97 98
}

L
liutiexing 已提交
99 100 101
WorkQueueGroupImpl::~WorkQueueGroupImpl() {
  for (auto queue : queues_) {
    queue->~NonblockingThreadPool();
102
  }
L
liutiexing 已提交
103 104 105
  delete tracker_;
  free(queues_storage_);
}
106

L
liutiexing 已提交
107 108 109 110 111 112 113 114 115 116 117
void WorkQueueGroupImpl::AddTask(size_t queue_idx, std::function<void()> fn) {
  assert(queue_idx < queues_.size());
  if (queues_options_.at(queue_idx).track_task) {
    fn = [
      task = std::move(fn), raii = CounterGuard<TaskTracker>(tracker_)
    ]() mutable {
      task();
    };
  }
  queues_[queue_idx]->AddTask(std::move(fn));
}
118

L
liutiexing 已提交
119 120 121 122 123 124 125 126
void WorkQueueGroupImpl::WaitQueueGroupEmpty() {
  if (nullptr == tracker_) {
    PADDLE_THROW(platform::errors::Unavailable(
        "set WorkQueueOptions.track_task = true for at least one of queues "
        "before call this interface."));
  }
  tracker_->WaitTaskNumToZero();
}
127

L
liutiexing 已提交
128 129 130 131
size_t WorkQueueGroupImpl::QueueNumThreads(size_t queue_idx) const {
  assert(queue_idx < queues_.size());
  return queues_.at(queue_idx)->NumThreads();
}
132

L
liutiexing 已提交
133 134 135 136
size_t WorkQueueGroupImpl::QueueGroupNumThreads() const {
  size_t total_num = 0;
  for (auto queue : queues_) {
    total_num += queue->NumThreads();
137
  }
L
liutiexing 已提交
138 139
  return total_num;
}
140

L
liutiexing 已提交
141
}  // namespace
142

L
liutiexing 已提交
143 144 145 146 147 148 149
std::unique_ptr<WorkQueue> CreateSingleThreadedWorkQueue(
    const WorkQueueOptions& options) {
  PADDLE_ENFORCE_EQ(options.num_threads, 1u,
                    platform::errors::InvalidArgument(
                        "For a SingleThreadedWorkQueue, "
                        "WorkQueueOptions.num_threads must equals to 1."));
  std::unique_ptr<WorkQueue> ptr(new WorkQueueImpl(options));
T
Tomasz Socha 已提交
150
  return ptr;
L
liutiexing 已提交
151
}
152

L
liutiexing 已提交
153 154 155 156 157 158 159 160
std::unique_ptr<WorkQueue> CreateMultiThreadedWorkQueue(
    const WorkQueueOptions& options) {
  PADDLE_ENFORCE_GT(
      options.num_threads, 1u,
      platform::errors::InvalidArgument("For a MultiThreadedWorkQueue, "
                                        "WorkQueueOptions.num_threads must be "
                                        "greater than 1."));
  std::unique_ptr<WorkQueue> ptr(new WorkQueueImpl(options));
T
Tomasz Socha 已提交
161
  return ptr;
L
liutiexing 已提交
162
}
163

L
liutiexing 已提交
164 165 166 167 168 169 170
std::unique_ptr<WorkQueueGroup> CreateWorkQueueGroup(
    const std::vector<WorkQueueOptions>& queues_options) {
  PADDLE_ENFORCE_GT(queues_options.size(), 1u,
                    platform::errors::InvalidArgument(
                        "For a WorkQueueGroup, the number of WorkQueueOptions "
                        "must be greater than 1."));
  std::unique_ptr<WorkQueueGroup> ptr(new WorkQueueGroupImpl(queues_options));
T
Tomasz Socha 已提交
171
  return ptr;
172 173
}

174 175
}  // namespace framework
}  // namespace paddle