chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
if(WITH_GPU)
|
||||
add_subdirectory(cuda)
|
||||
|
||||
nv_test(cuda_helper_test SRCS cuda_helper_test.cu)
|
||||
nv_test(
|
||||
cudnn_desc_test
|
||||
SRCS cudnn_desc_test.cc
|
||||
DEPS phi common)
|
||||
elseif(WITH_ROCM)
|
||||
add_subdirectory(rocm)
|
||||
|
||||
hip_test(cuda_helper_test SRCS cuda_helper_test.cu)
|
||||
hip_test(
|
||||
cudnn_desc_test
|
||||
SRCS cudnn_desc_test.cc
|
||||
DEPS phi common)
|
||||
endif()
|
||||
@@ -0,0 +1,4 @@
|
||||
nv_test(
|
||||
cudnn_helper_test
|
||||
SRCS cudnn_helper_test.cc
|
||||
DEPS phi common)
|
||||
@@ -0,0 +1,163 @@
|
||||
/* Copyright (c) 2016 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. */
|
||||
|
||||
#define GOOGLE_GLOG_DLL_DECL
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_dnn.h"
|
||||
|
||||
TEST(CudnnHelper, ScopedTensorDescriptor) {
|
||||
using phi::DataLayout;
|
||||
using phi::backends::gpu::ScopedTensorDescriptor;
|
||||
|
||||
ScopedTensorDescriptor tensor_desc;
|
||||
std::vector<int> shape = {2, 4, 6, 6};
|
||||
auto desc = tensor_desc.descriptor<float>(DataLayout::NCHW, shape);
|
||||
|
||||
cudnnDataType_t type;
|
||||
int nd;
|
||||
std::vector<int> dims(4);
|
||||
std::vector<int> strides(4);
|
||||
phi::dynload::cudnnGetTensorNdDescriptor(
|
||||
desc, 4, &type, &nd, dims.data(), strides.data());
|
||||
|
||||
EXPECT_EQ(nd, 4);
|
||||
for (size_t i = 0; i < dims.size(); ++i) {
|
||||
EXPECT_EQ(dims[i], shape[i]);
|
||||
}
|
||||
EXPECT_EQ(strides[3], 1);
|
||||
EXPECT_EQ(strides[2], 6);
|
||||
EXPECT_EQ(strides[1], 36);
|
||||
EXPECT_EQ(strides[0], 144);
|
||||
|
||||
// test tensor5d: ScopedTensorDescriptor
|
||||
ScopedTensorDescriptor tensor5d_desc;
|
||||
std::vector<int> shape_5d = {2, 4, 6, 6, 6};
|
||||
auto desc_5d = tensor5d_desc.descriptor<float>(DataLayout::NCDHW, shape_5d);
|
||||
|
||||
std::vector<int> dims_5d(5);
|
||||
std::vector<int> strides_5d(5);
|
||||
phi::dynload::cudnnGetTensorNdDescriptor(
|
||||
desc_5d, 5, &type, &nd, dims_5d.data(), strides_5d.data());
|
||||
|
||||
EXPECT_EQ(nd, 5);
|
||||
for (size_t i = 0; i < dims_5d.size(); ++i) {
|
||||
EXPECT_EQ(dims_5d[i], shape_5d[i]);
|
||||
}
|
||||
EXPECT_EQ(strides_5d[4], 1);
|
||||
EXPECT_EQ(strides_5d[3], 6);
|
||||
EXPECT_EQ(strides_5d[2], 36);
|
||||
EXPECT_EQ(strides_5d[1], 216);
|
||||
EXPECT_EQ(strides_5d[0], 864);
|
||||
}
|
||||
|
||||
TEST(CudnnHelper, ScopedFilterDescriptor) {
|
||||
using phi::DataLayout;
|
||||
using phi::backends::gpu::GetCudnnTensorFormat;
|
||||
using phi::backends::gpu::ScopedFilterDescriptor;
|
||||
|
||||
ScopedFilterDescriptor filter_desc;
|
||||
std::vector<int> shape = {2, 3, 3};
|
||||
auto desc = filter_desc.descriptor<float>(DataLayout::NCHW, shape);
|
||||
|
||||
cudnnDataType_t type;
|
||||
int nd;
|
||||
cudnnTensorFormat_t format;
|
||||
std::vector<int> kernel(3);
|
||||
phi::dynload::cudnnGetFilterNdDescriptor(
|
||||
desc, 3, &type, &format, &nd, kernel.data());
|
||||
|
||||
EXPECT_EQ(GetCudnnTensorFormat(DataLayout::NCHW), format);
|
||||
EXPECT_EQ(nd, 3);
|
||||
for (size_t i = 0; i < shape.size(); ++i) {
|
||||
EXPECT_EQ(kernel[i], shape[i]);
|
||||
}
|
||||
|
||||
ScopedFilterDescriptor filter_desc_4d;
|
||||
std::vector<int> shape_4d = {2, 3, 3, 3};
|
||||
auto desc_4d = filter_desc.descriptor<float>(DataLayout::NCDHW, shape_4d);
|
||||
|
||||
std::vector<int> kernel_4d(4);
|
||||
phi::dynload::cudnnGetFilterNdDescriptor(
|
||||
desc_4d, 4, &type, &format, &nd, kernel_4d.data());
|
||||
|
||||
EXPECT_EQ(GetCudnnTensorFormat(DataLayout::NCHW), format);
|
||||
EXPECT_EQ(nd, 4);
|
||||
for (size_t i = 0; i < shape_4d.size(); ++i) {
|
||||
EXPECT_EQ(kernel_4d[i], shape_4d[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CudnnHelper, ScopedConvolutionDescriptor) {
|
||||
using phi::backends::gpu::ScopedConvolutionDescriptor;
|
||||
|
||||
ScopedConvolutionDescriptor conv_desc;
|
||||
std::vector<int> src_pads = {2, 2, 2};
|
||||
std::vector<int> src_strides = {1, 1, 1};
|
||||
std::vector<int> src_dilations = {1, 1, 1};
|
||||
auto desc = conv_desc.descriptor<float>(src_pads, src_strides, src_dilations);
|
||||
|
||||
cudnnDataType_t type;
|
||||
cudnnConvolutionMode_t mode;
|
||||
int nd;
|
||||
std::vector<int> pads(3);
|
||||
std::vector<int> strides(3);
|
||||
std::vector<int> dilations(3);
|
||||
phi::dynload::cudnnGetConvolutionNdDescriptor(desc,
|
||||
3,
|
||||
&nd,
|
||||
pads.data(),
|
||||
strides.data(),
|
||||
dilations.data(),
|
||||
&mode,
|
||||
&type);
|
||||
|
||||
EXPECT_EQ(nd, 3);
|
||||
for (size_t i = 0; i < src_pads.size(); ++i) {
|
||||
EXPECT_EQ(pads[i], src_pads[i]);
|
||||
EXPECT_EQ(strides[i], src_strides[i]);
|
||||
EXPECT_EQ(dilations[i], src_dilations[i]);
|
||||
}
|
||||
EXPECT_EQ(mode, CUDNN_CROSS_CORRELATION);
|
||||
}
|
||||
|
||||
TEST(CudnnHelper, ScopedPoolingDescriptor) {
|
||||
using phi::backends::gpu::PoolingMode;
|
||||
using phi::backends::gpu::ScopedPoolingDescriptor;
|
||||
|
||||
ScopedPoolingDescriptor pool_desc;
|
||||
std::vector<int> src_kernel = {2, 2, 5};
|
||||
std::vector<int> src_pads = {1, 1, 2};
|
||||
std::vector<int> src_strides = {2, 2, 3};
|
||||
auto desc = pool_desc.descriptor(
|
||||
PoolingMode::kMaximum, src_kernel, src_pads, src_strides);
|
||||
|
||||
cudnnPoolingMode_t mode;
|
||||
cudnnNanPropagation_t nan_t = CUDNN_PROPAGATE_NAN;
|
||||
int nd;
|
||||
std::vector<int> kernel(3);
|
||||
std::vector<int> pads(3);
|
||||
std::vector<int> strides(3);
|
||||
phi::dynload::cudnnGetPoolingNdDescriptor(
|
||||
desc, 3, &mode, &nan_t, &nd, kernel.data(), pads.data(), strides.data());
|
||||
|
||||
EXPECT_EQ(nd, 3);
|
||||
for (size_t i = 0; i < src_pads.size(); ++i) {
|
||||
EXPECT_EQ(kernel[i], src_kernel[i]);
|
||||
EXPECT_EQ(pads[i], src_pads[i]);
|
||||
EXPECT_EQ(strides[i], src_strides[i]);
|
||||
}
|
||||
EXPECT_EQ(mode, CUDNN_POOLING_MAX);
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#ifdef _WIN32
|
||||
#include <numeric>
|
||||
#endif
|
||||
#include <random>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_device_function.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/float16.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_helper.h"
|
||||
|
||||
using phi::PADDLE_CUDA_NUM_THREADS;
|
||||
using phi::dtype::float16;
|
||||
|
||||
template <typename T>
|
||||
__global__ void AddKernel(const T* data_a, T* data_b, size_t num) {
|
||||
CUDA_KERNEL_LOOP(i, num) { phi::CudaAtomicAdd(&data_b[i], data_a[i]); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct AddFunctor {
|
||||
T operator()(const T& a, const T& b) { return a + b; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void TestCase(size_t num) {
|
||||
T *in1, *in2, *out;
|
||||
T *d_in1, *d_in2;
|
||||
size_t size = sizeof(T) * num;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in2), size);
|
||||
#else
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in2), size);
|
||||
#endif
|
||||
in1 = reinterpret_cast<T*>(malloc(size));
|
||||
in2 = reinterpret_cast<T*>(malloc(size));
|
||||
out = reinterpret_cast<T*>(malloc(size));
|
||||
std::minstd_rand engine;
|
||||
std::uniform_real_distribution<double> dist(0.0, 1.0);
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
in1[i] = static_cast<T>(dist(engine));
|
||||
in2[i] = static_cast<T>(dist(engine));
|
||||
}
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMemcpy(d_in1, in1, size, hipMemcpyHostToDevice);
|
||||
hipMemcpy(d_in2, in2, size, hipMemcpyHostToDevice);
|
||||
hipLaunchKernelGGL(HIP_KERNEL_NAME(AddKernel<T>),
|
||||
dim3(1),
|
||||
dim3(PADDLE_CUDA_NUM_THREADS),
|
||||
0,
|
||||
0,
|
||||
d_in1,
|
||||
d_in2,
|
||||
num);
|
||||
hipDeviceSynchronize();
|
||||
hipMemcpy(out, d_in2, size, hipMemcpyDeviceToHost);
|
||||
hipDeviceSynchronize();
|
||||
#else
|
||||
cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in2, in2, size, cudaMemcpyHostToDevice);
|
||||
AddKernel<T><<<1, PADDLE_CUDA_NUM_THREADS>>>(d_in1, d_in2, num);
|
||||
cudaDeviceSynchronize();
|
||||
cudaMemcpy(out, d_in2, size, cudaMemcpyDeviceToHost);
|
||||
cudaDeviceSynchronize();
|
||||
#endif
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
// NOTE(dzhwinter): the float16 add has small underflow/overflow
|
||||
// so we use EXPECT_NEAR to check the result.
|
||||
EXPECT_NEAR(static_cast<float>(out[i]),
|
||||
static_cast<float>(AddFunctor<T>()(in1[i], in2[i])),
|
||||
0.001);
|
||||
}
|
||||
free(in1);
|
||||
free(in2);
|
||||
free(out);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipFree(d_in1);
|
||||
hipFree(d_in2);
|
||||
#else
|
||||
cudaFree(d_in1);
|
||||
cudaFree(d_in2);
|
||||
#endif
|
||||
}
|
||||
|
||||
// cuda primitives
|
||||
TEST(CudaAtomic, Add) {
|
||||
TestCase<float>(static_cast<size_t>(10));
|
||||
TestCase<float>(static_cast<size_t>(1024 * 1024));
|
||||
|
||||
TestCase<double>(static_cast<size_t>(10));
|
||||
TestCase<double>(static_cast<size_t>(1024 * 1024));
|
||||
}
|
||||
|
||||
TEST(CudaAtomic, float16) {
|
||||
TestCase<float16>(static_cast<size_t>(1));
|
||||
TestCase<float16>(static_cast<size_t>(2));
|
||||
TestCase<float16>(static_cast<size_t>(3));
|
||||
|
||||
TestCase<float16>(static_cast<size_t>(10));
|
||||
TestCase<float16>(static_cast<size_t>(1024 * 1024));
|
||||
}
|
||||
|
||||
// unalignment of uint8
|
||||
void TestUnalign(size_t num, const int shift_bit) {
|
||||
ASSERT_EQ(num % 2, 0);
|
||||
float16 *in1, *in2, *out;
|
||||
float16 *d_in1, *d_in2;
|
||||
size_t size = sizeof(uint8_t) * (num + shift_bit);
|
||||
size_t array_size = sizeof(float16) * (num / 2);
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in2), size);
|
||||
#else
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in2), size);
|
||||
#endif
|
||||
in1 = reinterpret_cast<float16*>(malloc(size));
|
||||
in2 = reinterpret_cast<float16*>(malloc(size));
|
||||
out = reinterpret_cast<float16*>(malloc(size));
|
||||
|
||||
// right shift 1, mimic the unalignment of address
|
||||
float16* r_in1 =
|
||||
reinterpret_cast<float16*>(reinterpret_cast<uint8_t*>(in1) + shift_bit);
|
||||
float16* r_in2 =
|
||||
reinterpret_cast<float16*>(reinterpret_cast<uint8_t*>(in2) + shift_bit);
|
||||
|
||||
std::minstd_rand engine;
|
||||
std::uniform_real_distribution<double> dist(0.0, 1.0);
|
||||
for (size_t i = 0; i < num / 2; ++i) {
|
||||
r_in1[i] = static_cast<float16>(dist(engine));
|
||||
r_in2[i] = static_cast<float16>(dist(engine));
|
||||
}
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMemcpy(d_in1, r_in1, array_size, hipMemcpyHostToDevice);
|
||||
hipMemcpy(d_in2, r_in2, array_size, hipMemcpyHostToDevice);
|
||||
hipLaunchKernelGGL(HIP_KERNEL_NAME(AddKernel<float16>),
|
||||
dim3(1),
|
||||
dim3(PADDLE_CUDA_NUM_THREADS),
|
||||
0,
|
||||
0,
|
||||
d_in1,
|
||||
d_in2,
|
||||
num / 2);
|
||||
hipDeviceSynchronize();
|
||||
hipMemcpy(out, d_in2, array_size, hipMemcpyDeviceToHost);
|
||||
hipDeviceSynchronize();
|
||||
#else
|
||||
cudaMemcpy(d_in1, r_in1, array_size, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in2, r_in2, array_size, cudaMemcpyHostToDevice);
|
||||
AddKernel<float16><<<1, PADDLE_CUDA_NUM_THREADS>>>(d_in1, d_in2, num / 2);
|
||||
cudaDeviceSynchronize();
|
||||
cudaMemcpy(out, d_in2, array_size, cudaMemcpyDeviceToHost);
|
||||
cudaDeviceSynchronize();
|
||||
#endif
|
||||
for (size_t i = 0; i < num / 2; ++i) {
|
||||
// NOTE(dzhwinter): the float16 add has small truncate error.
|
||||
// so we use EXPECT_NEAR to check the result.
|
||||
EXPECT_NEAR(static_cast<float>(out[i]),
|
||||
static_cast<float>(AddFunctor<float16>()(r_in1[i], r_in2[i])),
|
||||
0.001);
|
||||
}
|
||||
free(in1);
|
||||
free(in2);
|
||||
free(out);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipFree(d_in1);
|
||||
hipFree(d_in2);
|
||||
#else
|
||||
cudaFree(d_in1);
|
||||
cudaFree(d_in2);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(CudaAtomic, float16Unalign) {
|
||||
// same with float16 testcase
|
||||
TestUnalign(static_cast<size_t>(2), /*shift_bit*/ 2);
|
||||
TestUnalign(static_cast<size_t>(1024), /*shift_bit*/ 2);
|
||||
TestUnalign(static_cast<size_t>(1024 * 1024), /*shift_bit*/ 2);
|
||||
|
||||
// shift the address.
|
||||
TestUnalign(static_cast<size_t>(2), /*shift_bit*/ 1);
|
||||
TestUnalign(static_cast<size_t>(1024), /*shift_bit*/ 1);
|
||||
TestUnalign(static_cast<size_t>(1024 * 1024), /*shift_bit*/ 1);
|
||||
|
||||
TestUnalign(static_cast<size_t>(2), /*shift_bit*/ 3);
|
||||
TestUnalign(static_cast<size_t>(1024), /*shift_bit*/ 3);
|
||||
TestUnalign(static_cast<size_t>(1024 * 1024), /*shift_bit*/ 3);
|
||||
}
|
||||
|
||||
// https://devblogs.nvidia.com/faster-parallel-reductions-kepler/
|
||||
template <typename T>
|
||||
static __forceinline__ __device__ T WarpReduceSum(T val) {
|
||||
unsigned mask = 0u;
|
||||
CREATE_SHFL_MASK(mask, true);
|
||||
for (int offset = warpSize / 2; offset > 0; offset /= 2) {
|
||||
val += phi::backends::gpu::CudaShuffleDownSync(mask, val, offset);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__forceinline__ __device__ T BlockReduce(T val) {
|
||||
static __shared__ T shared[32]; // Shared mem for 32 partial sums
|
||||
int lane = threadIdx.x % warpSize;
|
||||
int wid = threadIdx.x / warpSize;
|
||||
|
||||
val = WarpReduceSum(val); // Each warp performs partial reduction
|
||||
|
||||
if (lane == 0) shared[wid] = val; // Write reduced value to shared memory
|
||||
|
||||
__syncthreads(); // Wait for all partial reductions
|
||||
|
||||
// read from shared memory only if that warp existed
|
||||
val =
|
||||
(threadIdx.x < blockDim.x / warpSize) ? shared[lane] : static_cast<T>(0);
|
||||
|
||||
if (wid == 0) val = WarpReduceSum(val); // Final reduce within first warp
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void DeviceReduceSum(T* in, T* out, size_t N) {
|
||||
T sum(0);
|
||||
CUDA_KERNEL_LOOP(i, N) { sum += in[i]; }
|
||||
sum = BlockReduce<T>(sum);
|
||||
__syncthreads();
|
||||
if (threadIdx.x == 0) out[blockIdx.x] = sum;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestReduce(size_t num, float atol = 0.01) {
|
||||
T* in1;
|
||||
T *d_in1, *d_in2;
|
||||
size_t size = sizeof(T) * num;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
hipMalloc(reinterpret_cast<void**>(&d_in2), sizeof(T));
|
||||
#else
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in1), size);
|
||||
cudaMalloc(reinterpret_cast<void**>(&d_in2), sizeof(T));
|
||||
#endif
|
||||
in1 = reinterpret_cast<T*>(malloc(size));
|
||||
std::minstd_rand engine;
|
||||
std::uniform_real_distribution<double> dist(0.0, 1.0);
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
in1[i] = static_cast<T>(dist(engine));
|
||||
}
|
||||
auto out = std::accumulate(in1, in1 + num, static_cast<T>(0));
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMemcpy(d_in1, in1, size, hipMemcpyHostToDevice);
|
||||
hipDeviceSynchronize();
|
||||
hipLaunchKernelGGL(HIP_KERNEL_NAME(DeviceReduceSum<T>),
|
||||
dim3(1),
|
||||
dim3(PADDLE_CUDA_NUM_THREADS),
|
||||
0,
|
||||
0,
|
||||
d_in1,
|
||||
d_in2,
|
||||
num);
|
||||
hipMemcpy(in1, d_in2, sizeof(T), hipMemcpyDeviceToHost);
|
||||
hipDeviceSynchronize();
|
||||
#else
|
||||
cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice);
|
||||
cudaDeviceSynchronize();
|
||||
DeviceReduceSum<T><<<1, PADDLE_CUDA_NUM_THREADS>>>(d_in1, d_in2, num);
|
||||
cudaMemcpy(in1, d_in2, sizeof(T), cudaMemcpyDeviceToHost);
|
||||
cudaDeviceSynchronize();
|
||||
#endif
|
||||
// NOTE(dzhwinter): the float16 add has small underflow/overflow
|
||||
// so we use EXPECT_NEAR to check the result.
|
||||
EXPECT_NEAR(static_cast<float>(in1[0]), static_cast<float>(out), atol);
|
||||
free(in1);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipFree(d_in1);
|
||||
hipFree(d_in2);
|
||||
#else
|
||||
cudaFree(d_in1);
|
||||
cudaFree(d_in2);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(CudaShuffleSync, float16) {
|
||||
TestReduce<float>(10);
|
||||
TestReduce<float>(1000);
|
||||
|
||||
// float16 will overflow or accumulate truncate errors in big size.
|
||||
TestReduce<float16>(10);
|
||||
TestReduce<float16>(100, /*atol error*/ 1.0);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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 <gtest/gtest.h>
|
||||
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_dnn.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace platform {
|
||||
|
||||
TEST(TensorDescriptor, Empty) {
|
||||
phi::backends::gpu::ActivationDescriptor a;
|
||||
phi::backends::gpu::TensorDescriptor t;
|
||||
phi::backends::gpu::TensorDescriptor t1;
|
||||
phi::backends::gpu::TensorDescriptor *t11 =
|
||||
new phi::backends::gpu::TensorDescriptor();
|
||||
delete t11;
|
||||
std::unique_ptr<phi::backends::gpu::TensorDescriptor> tt(
|
||||
new phi::backends::gpu::TensorDescriptor());
|
||||
}
|
||||
|
||||
TEST(TensorDescriptor, Normal) {
|
||||
phi::DenseTensor tt;
|
||||
tt.Resize({2, 3, 4});
|
||||
tt.mutable_data<float>(phi::CPUPlace());
|
||||
|
||||
phi::backends::gpu::TensorDescriptor desc;
|
||||
desc.set(tt);
|
||||
EXPECT_TRUE(desc.desc() != nullptr);
|
||||
}
|
||||
|
||||
} // namespace platform
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,4 @@
|
||||
hip_test(
|
||||
miopen_helper_test
|
||||
SRCS miopen_helper_test.cc
|
||||
DEPS phi common)
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2020 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. */
|
||||
|
||||
#define GOOGLE_GLOG_DLL_DECL
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_dnn.h"
|
||||
|
||||
TEST(MIOpenHelper, ScopedTensorDescriptor) {
|
||||
using phi::DataLayout;
|
||||
using phi::backends::gpu::ScopedTensorDescriptor;
|
||||
|
||||
ScopedTensorDescriptor tensor_desc;
|
||||
std::vector<int> shape = {2, 4, 6, 6};
|
||||
auto desc = tensor_desc.descriptor<float>(DataLayout::NCHW, shape);
|
||||
|
||||
miopenDataType_t type;
|
||||
int nd;
|
||||
std::vector<int> dims(4);
|
||||
std::vector<int> strides(4);
|
||||
phi::dynload::miopenGetTensorDescriptor(
|
||||
desc, &type, dims.data(), strides.data());
|
||||
phi::dynload::miopenGetTensorDescriptorSize(desc, &nd);
|
||||
|
||||
EXPECT_EQ(nd, 4);
|
||||
for (size_t i = 0; i < dims.size(); ++i) {
|
||||
EXPECT_EQ(dims[i], shape[i]);
|
||||
}
|
||||
EXPECT_EQ(strides[3], 1);
|
||||
EXPECT_EQ(strides[2], 6);
|
||||
EXPECT_EQ(strides[1], 36);
|
||||
EXPECT_EQ(strides[0], 144);
|
||||
|
||||
// test tensor5d: ScopedTensorDescriptor
|
||||
ScopedTensorDescriptor tensor5d_desc;
|
||||
std::vector<int> shape_5d = {2, 4, 6, 6, 6};
|
||||
auto desc_5d = tensor5d_desc.descriptor<float>(DataLayout::NCDHW, shape_5d);
|
||||
|
||||
std::vector<int> dims_5d(5);
|
||||
std::vector<int> strides_5d(5);
|
||||
phi::dynload::miopenGetTensorDescriptor(
|
||||
desc_5d, &type, dims_5d.data(), strides_5d.data());
|
||||
phi::dynload::miopenGetTensorDescriptorSize(desc_5d, &nd);
|
||||
|
||||
EXPECT_EQ(nd, 5);
|
||||
for (size_t i = 0; i < dims_5d.size(); ++i) {
|
||||
EXPECT_EQ(dims_5d[i], shape_5d[i]);
|
||||
}
|
||||
EXPECT_EQ(strides_5d[4], 1);
|
||||
EXPECT_EQ(strides_5d[3], 6);
|
||||
EXPECT_EQ(strides_5d[2], 36);
|
||||
EXPECT_EQ(strides_5d[1], 216);
|
||||
EXPECT_EQ(strides_5d[0], 864);
|
||||
}
|
||||
|
||||
TEST(MIOpenHelper, ScopedConvolutionDescriptor) {
|
||||
using phi::backends::gpu::ScopedConvolutionDescriptor;
|
||||
|
||||
ScopedConvolutionDescriptor conv_desc;
|
||||
std::vector<int> src_pads = {2, 2, 2};
|
||||
std::vector<int> src_strides = {1, 1, 1};
|
||||
std::vector<int> src_dilations = {1, 1, 1};
|
||||
auto desc = conv_desc.descriptor<float>(src_pads, src_strides, src_dilations);
|
||||
|
||||
miopenConvolutionMode_t mode;
|
||||
int nd;
|
||||
std::vector<int> pads(3);
|
||||
std::vector<int> strides(3);
|
||||
std::vector<int> dilations(3);
|
||||
phi::dynload::miopenGetConvolutionNdDescriptor(
|
||||
desc, 3, &nd, pads.data(), strides.data(), dilations.data(), &mode);
|
||||
|
||||
EXPECT_EQ(nd, 3);
|
||||
for (size_t i = 0; i < src_pads.size(); ++i) {
|
||||
EXPECT_EQ(pads[i], src_pads[i]);
|
||||
EXPECT_EQ(strides[i], src_strides[i]);
|
||||
EXPECT_EQ(dilations[i], src_dilations[i]);
|
||||
}
|
||||
EXPECT_EQ(mode, miopenConvolution);
|
||||
}
|
||||
Reference in New Issue
Block a user