chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
// Copyright (c) 2023 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 <assert.h>
|
||||
#include "paddle/phi/kernels/funcs/aligned_vector.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
|
||||
#define CUDART_INF __longlong_as_double(0x7ff0000000000000ULL)
|
||||
#define CUDART_INF_F __int_as_float(0x7f800000)
|
||||
|
||||
namespace phi {
|
||||
namespace funcs {
|
||||
|
||||
constexpr int kWarpSize = 32;
|
||||
|
||||
template <typename T>
|
||||
__inline__ __device__ T Inf();
|
||||
|
||||
template <>
|
||||
__inline__ __device__ float Inf<float>() {
|
||||
return CUDART_INF_F;
|
||||
}
|
||||
|
||||
template <>
|
||||
__inline__ __device__ double Inf<double>() {
|
||||
return CUDART_INF;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
template <typename>
|
||||
class Functor,
|
||||
int ThreadGroupWidth = kWarpSize>
|
||||
__inline__ __device__ T WarpAllReduce(T val) {
|
||||
for (int mask = ThreadGroupWidth / 2; mask > 0; mask /= 2) {
|
||||
#if PADDLE_WITH_HIP
|
||||
val = Functor<T>()(val, __shfl_xor(0xffffffff, val, mask));
|
||||
#else
|
||||
val = Functor<T>()(val, __shfl_xor_sync(0xffffffff, val, mask));
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
#if PADDLE_WITH_HIP
|
||||
inline void GetNumBlocks(int64_t block_size,
|
||||
int64_t max_blocks,
|
||||
int64_t waves,
|
||||
int* num_blocks) {
|
||||
int dev;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipGetDevice(&dev));
|
||||
int sm_count;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipDeviceGetAttribute(
|
||||
&sm_count, hipDeviceAttributeMultiprocessorCount, dev));
|
||||
int tpm;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipDeviceGetAttribute(
|
||||
&tpm, hipDeviceAttributeMaxThreadsPerMultiProcessor, dev));
|
||||
*num_blocks = std::max<int>(
|
||||
1, std::min<int64_t>(max_blocks, sm_count * tpm / block_size * waves));
|
||||
}
|
||||
#else
|
||||
inline void GetNumBlocks(int64_t block_size,
|
||||
int64_t max_blocks,
|
||||
int64_t waves,
|
||||
int* num_blocks) {
|
||||
int dev;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaGetDevice(&dev));
|
||||
int sm_count;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
cudaDeviceGetAttribute(&sm_count, cudaDevAttrMultiProcessorCount, dev));
|
||||
int tpm;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaDeviceGetAttribute(
|
||||
&tpm, cudaDevAttrMaxThreadsPerMultiProcessor, dev));
|
||||
*num_blocks = std::max<int>(
|
||||
1, std::min<int64_t>(max_blocks, sm_count * tpm / block_size * waves));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T,
|
||||
typename SourceType,
|
||||
typename Context,
|
||||
int VecSize,
|
||||
int ColsPerThread,
|
||||
int RowsPerThread,
|
||||
int ThreadGroupWidth,
|
||||
bool NeedPadding>
|
||||
__global__ void LogsumexpWarpImpl(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
static_assert(ColsPerThread % VecSize == 0, "");
|
||||
static_assert(ThreadGroupWidth <= kWarpSize, "");
|
||||
static_assert(kWarpSize % ThreadGroupWidth == 0, "");
|
||||
constexpr int num_read = ColsPerThread / VecSize;
|
||||
assert(num_col <= ColsPerThread * ThreadGroupWidth);
|
||||
const int group_id = blockIdx.x * blockDim.y + threadIdx.y;
|
||||
const int num_thread_group = gridDim.x * blockDim.y;
|
||||
const int thread_id = threadIdx.x;
|
||||
const int step = num_thread_group * RowsPerThread;
|
||||
|
||||
using LoadType = AlignedVector<SourceType, VecSize>;
|
||||
using StoreType = AlignedVector<SourceType, RowsPerThread>;
|
||||
|
||||
LoadType load_vec;
|
||||
StoreType store_vec;
|
||||
|
||||
T buffer[RowsPerThread][ColsPerThread];
|
||||
|
||||
for (int64_t cur_row = group_id * RowsPerThread; cur_row < num_row;
|
||||
cur_row += step) {
|
||||
T thread_max[RowsPerThread];
|
||||
// Read data
|
||||
#pragma unroll
|
||||
for (int row_id = 0; row_id < RowsPerThread; row_id++) {
|
||||
thread_max[row_id] = -Inf<T>();
|
||||
T* row_buffer = buffer[row_id];
|
||||
#pragma unroll
|
||||
for (int read_id = 0; read_id < num_read; read_id++) {
|
||||
const int offset = read_id * VecSize;
|
||||
const int cur_col = (read_id * ThreadGroupWidth + thread_id) * VecSize;
|
||||
if (!NeedPadding || cur_col < num_col) {
|
||||
int64_t load_offset = ((cur_row + row_id) * num_col + cur_col);
|
||||
Load<SourceType, VecSize>(in + load_offset, &load_vec);
|
||||
#pragma unroll
|
||||
for (int i = 0; i < VecSize; i++) {
|
||||
row_buffer[offset + i] = static_cast<T>(load_vec[i]);
|
||||
thread_max[row_id] =
|
||||
max(thread_max[row_id], row_buffer[offset + i]);
|
||||
}
|
||||
} else {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < VecSize; i++) {
|
||||
row_buffer[offset + i] = -Inf<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
T warp_max[RowsPerThread];
|
||||
// Get warp max
|
||||
#pragma unroll
|
||||
for (int row_id = 0; row_id < RowsPerThread; row_id++) {
|
||||
warp_max[row_id] = WarpAllReduce<T, kps::MaxFunctor, ThreadGroupWidth>(
|
||||
thread_max[row_id]);
|
||||
}
|
||||
T thread_sum[RowsPerThread];
|
||||
// Calculate
|
||||
#pragma unroll
|
||||
for (int row_id = 0; row_id < RowsPerThread; row_id++) {
|
||||
thread_sum[row_id] = 0;
|
||||
T* row_buffer = buffer[row_id];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < ColsPerThread; i++) {
|
||||
thread_sum[row_id] += exp(row_buffer[i] - warp_max[row_id]);
|
||||
}
|
||||
}
|
||||
// Get warp sum and write
|
||||
#pragma unroll
|
||||
for (int row_id = 0; row_id < RowsPerThread; row_id++) {
|
||||
T res = log(WarpAllReduce<T, kps::AddFunctor, ThreadGroupWidth>(
|
||||
thread_sum[row_id]));
|
||||
store_vec[row_id] = static_cast<SourceType>(res + warp_max[row_id]);
|
||||
}
|
||||
if (thread_id == 0 && cur_row < num_row) {
|
||||
Store<SourceType, RowsPerThread>(store_vec, out + cur_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename SourceType,
|
||||
typename Context,
|
||||
int VecSize,
|
||||
int ColsPerThread,
|
||||
int RowsPerThread,
|
||||
int ThreadGroupWidth,
|
||||
bool NeedPadding>
|
||||
#if PADDLE_WITH_HIP
|
||||
inline hipError_t LaunchLogsumexpWarp(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#else
|
||||
inline cudaError_t LaunchLogsumexpWarp(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#endif
|
||||
constexpr int block_size = 128;
|
||||
constexpr int waves = 32;
|
||||
static_assert(block_size % ThreadGroupWidth == 0, "");
|
||||
constexpr int thread_groups_per_block = block_size / ThreadGroupWidth;
|
||||
dim3 block_dim(ThreadGroupWidth, thread_groups_per_block);
|
||||
const int64_t num_blocks =
|
||||
(num_row / RowsPerThread + thread_groups_per_block - 1) /
|
||||
thread_groups_per_block;
|
||||
int grid_dim_x;
|
||||
{ GetNumBlocks(block_size, num_blocks, waves, &grid_dim_x); }
|
||||
LogsumexpWarpImpl<T,
|
||||
SourceType,
|
||||
Context,
|
||||
VecSize,
|
||||
ColsPerThread,
|
||||
RowsPerThread,
|
||||
ThreadGroupWidth,
|
||||
NeedPadding>
|
||||
<<<grid_dim_x, block_dim, 0, dev_ctx.stream()>>>(
|
||||
dev_ctx, num_row, num_col, in, out);
|
||||
#if PADDLE_WITH_HIP
|
||||
return hipPeekAtLastError();
|
||||
#else
|
||||
return cudaPeekAtLastError();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename SourceType,
|
||||
typename Context,
|
||||
int VecSize,
|
||||
int ColsPerThread,
|
||||
int RowsPerThread,
|
||||
int ThreadGroupWidth>
|
||||
#if PADDLE_WITH_HIP
|
||||
inline hipError_t DispatchLogsumexpWarpWithPadding(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#else
|
||||
inline cudaError_t DispatchLogsumexpWarpWithPadding(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#endif
|
||||
if (num_col == ColsPerThread * ThreadGroupWidth) {
|
||||
return LaunchLogsumexpWarp<T,
|
||||
SourceType,
|
||||
Context,
|
||||
VecSize,
|
||||
ColsPerThread,
|
||||
RowsPerThread,
|
||||
ThreadGroupWidth,
|
||||
false>(dev_ctx, num_row, num_col, in, out);
|
||||
} else {
|
||||
return LaunchLogsumexpWarp<T,
|
||||
SourceType,
|
||||
Context,
|
||||
VecSize,
|
||||
ColsPerThread,
|
||||
RowsPerThread,
|
||||
ThreadGroupWidth,
|
||||
true>(dev_ctx, num_row, num_col, in, out);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename SourceType, typename Context, int VecSize>
|
||||
#if PADDLE_WITH_HIP
|
||||
typename std::enable_if<VecSize == 1, hipError_t>::type
|
||||
DispatchLogsumexpWarpCols(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#else
|
||||
typename std::enable_if<VecSize == 1, cudaError_t>::type
|
||||
DispatchLogsumexpWarpCols(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#endif
|
||||
if (num_col <= 0) {
|
||||
#if PADDLE_WITH_HIP
|
||||
return hipErrorInvalidValue;
|
||||
#else
|
||||
return cudaErrorInvalidValue;
|
||||
#endif
|
||||
}
|
||||
#define HANDLE_THREAD_GROUP(thread_group_width) \
|
||||
if (num_col <= (thread_group_width)*VecSize) { \
|
||||
if (num_row % 2 == 0) { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
VecSize, \
|
||||
2, \
|
||||
thread_group_width>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
} else { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
VecSize, \
|
||||
1, \
|
||||
thread_group_width>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
} \
|
||||
}
|
||||
HANDLE_THREAD_GROUP(1)
|
||||
HANDLE_THREAD_GROUP(2)
|
||||
HANDLE_THREAD_GROUP(4)
|
||||
HANDLE_THREAD_GROUP(8)
|
||||
HANDLE_THREAD_GROUP(16)
|
||||
HANDLE_THREAD_GROUP(32)
|
||||
#undef HANDLE_ROWS
|
||||
// if num_col > 32
|
||||
#define HANDLE_COL(col) \
|
||||
if (num_col <= (col)*kWarpSize) { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
col, \
|
||||
1, \
|
||||
kWarpSize>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
}
|
||||
|
||||
HANDLE_COL(2)
|
||||
HANDLE_COL(3)
|
||||
HANDLE_COL(4)
|
||||
HANDLE_COL(5)
|
||||
HANDLE_COL(6)
|
||||
HANDLE_COL(7)
|
||||
HANDLE_COL(8)
|
||||
HANDLE_COL(9)
|
||||
HANDLE_COL(10)
|
||||
HANDLE_COL(11)
|
||||
HANDLE_COL(12)
|
||||
HANDLE_COL(13)
|
||||
HANDLE_COL(14)
|
||||
HANDLE_COL(15)
|
||||
HANDLE_COL(16)
|
||||
HANDLE_COL(17)
|
||||
HANDLE_COL(18)
|
||||
HANDLE_COL(19)
|
||||
HANDLE_COL(20)
|
||||
HANDLE_COL(21)
|
||||
HANDLE_COL(22)
|
||||
HANDLE_COL(23)
|
||||
HANDLE_COL(24)
|
||||
HANDLE_COL(25)
|
||||
HANDLE_COL(26)
|
||||
HANDLE_COL(27)
|
||||
HANDLE_COL(28)
|
||||
HANDLE_COL(29)
|
||||
HANDLE_COL(30)
|
||||
HANDLE_COL(31)
|
||||
HANDLE_COL(32)
|
||||
#undef HANDLE_COL
|
||||
#if PADDLE_WITH_HIP
|
||||
return hipErrorInvalidValue;
|
||||
#else
|
||||
return cudaErrorInvalidValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename SourceType, typename Context, int VecSize>
|
||||
#if PADDLE_WITH_HIP
|
||||
typename std::enable_if<VecSize == 2, hipError_t>::type
|
||||
DispatchLogsumexpWarpCols(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#else
|
||||
typename std::enable_if<VecSize == 2, cudaError_t>::type
|
||||
DispatchLogsumexpWarpCols(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#endif
|
||||
if (num_col <= 0) {
|
||||
#if PADDLE_WITH_HIP
|
||||
return hipErrorInvalidValue;
|
||||
#else
|
||||
return cudaErrorInvalidValue;
|
||||
#endif
|
||||
}
|
||||
#define HANDLE_THREAD_GROUP(thread_group_width) \
|
||||
if (num_col <= (thread_group_width)*VecSize) { \
|
||||
if (num_row % 2 == 0) { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
VecSize, \
|
||||
2, \
|
||||
thread_group_width>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
} else { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
VecSize, \
|
||||
1, \
|
||||
thread_group_width>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
} \
|
||||
}
|
||||
HANDLE_THREAD_GROUP(1)
|
||||
HANDLE_THREAD_GROUP(2)
|
||||
HANDLE_THREAD_GROUP(4)
|
||||
HANDLE_THREAD_GROUP(8)
|
||||
HANDLE_THREAD_GROUP(16)
|
||||
HANDLE_THREAD_GROUP(32)
|
||||
#undef HANDLE_THREAD_GROUP
|
||||
// if num_col > 32
|
||||
#define HANDLE_COL(col) \
|
||||
if (num_col <= (col)*kWarpSize) { \
|
||||
return DispatchLogsumexpWarpWithPadding<T, \
|
||||
SourceType, \
|
||||
Context, \
|
||||
VecSize, \
|
||||
col, \
|
||||
1, \
|
||||
kWarpSize>( \
|
||||
dev_ctx, num_row, num_col, in, out); \
|
||||
}
|
||||
|
||||
HANDLE_COL(4)
|
||||
HANDLE_COL(6)
|
||||
HANDLE_COL(8)
|
||||
HANDLE_COL(10)
|
||||
HANDLE_COL(12)
|
||||
HANDLE_COL(14)
|
||||
HANDLE_COL(16)
|
||||
HANDLE_COL(18)
|
||||
HANDLE_COL(20)
|
||||
HANDLE_COL(22)
|
||||
HANDLE_COL(24)
|
||||
HANDLE_COL(26)
|
||||
HANDLE_COL(28)
|
||||
HANDLE_COL(30)
|
||||
HANDLE_COL(32)
|
||||
#undef HANDLE_COL
|
||||
#if PADDLE_WITH_HIP
|
||||
return hipErrorInvalidValue;
|
||||
#else
|
||||
return cudaErrorInvalidValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename SourceType, typename Context>
|
||||
#if PADDLE_WITH_HIP
|
||||
inline hipError_t DispatchLogsumexpWarp(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#else
|
||||
inline cudaError_t DispatchLogsumexpWarp(const Context& dev_ctx,
|
||||
const int64_t num_row,
|
||||
const int64_t num_col,
|
||||
const SourceType* in,
|
||||
SourceType* out) {
|
||||
#endif
|
||||
// dispatch logsumexp warp with vecsize
|
||||
if (num_col % 2 == 0) {
|
||||
return DispatchLogsumexpWarpCols<T, SourceType, Context, 2>(
|
||||
dev_ctx, num_row, num_col, in, out);
|
||||
} else {
|
||||
return DispatchLogsumexpWarpCols<T, SourceType, Context, 1>(
|
||||
dev_ctx, num_row, num_col, in, out);
|
||||
}
|
||||
}
|
||||
} // namespace funcs
|
||||
} // namespace phi
|
||||
Reference in New Issue
Block a user