chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
@@ -0,0 +1,5 @@
file(
GLOB reader_cc
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"*.cc")
collect_srcs(core_srcs SRCS ${reader_cc})
@@ -0,0 +1,195 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <condition_variable> // NOLINT
#include <deque>
#include <utility>
#include "paddle/phi/core/enforce.h"
namespace paddle {
namespace operators {
namespace reader {
template <typename T>
class BlockingQueue {
// BlockingQueue is for buffered reading and is supposed to use only the
// reader package. It is true that we could and we should have been using
// framework::Channel, but which has currently a deadlock bug. BlockingQueue
// is a workaround and a simplified version of framework::Channel as it
// doesn't support GPU and it implements on buffered blocking queue.
public:
explicit BlockingQueue(size_t capacity, bool speed_test_mode = false)
: capacity_(capacity), speed_test_mode_(speed_test_mode) {
PADDLE_ENFORCE_GT(capacity_,
static_cast<size_t>(0),
common::errors::InvalidArgument(
"The capacity of a reader::BlockingQueue must be "
"greater than 0, but received capacity is %d.",
capacity_));
}
bool Send(const T& elem) {
std::unique_lock<std::mutex> lock(mutex_);
send_cv_.wait(
lock, [&] { return queue_.size() < capacity_ || closed_ || killed_; });
if (killed_) {
// VLOG(3)
// << "WARNING:: Sending an element to a killed
// reader::BlockingQueue";
return false;
}
if (closed_) {
// VLOG(5)
// << "WARNING: Sending an element to a closed
// reader::BlockingQueue.";
return false;
}
PADDLE_ENFORCE_LT(
queue_.size(),
capacity_,
common::errors::PermissionDenied(
"The queue size cannot exceed the set queue capacity. Expected "
"queue size is less than %d. But received %d",
capacity_,
queue_.size()));
queue_.push_back(elem);
receive_cv_.notify_one();
return true;
}
bool Send(T&& elem) {
std::unique_lock<std::mutex> lock(mutex_);
send_cv_.wait(
lock, [&] { return queue_.size() < capacity_ || closed_ || killed_; });
if (killed_) {
// VLOG(3)
// << "WARNING:: Sending an element to a killed
// reader::BlockingQueue";
return false;
}
if (closed_) {
// VLOG(5)
// << "WARNING: Sending an element to a closed
// reader::BlockingQueue.";
return false;
}
PADDLE_ENFORCE_LT(
queue_.size(),
capacity_,
common::errors::PermissionDenied(
"The queue size cannot exceed the set queue capacity. Expected "
"queue size is less than %d. But received %d",
capacity_,
queue_.size()));
queue_.emplace_back(std::move(elem));
receive_cv_.notify_one();
return true;
}
bool Receive(T* elem) {
std::unique_lock<std::mutex> lock(mutex_);
receive_cv_.wait(lock,
[&] { return !queue_.empty() || closed_ || killed_; });
EnforceNotKilled();
if (!queue_.empty()) {
PADDLE_ENFORCE_NOT_NULL(
elem,
common::errors::InvalidArgument(
"The holder to receive queue data is null pointer."));
*elem = queue_.front();
if (LIKELY(!speed_test_mode_)) {
queue_.pop_front();
}
send_cv_.notify_one();
return true;
} else {
PADDLE_ENFORCE_EQ(closed_,
true,
common::errors::PermissionDenied(
"Blocking queue status error, if queue is empty "
"when pop data, it should be closed."));
// VLOG(3) << "queue is closed! return nothing.";
return false;
}
}
void ReOpen() {
std::lock_guard<std::mutex> lock(mutex_);
EnforceNotKilled();
// VLOG(1) << "reopen queue";
closed_ = false;
std::deque<T> new_deque;
queue_.swap(new_deque);
send_cv_.notify_all();
receive_cv_.notify_all();
}
void Close() {
std::lock_guard<std::mutex> lock(mutex_);
// VLOG(1) << "close queue";
closed_ = true;
send_cv_.notify_all();
receive_cv_.notify_all();
}
bool IsClosed() const {
std::lock_guard<std::mutex> lock(mutex_);
return closed_;
}
size_t Cap() const {
std::lock_guard<std::mutex> lock(mutex_);
return capacity_;
}
size_t Size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
void Kill() {
std::lock_guard<std::mutex> lock(mutex_);
// VLOG(1) << "kill queue";
closed_ = true;
killed_ = true;
send_cv_.notify_all();
receive_cv_.notify_all();
}
private:
inline void EnforceNotKilled() {
PADDLE_ENFORCE_NE(
killed_,
true,
common::errors::Fatal("Blocking queue is killed because the "
"data reader raises an exception."));
}
private:
size_t capacity_;
bool speed_test_mode_;
bool closed_{false};
bool killed_{false}; // the queue is broken since exception raises
std::deque<T> queue_;
mutable std::mutex mutex_;
mutable std::condition_variable receive_cv_;
mutable std::condition_variable send_cv_;
};
} // namespace reader
} // namespace operators
} // namespace paddle
@@ -0,0 +1,417 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/phi/core/operators/reader/buffered_reader.h"
#include "paddle/phi/core/framework/convert_utils.h"
#include "paddle/phi/core/platform/device/device_wrapper.h"
#include "paddle/phi/core/platform/profiler.h"
#include "paddle/phi/core/platform/profiler/event_tracing.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/backends/device_guard.h"
#include "paddle/phi/backends/device_manager.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/memory_utils.h"
#include "glog/logging.h"
namespace paddle::operators::reader {
BufferedReader::~BufferedReader() {
VLOG(1) << "~BufferedReader";
reader_->Shutdown();
while (!position_.empty()) {
auto &front = position_.front();
if (front.valid()) {
front.wait();
}
position_.pop();
}
}
BufferedReader::BufferedReader(
const std::shared_ptr<framework::ReaderBase> &reader,
const Place &place,
size_t buffer_size,
bool pin_memory)
: framework::DecoratedReader(reader),
thread_pool_(1),
place_(place),
buffer_size_(buffer_size),
pin_memory_(pin_memory),
position_(),
cpu_buffer_(),
cuda_buffer_(),
xpu_buffer_(),
custom_device_buffer_() {
VLOG(1) << "BufferedReader";
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
if (place_.GetType() == AllocationType::GPU && !pin_memory) {
int dev_idx = place_.device; // NOLINT
compute_stream_ =
((phi::GPUContext *)(phi::DeviceContextPool::Instance().Get(place_)))
->stream();
events_.resize(buffer_size);
for (auto &event : events_) {
event = platform::CudaEventResourcePool::Instance().New(dev_idx);
}
stream_ = platform::CudaStreamResourcePool::Instance().New(dev_idx);
}
#endif
#ifdef PADDLE_WITH_XPU
if (place_.GetType() == AllocationType::XPU) {
int dev_idx = place_.device;
compute_stream_ =
((phi::XPUContext *)(phi::DeviceContextPool::Instance().Get(place_)))
->stream();
events_.resize(buffer_size);
for (auto &event : events_) {
event = platform::XpuEventResourcePool::Instance().New(dev_idx);
}
stream_ = platform::XpuStreamResourcePool::Instance().New(dev_idx);
}
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
if (place_.GetType() == AllocationType::CUSTOM) {
auto stream =
((phi::CustomContext *)(phi::DeviceContextPool::Instance().Get(place_)))
->stream();
custom_device_compute_stream_ =
std::make_shared<phi::stream::Stream>(place_, stream);
custom_device_events_.resize(buffer_size);
for (auto &event : custom_device_events_) {
event = std::make_shared<phi::event::Event>();
event->Init(place_);
}
custom_device_stream_ = std::make_shared<phi::stream::Stream>();
custom_device_stream_->Init(place_);
}
#endif
cpu_buffer_.resize(buffer_size);
cuda_buffer_.resize(buffer_size);
xpu_buffer_.resize(buffer_size);
custom_device_buffer_.resize(buffer_size);
ReadTillBufferFullAsync();
}
void BufferedReader::ReadTillBufferFullAsync() {
for (size_t i = 0; i < buffer_size_; ++i) {
ReadAsync(i);
}
}
void BufferedReader::ReadAsync(size_t i) {
position_.emplace(thread_pool_.enqueue([this, i]() -> size_t {
TensorVec &cpu = cpu_buffer_[i];
reader_->ReadNext(&cpu);
if (cpu.empty()) {
return -1UL;
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) // @{ Group GPU Place
if (place_.GetType() == AllocationType::GPU) {
auto dev_ctx_gpu =
(phi::GPUContext *)(phi::DeviceContextPool::Instance().Get(place_));
TensorVec &cuda = cuda_buffer_[i];
if (cuda.empty()) {
cuda.resize(cpu.size());
} else {
PADDLE_ENFORCE_EQ(
cuda.size(),
cpu.size(),
common::errors::InvalidArgument(
"Input tensor number on GPU and CPU devices are not matched."));
}
if (pin_memory_) {
// NOTE: [Copy processing of different input devices]
// We may accept input tensor in three different devices:
// - CPUPlace
// - CUDAPinnedPlace
// - CUDAPlace
// CUDA Stream Synchronizing is slow, in order to avoid Synchronizing
// in BufferedReader thread, we do data copy as follows:
// - If src Tensor on CPU memory, we copy it to CUDAPinned memory
// - IF src Tensor on CUDAPinned memory, we use it directly
// - IF src Tensor on CUDA memory, we use it directly
phi::GPUPinnedPlace cuda_pinned_place;
std::vector<void *> cuda_pinned_ptrs;
cuda_pinned_ptrs.reserve(cpu.size());
phi::RecordEvent record_event(
"BufferedReader:MemoryCopy", phi::TracerEventType::UserDefined, 1);
// NODE(chenweihang): When we use CUDAPinned Memory, we need call
// cudaHostAlloc, that is a CUDA API, calling CUDA API need load
// cuda lib into device, it will cost hundreds of MB of GPU memory.
// If we don't set Device here, which will use CUDAPlace(0) default.
platform::SetDeviceId(place_.device);
for (size_t i = 0; i < cpu.size(); ++i) {
if (cpu[i].place().GetType() == AllocationType::CPU) {
cuda[i].Resize(cpu[i].dims());
cuda[i].set_layout(cpu[i].layout());
cuda_pinned_ptrs[i] =
dev_ctx_gpu->Alloc(&cuda[i],
cpu[i].type(),
0,
true); // pinned=true to use GPUPinnedPlace
auto size = cpu[i].numel() * phi::SizeOf(cpu[i].dtype());
phi::memory_utils::Copy(cuda_pinned_place,
cuda_pinned_ptrs[i],
cpu[i].place(),
cpu[i].data(),
size);
cuda[i].set_lod(cpu[i].lod());
} else {
// Here the cpu[i]'s place may be CUDAPlace, CUDAPinnedPlace, or
// others, we don't copy the memory of it to CUDAPinnedPlace, but
// we should share tensor data to cuda[i]
cuda[i].ShareDataWith(cpu[i]);
}
}
} else {
// NOTE(liangdun): using async copy instead of TensorCopySync
// TensorCopySync would block other stream, because TensorCopySync
// issues the copying command to the default stream, it will make two
// commands from different streams cannot run concurrently.
std::vector<void *> gpu_ptrs;
gpu_ptrs.reserve(cpu.size());
for (size_t i = 0; i < cpu.size(); ++i) {
cuda[i].Resize(cpu[i].dims());
cuda[i].set_layout(cpu[i].layout());
gpu_ptrs.emplace_back(dev_ctx_gpu->Alloc(&cuda[i], cpu[i].type()));
}
// NOTE(zjl): cudaStreamWaitEvent() must be called after all
// Alloc(cuda[i]) is called, since some ops release
// cuda memory immediately without waiting cuda kernel ends
platform::SetDeviceId(place_.device);
#ifdef PADDLE_WITH_HIP
PADDLE_ENFORCE_GPU_SUCCESS(
hipEventRecord(events_[i].get(), compute_stream_));
PADDLE_ENFORCE_GPU_SUCCESS(
hipStreamWaitEvent(stream_.get(), events_[i].get(), 0));
#else
PADDLE_ENFORCE_GPU_SUCCESS(
cudaEventRecord(events_[i].get(), compute_stream_));
PADDLE_ENFORCE_GPU_SUCCESS(
cudaStreamWaitEvent(stream_.get(), events_[i].get(), 0));
#endif
phi::RecordEvent record_event(
"BufferedReader:MemoryCopy", phi::TracerEventType::UserDefined, 1);
for (size_t i = 0; i < cpu.size(); ++i) {
auto cpu_place = cpu[i].place();
auto cpu_ptr = cpu[i].data();
auto gpu_ptr = gpu_ptrs[i];
auto size = cpu[i].numel() * phi::SizeOf(cpu[i].dtype());
if (cpu_place.GetType() == AllocationType::GPUPINNED ||
cpu_place.GetType() == AllocationType::GPU) {
phi::memory_utils::Copy(
place_, gpu_ptr, cpu_place, cpu_ptr, size, stream_.get());
} else {
phi::GPUPinnedPlace cuda_pinned_place;
DenseTensor cuda_pinned_tensor;
cuda_pinned_tensor.Resize(cpu[i].dims());
auto cuda_pinned_ptr =
dev_ctx_gpu->Alloc(&cuda_pinned_tensor,
cpu[i].type(),
0,
true); // pinned=true to use GPUPinnedPlace
phi::memory_utils::Copy(
cuda_pinned_place, cuda_pinned_ptr, cpu_place, cpu_ptr, size);
phi::memory_utils::Copy(place_,
gpu_ptr,
cuda_pinned_place,
cuda_pinned_ptr,
size,
stream_.get());
phi::backends::gpu::GpuStreamSync(stream_.get());
}
cuda[i].set_lod(cpu[i].lod());
}
phi::backends::gpu::GpuStreamSync(stream_.get());
}
}
#endif
#ifdef PADDLE_WITH_XPU
if (place_.GetType() == AllocationType::XPU) {
auto dev_ctx_xpu =
(phi::XPUContext *)(phi::DeviceContextPool::Instance().Get(place_));
TensorVec &xpu = xpu_buffer_[i];
if (xpu.empty()) {
xpu.resize(cpu.size());
} else {
PADDLE_ENFORCE_EQ(
xpu.size(),
cpu.size(),
common::errors::InvalidArgument(
"Input tensor number on XPU and CPU devices are not matched. "
"The number on XPU is %d, on CPU is %d",
xpu.size(),
cpu.size()));
}
std::vector<void *> xpu_ptrs;
xpu_ptrs.reserve(cpu.size());
for (size_t i = 0; i < cpu.size(); ++i) {
xpu[i].Resize(cpu[i].dims());
xpu[i].set_layout(cpu[i].layout());
xpu_ptrs.emplace_back(dev_ctx_xpu->Alloc(&xpu[i], cpu[i].type()));
}
phi::backends::xpu::XPUDeviceGuard guard(place_.device);
int r = xpu_event_record(events_[i].get(), compute_stream_);
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_event_record");
r = xpu_stream_wait_event(stream_.get(), events_[i].get());
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_stream_wait_event");
phi::RecordEvent record_event(
"BufferedReader:MemoryCopy", phi::TracerEventType::UserDefined, 1);
for (size_t i = 0; i < cpu.size(); ++i) {
auto cpu_place = cpu[i].place();
auto cpu_ptr = cpu[i].data();
auto xpu_ptr = xpu_ptrs[i];
auto size = cpu[i].numel() * phi::SizeOf(cpu[i].dtype());
// TODO(zhanghuan) for now hardware not support xpu_memcpy_async, maybe
// KL3
if ((cpu_place.GetType() == AllocationType::XPU)) {
platform::XPUStreamSync(stream_.get());
char *tmp = new char[size];
PADDLE_ENFORCE_XPU_SUCCESS(xpu_memcpy(
tmp, cpu_ptr, size, XPUMemcpyKind::XPU_DEVICE_TO_HOST));
PADDLE_ENFORCE_XPU_SUCCESS(xpu_memcpy(
xpu_ptr, tmp, size, XPUMemcpyKind::XPU_HOST_TO_DEVICE));
delete[] tmp;
} else {
phi::memory_utils::Copy(place_, xpu_ptr, cpu_place, cpu_ptr, size);
}
xpu[i].set_lod(cpu[i].lod());
}
platform::XPUStreamSync(stream_.get());
}
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
if (place_.GetType() == AllocationType::CUSTOM) {
auto dev_ctx_custom =
(phi::CustomContext *)(phi::DeviceContextPool::Instance().Get(
place_));
phi::DeviceManager::SetDevice(place_);
TensorVec &custom_device = custom_device_buffer_[i];
if (custom_device.empty()) {
custom_device.resize(cpu.size());
} else {
PADDLE_ENFORCE_EQ(custom_device.size(),
cpu.size(),
common::errors::InvalidArgument(
"Input tensor number on CustomDevice and CPU "
"devices are not matched. "
"The number on CustomDevice is %d, on CPU is %d",
custom_device.size(),
cpu.size()));
}
std::vector<void *> custom_device_ptrs;
custom_device_ptrs.reserve(cpu.size());
for (size_t i = 0; i < cpu.size(); ++i) {
custom_device[i].Resize(cpu[i].dims());
custom_device[i].set_layout(cpu[i].layout());
custom_device_ptrs.emplace_back(
dev_ctx_custom->Alloc(&custom_device[i], cpu[i].type()));
}
phi::DeviceManager::GetDeviceWithPlace(place_)->RecordEvent(
custom_device_events_[i].get(), custom_device_compute_stream_.get());
phi::DeviceManager::GetDeviceWithPlace(place_)->StreamWaitEvent(
custom_device_stream_.get(), custom_device_events_[i].get());
phi::RecordEvent record_event(
"BufferedReader:MemoryCopy", phi::TracerEventType::UserDefined, 1);
for (size_t i = 0; i < cpu.size(); ++i) {
auto cpu_place = cpu[i].place();
auto cpu_ptr = cpu[i].data();
auto custom_device_ptr = custom_device_ptrs[i];
auto size = cpu[i].numel() * phi::SizeOf(cpu[i].dtype());
if ((cpu_place.GetType() == AllocationType::CUSTOM)) {
phi::memory_utils::Copy(
place_, custom_device_ptr, cpu_place, cpu_ptr, size);
custom_device_stream_->Synchronize();
} else {
phi::memory_utils::Copy(
place_, custom_device_ptr, cpu_place, cpu_ptr, size);
}
custom_device[i].set_lod(cpu[i].lod());
}
custom_device_stream_->Synchronize();
}
#endif
return i;
}));
}
void BufferedReader::ShutdownImpl() {
VLOG(1) << "ShutdownImpl";
reader_->Shutdown();
while (!position_.empty()) {
position_.pop();
}
prev_pos_ = -1UL;
}
void BufferedReader::StartImpl() {
reader_->Start();
ReadTillBufferFullAsync();
}
void BufferedReader::ReadNextImpl(phi::TensorArray *out) {
if (position_.empty()) {
out->clear();
return;
}
size_t i = position_.front().get();
position_.pop();
if (i == -1UL) {
ReadNextImpl(out);
return;
}
if (place_.GetType() == AllocationType::GPU) { // NOLINT
*out = std::move(cuda_buffer_[i]);
} else if (place_.GetType() == AllocationType::XPU) {
*out = std::move(xpu_buffer_[i]);
} else if (place_.GetType() == AllocationType::CUSTOM) {
*out = std::move(custom_device_buffer_[i]);
} else {
*out = std::move(cpu_buffer_[i]);
}
// Do not push current position into ReadAsync. Push the previous position
// Since all computation in fluid are async, change the data of
// current position may cause data error.
if (prev_pos_ != -1Ul) {
ReadAsync(prev_pos_);
}
prev_pos_ = i;
}
} // namespace paddle::operators::reader
@@ -0,0 +1,104 @@
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <list>
#include <memory>
#include <queue>
#include <vector>
#include "ThreadPool.h"
#include "paddle/phi/core/framework/reader.h"
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
#include "paddle/phi/backends/gpu/gpu_info.h"
#include "paddle/phi/core/platform/device/gpu/gpu_resource_pool.h"
#endif
#ifdef PADDLE_WITH_XPU
#include "paddle/phi/core/platform/device/xpu/xpu_info.h"
#include "paddle/phi/core/platform/device/xpu/xpu_resource_pool.h"
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
#include "paddle/phi/backends/event.h"
#include "paddle/phi/backends/stream.h"
#endif
namespace paddle {
namespace operators {
namespace reader {
class PADDLE_API BufferedReader : public framework::DecoratedReader {
using TensorVec = phi::TensorArray;
using VecFuture = std::future<TensorVec>;
public:
BufferedReader(const std::shared_ptr<framework::ReaderBase>& reader,
const Place& place,
size_t buffer_size,
bool pin_memory = false);
~BufferedReader() override;
Place GetPlace() const { return place_; }
private:
void ReadTillBufferFullAsync();
void ReadAsync(size_t i);
protected:
void ShutdownImpl() override;
void StartImpl() override;
void ReadNextImpl(phi::TensorArray* out) override;
private:
ThreadPool thread_pool_;
Place place_;
const size_t buffer_size_;
bool pin_memory_;
std::queue<std::future<size_t>> position_;
// The buffer for reading data.
// NOTE: the simplest way to implement buffered reader is do not use any
// buffer, just read async and create futures as buffer size. However, to
// malloc tensors every time is extremely slow. Here we store all data in
// buffers and prevent alloc every time.
std::vector<TensorVec> cpu_buffer_;
std::vector<TensorVec> cuda_buffer_;
std::vector<TensorVec> xpu_buffer_;
std::vector<TensorVec> custom_device_buffer_;
size_t prev_pos_{-1UL};
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
gpuStream_t compute_stream_;
std::shared_ptr<platform::CudaStreamObject> stream_ = nullptr;
std::vector<std::shared_ptr<platform::CudaEventObject>> events_{};
#endif
#ifdef PADDLE_WITH_XPU
xpuStream compute_stream_;
std::shared_ptr<platform::XpuStreamObject> stream_ = nullptr;
std::vector<std::shared_ptr<platform::XpuEventObject>> events_{};
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
std::shared_ptr<phi::stream::Stream> custom_device_compute_stream_ = nullptr;
std::shared_ptr<phi::stream::Stream> custom_device_stream_ = nullptr;
std::vector<std::shared_ptr<phi::event::Event>> custom_device_events_{};
#endif
};
} // namespace reader
} // namespace operators
} // namespace paddle
@@ -0,0 +1,253 @@
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <memory>
#include <utility>
#include <vector>
#include "paddle/common/ddim.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/operators/reader/blocking_queue.h"
#include "paddle/phi/core/tensor_array.h"
namespace paddle {
namespace operators {
namespace reader {
class DenseTensorBlockingQueue {
public:
explicit DenseTensorBlockingQueue(size_t capacity,
bool speed_test_mode = false)
: queue_(capacity, speed_test_mode) {}
~DenseTensorBlockingQueue() {
// VLOG(10) << "Destruct DenseTensorBlockingQueue";
}
bool Push(const phi::TensorArray& lod_tensor_vec) {
return queue_.Send(lod_tensor_vec);
}
bool Push(phi::TensorArray&& lod_tensor_vec) {
return queue_.Send(std::move(lod_tensor_vec));
}
phi::TensorArray Pop(bool* ok = nullptr) {
phi::TensorArray lod_tensor_vec;
bool success = queue_.Receive(&lod_tensor_vec);
if (ok != nullptr) *ok = success;
return lod_tensor_vec;
}
inline size_t Cap() const { return queue_.Cap(); }
inline size_t Size() const { return queue_.Size(); }
inline void ReOpen() { queue_.ReOpen(); }
inline void Close() {
// VLOG(1) << "DenseTensorBlockingQueue close";
queue_.Close();
}
inline bool IsClosed() const { return queue_.IsClosed(); }
inline void Kill() { queue_.Kill(); }
inline bool WaitForInited(size_t) { return true; }
private:
BlockingQueue<phi::TensorArray> queue_;
};
class OrderedMultiDeviceDenseTensorBlockingQueue {
public:
OrderedMultiDeviceDenseTensorBlockingQueue(size_t capacity,
bool speed_test_mode = false)
: capacity_(capacity), speed_test_mode_(speed_test_mode) {}
~OrderedMultiDeviceDenseTensorBlockingQueue() {
// VLOG(10) << "Destruct OrderedMultiDeviceDenseTensorBlockingQueue";
}
bool WaitForInited(size_t milliseconds) {
std::unique_lock<std::mutex> lock(init_mutex_);
return cv_.wait_for(lock, std::chrono::milliseconds(milliseconds), [this] {
return !queues_.empty();
});
}
void SetDeviceCount(size_t dev_cnt) {
{
std::lock_guard<std::mutex> lock(init_mutex_);
PADDLE_ENFORCE_GE(dev_cnt,
1,
common::errors::InvalidArgument(
"Device count to init "
"OrderedMultiDeviceDenseTensorBlockingQueue"
" must be larger than 1"));
if (!queues_.empty()) {
PADDLE_ENFORCE_EQ(queues_.size(),
dev_cnt,
common::errors::InvalidArgument(
"queues should be only inited once"));
return;
}
// VLOG(1) << "Init queue with size " << dev_cnt;
queues_.resize(dev_cnt);
for (auto& item : queues_) {
auto cap = (capacity_ + dev_cnt - 1) / dev_cnt;
item =
std::make_unique<DenseTensorBlockingQueue>(cap, speed_test_mode_);
}
}
cv_.notify_all();
}
const std::shared_ptr<DenseTensorBlockingQueue>& GetQueue(size_t idx) const {
EnforceIsInited();
PADDLE_ENFORCE_LT(
idx,
queues_.size(),
common::errors::OutOfRange("The queue index is out of range"));
return queues_[idx];
}
bool Push(const phi::TensorArray& lod_tensor_vec) {
return CurQueue()->Push(lod_tensor_vec);
}
inline size_t Size() const {
size_t size = 0;
for (auto& item : queues_) {
size += item->Size();
}
return size;
}
inline void Close() {
for (auto& item : queues_) {
item->Close();
}
}
inline void Kill() {
for (auto& item : queues_) {
item->Kill();
}
}
inline void Reset() {
{
std::lock_guard<std::mutex> reset_lock(reset_mutex_);
for (auto& method : reset_methods_) {
if (method) method();
}
}
auto dev_cnt = queues_.size();
for (auto& item : queues_) {
auto cap = (capacity_ + dev_cnt - 1) / dev_cnt;
item = std::make_unique<DenseTensorBlockingQueue>(cap, speed_test_mode_);
}
data_index_ = 0;
}
inline void SetResetMethod(size_t idx,
const std::function<void()>& reset_method) {
std::lock_guard<std::mutex> reset_lock(reset_mutex_);
EnforceIsInited();
if (reset_methods_.size() <= idx) {
reset_methods_.resize(idx + 1);
}
reset_methods_[idx] = reset_method;
}
inline size_t Cap() const { return capacity_; }
private:
const std::shared_ptr<DenseTensorBlockingQueue>& CurQueue() {
return queues_[(data_index_++) % queues_.size()];
}
private:
void EnforceIsInited() const {
PADDLE_ENFORCE_EQ(queues_.empty(),
false,
common::errors::NotFound("queue has not been inited"));
}
private:
std::vector<std::shared_ptr<DenseTensorBlockingQueue>> queues_;
mutable uint64_t data_index_{0};
size_t dev_cnt_{0};
const size_t capacity_;
const bool speed_test_mode_;
bool is_closed_{false};
std::vector<std::function<void()>> reset_methods_;
mutable std::mutex reset_mutex_;
mutable std::mutex init_mutex_;
mutable std::condition_variable cv_;
};
class DenseTensorBlockingQueueHolder {
public:
void InitOnce(size_t capacity, bool speed_test_mode = false) {
PADDLE_ENFORCE_EQ(
queue_,
nullptr,
common::errors::AlreadyExists("DenseTensorBlockingQueueHolder::"
"InitOnce() can only be called once"));
queue_ =
std::make_unique<DenseTensorBlockingQueue>(capacity, speed_test_mode);
}
inline const std::shared_ptr<DenseTensorBlockingQueue>& GetQueue() const {
return queue_;
}
private:
std::shared_ptr<DenseTensorBlockingQueue> queue_;
};
class OrderedMultiDeviceDenseTensorBlockingQueueHolder {
public:
void InitOnce(size_t capacity, bool speed_test_mode = false) {
PADDLE_ENFORCE_EQ(queue_,
nullptr,
common::errors::AlreadyExists(
"OrderedMultiDeviceDenseTensorBlockingQueueHolder::"
"InitOnce() can only be called once"));
queue_ = std::make_unique<OrderedMultiDeviceDenseTensorBlockingQueue>(
capacity, speed_test_mode);
}
inline const std::shared_ptr<OrderedMultiDeviceDenseTensorBlockingQueue>&
GetQueue() const {
return queue_;
}
private:
std::shared_ptr<OrderedMultiDeviceDenseTensorBlockingQueue> queue_;
};
} // namespace reader
} // namespace operators
} // namespace paddle
@@ -0,0 +1,45 @@
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/phi/core/operators/reader/py_reader.h"
namespace paddle::operators::reader {
PyReader::PyReader(
const std::shared_ptr<DenseTensorBlockingQueue>& queue,
const std::vector<phi::DDim>& dims,
const std::vector<framework::proto::VarType::Type>& var_types,
const std::vector<bool>& need_check_feed)
: framework::FileReader(dims, var_types, need_check_feed) {
PADDLE_ENFORCE_NOT_NULL(queue,
common::errors::PreconditionNotMet(
"DenseTensorBlockingQueue must not be null."));
queue_ = queue;
}
void PyReader::ReadNext(phi::TensorArray* out) {
bool success = false;
*out = queue_->Pop(&success);
if (!success) out->clear();
}
PyReader::~PyReader() { // NOLINT
queue_->Close();
}
void PyReader::Shutdown() { queue_->Close(); }
void PyReader::Start() { queue_->ReOpen(); }
} // namespace paddle::operators::reader
@@ -0,0 +1,52 @@
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <atomic>
#include <memory>
#include <vector>
#include "paddle/phi/core/framework/reader.h"
#include "paddle/phi/core/operators/reader/dense_tensor_blocking_queue.h"
namespace paddle {
namespace operators {
namespace reader {
class DenseTensorBlockingQueue;
class PADDLE_API PyReader : public framework::FileReader {
public:
explicit PyReader(
const std::shared_ptr<DenseTensorBlockingQueue>& queue,
const std::vector<phi::DDim>& dims,
const std::vector<framework::proto::VarType::Type>& var_types,
const std::vector<bool>& need_check_feed);
void ReadNext(phi::TensorArray* out) override;
~PyReader();
void Shutdown() override;
void Start() override;
private:
std::shared_ptr<DenseTensorBlockingQueue> queue_;
};
} // namespace reader
} // namespace operators
} // namespace paddle