Files
2026-07-13 12:40:42 +08:00

258 lines
7.8 KiB
C++

// 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 "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
#include "paddle/phi/common/memory_utils.h"
#include "paddle/phi/core/dense_tensor.h"
namespace phi {
namespace funcs {
#ifndef PADDLE_WITH_HIP
#if !defined(_WIN32)
#define PADDLE_ALIGN(x) __attribute__((aligned(x)))
#else
#define PADDLE_ALIGN(x)
#endif
#else
#define PADDLE_ALIGN(x)
#endif
enum class SegmentedArraySize {
kVariableLength = 0,
kFixed4 = 4,
kFixed8 = 8,
kFixed16 = 16,
kFixed32 = 32,
kFixed64 = 64,
};
template <typename T, SegmentedArraySize Size, int Num = static_cast<int>(Size)>
struct PADDLE_ALIGN(256) ValueArray {
public:
T data[Num];
void Set(T* ptr, const int num) {
for (auto i = 0; i < num; ++i) {
data[i] = ptr[i];
}
}
};
template <typename T>
struct PADDLE_ALIGN(256) ValueArray<T, SegmentedArraySize::kVariableLength, 0> {
public:
T* data{nullptr};
void Set(T* ptr, const int num) { data = ptr; }
};
template <typename T, SegmentedArraySize Size>
struct PADDLE_ALIGN(256) ConstPointerArray {
public:
const T* data[static_cast<int>(Size)];
void Set(const std::vector<const T*>& ptrs, const T** dev_ptr = nullptr) {
for (auto i = 0; i < ptrs.size(); ++i) {
data[i] = ptrs[i];
}
}
};
template <typename T>
struct PADDLE_ALIGN(256)
ConstPointerArray<T, SegmentedArraySize::kVariableLength> {
public:
const T** data{nullptr};
void Set(const std::vector<const T*>& ptrs, const T** dev_ptr = nullptr) {
data = dev_ptr;
}
};
template <typename T, SegmentedArraySize Size>
struct PADDLE_ALIGN(256) PointerArray {
public:
T* data[static_cast<int>(Size)];
void Set(T** ptrs, const int num, T** dev_ptr = nullptr) {
for (auto i = 0; i < num; ++i) {
data[i] = ptrs[i];
}
}
};
template <typename T>
struct PADDLE_ALIGN(256) PointerArray<T, SegmentedArraySize::kVariableLength> {
public:
T** data{nullptr};
void Set(T** ptrs, const int num, T** dev_ptr = nullptr) { data = dev_ptr; }
};
#undef PADDLE_ALIGN
template <typename Context>
struct ArraySetterBase {
protected:
void* AllocAndCopy(const Context& dev_ctx,
void* src,
size_t num_bytes,
bool use_cuda_graph = false) {
auto allocation = phi::memory_utils::Alloc(
dev_ctx.GetPlace(),
num_bytes,
phi::Stream(reinterpret_cast<phi::StreamId>(dev_ctx.stream())));
int8_t* restored = reinterpret_cast<int8_t*>(src);
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
if (use_cuda_graph) {
restored = phi::backends::gpu::RestoreHostMemIfCapturingCUDAGraph<int8_t>(
restored, num_bytes);
}
#endif
phi::backends::gpu::GpuMemcpyAsync(allocation->ptr(),
restored,
num_bytes,
phi::gpuMemcpyHostToDevice,
dev_ctx.stream());
auto ptr = allocation->ptr();
allocations.emplace_back(std::move(allocation));
return ptr;
}
std::vector<phi::Allocator::AllocationPtr> allocations;
};
template <typename Context, typename T, SegmentedArraySize Size>
struct ConstPointerArraySetter : public ArraySetterBase<Context> {
public:
ConstPointerArray<T, Size> array;
ConstPointerArraySetter(const Context& dev_ctx,
const std::vector<const DenseTensor*>& t) {
ptrs.resize(t.size());
for (int i = 0; i < t.size(); ++i) {
ptrs[i] = t[i]->data<T>();
}
const T** dev_ptr = nullptr;
if (Size == SegmentedArraySize::kVariableLength) {
size_t num_bytes = t.size() * sizeof(T*);
dev_ptr = reinterpret_cast<const T**>(this->AllocAndCopy(
dev_ctx, reinterpret_cast<void*>(ptrs.data()), num_bytes));
}
array.Set(ptrs, dev_ptr);
}
private:
std::vector<const T*> ptrs;
};
template <typename Context, typename T, SegmentedArraySize Size>
struct PointerArraySetter : public ArraySetterBase<Context> {
public:
PointerArray<T, Size> array;
// need_alloc : tensor data needs extra buffer or not.
// use_cuda_graph: tensor data shall be captured by cuda_graph or not.
// pre_alloc_host_buf: tensor data is temporarily stored by pinned memory or
// not.
PointerArraySetter(const Context& dev_ctx,
std::vector<DenseTensor*>* t,
bool need_alloc = false,
bool use_cuda_graph = false,
T** pre_alloc_host_buf = nullptr) {
ptrs.resize(t->size());
T** data_ptr = ptrs.data();
#ifdef PADDLE_WITH_HIP
if (pre_alloc_host_buf) {
data_ptr = pre_alloc_host_buf;
}
#endif
for (int i = 0; i < t->size(); ++i) {
if (t->at(i) && (t->at(i)->numel() > 0)) {
data_ptr[i] = need_alloc ? dev_ctx.template Alloc<T>(t->at(i))
: t->at(i)->data<T>();
} else {
data_ptr[i] = nullptr;
}
}
T** dev_ptr = nullptr;
if (Size == SegmentedArraySize::kVariableLength) {
size_t num_bytes = t->size() * sizeof(T*);
dev_ptr = reinterpret_cast<T**>(
this->AllocAndCopy(dev_ctx,
reinterpret_cast<void*>(data_ptr),
num_bytes,
use_cuda_graph));
}
array.Set(data_ptr, t->size(), dev_ptr);
}
private:
std::vector<T*> ptrs;
};
inline SegmentedArraySize CalcArraySize(int n) {
if (n <= 4) {
return SegmentedArraySize::kFixed4;
} else if (n <= 8) {
return SegmentedArraySize::kFixed8;
} else if (n <= 16) {
return SegmentedArraySize::kFixed16;
} else if (n <= 32) {
return SegmentedArraySize::kFixed32;
} else if (n <= 64) {
return SegmentedArraySize::kFixed64;
} else {
return SegmentedArraySize::kVariableLength;
}
}
} // namespace funcs
#define _SEGMENTED_ARRAY_KERNEL_CASE(size, ...) \
case (size): { \
constexpr auto kArraySize = (size); \
__VA_ARGS__; \
} break
#define _SEGMENTED_ARRAY_KERNEL_DEFAULT(size, ...) \
default: { \
constexpr auto kArraySize = (size); \
__VA_ARGS__; \
} break
#define SEGMENTED_ARRAY_KERNEL_HELPER(...) \
_SEGMENTED_ARRAY_KERNEL_CASE(funcs::SegmentedArraySize::kFixed4, \
##__VA_ARGS__); \
_SEGMENTED_ARRAY_KERNEL_CASE(funcs::SegmentedArraySize::kFixed8, \
##__VA_ARGS__); \
_SEGMENTED_ARRAY_KERNEL_CASE(funcs::SegmentedArraySize::kFixed16, \
##__VA_ARGS__); \
_SEGMENTED_ARRAY_KERNEL_CASE(funcs::SegmentedArraySize::kFixed32, \
##__VA_ARGS__); \
_SEGMENTED_ARRAY_KERNEL_CASE(funcs::SegmentedArraySize::kFixed64, \
##__VA_ARGS__); \
_SEGMENTED_ARRAY_KERNEL_DEFAULT(funcs::SegmentedArraySize::kVariableLength, \
##__VA_ARGS__);
} // namespace phi