workqueue.cc 5.6 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
  explicit WorkQueueImpl(const WorkQueueOptions& options)
      : WorkQueue(options), queue_(nullptr), tracker_(nullptr) {
    if (options_.track_task) {
L
liutiexing 已提交
21 22
      void* storage = AlignedMalloc(sizeof(TaskTracker), alignof(TaskTracker));
      tracker_ = new (storage) TaskTracker;
L
liutiexing 已提交
23 24 25 26
    }
    queue_ = new NonblockingThreadPool(options_.num_threads,
                                       options_.allow_spinning);
  }
27

L
liutiexing 已提交
28
  virtual ~WorkQueueImpl() {
L
liutiexing 已提交
29 30 31 32
    if (tracker_ != nullptr) {
      tracker_->~TaskTracker();
      AlignedFree(tracker_);
    }
L
liutiexing 已提交
33 34
    delete queue_;
  }
35 36

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

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

L
liutiexing 已提交
56
  size_t NumThreads() const override { return queue_->NumThreads(); }
57 58

 private:
L
liutiexing 已提交
59 60
  NonblockingThreadPool* queue_;
  TaskTracker* tracker_;
61 62
};

L
liutiexing 已提交
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
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) {
L
liutiexing 已提交
96 97
      void* storage = AlignedMalloc(sizeof(TaskTracker), alignof(TaskTracker));
      tracker_ = new (storage) TaskTracker;
L
liutiexing 已提交
98 99 100 101
    }
    queues_[idx] = new (&queues_storage_[idx])
        NonblockingThreadPool(options.num_threads, options.allow_spinning);
  }
102 103
}

L
liutiexing 已提交
104 105 106
WorkQueueGroupImpl::~WorkQueueGroupImpl() {
  for (auto queue : queues_) {
    queue->~NonblockingThreadPool();
107
  }
L
liutiexing 已提交
108 109 110 111
  if (tracker_ != nullptr) {
    tracker_->~TaskTracker();
    AlignedFree(tracker_);
  }
L
liutiexing 已提交
112 113
  free(queues_storage_);
}
114

L
liutiexing 已提交
115 116 117 118 119 120 121 122 123 124 125
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));
}
126

L
liutiexing 已提交
127 128 129 130 131 132 133 134
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();
}
135

L
liutiexing 已提交
136 137 138 139
size_t WorkQueueGroupImpl::QueueNumThreads(size_t queue_idx) const {
  assert(queue_idx < queues_.size());
  return queues_.at(queue_idx)->NumThreads();
}
140

L
liutiexing 已提交
141 142 143 144
size_t WorkQueueGroupImpl::QueueGroupNumThreads() const {
  size_t total_num = 0;
  for (auto queue : queues_) {
    total_num += queue->NumThreads();
145
  }
L
liutiexing 已提交
146 147
  return total_num;
}
148

L
liutiexing 已提交
149
}  // namespace
150

L
liutiexing 已提交
151 152 153 154 155 156 157
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 已提交
158
  return ptr;
L
liutiexing 已提交
159
}
160

L
liutiexing 已提交
161 162 163 164 165 166 167 168
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 已提交
169
  return ptr;
L
liutiexing 已提交
170
}
171

L
liutiexing 已提交
172 173 174 175 176 177 178
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 已提交
179
  return ptr;
180 181
}

182 183
}  // namespace framework
}  // namespace paddle