1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
10 #define EIGEN_TEST_NO_LONGDOUBLE
11 #define EIGEN_TEST_FUNC cxx11_tensor_complex
12 #define EIGEN_USE_GPU
13
14 #if defined __CUDACC_VER__ && __CUDACC_VER__ >= 70500
15 #include <cuda_fp16.h>
16 #endif
17 #include "main.h"
18 #include <unsupported/Eigen/CXX11/Tensor>
19
20 using Eigen::Tensor;
21
test_cuda_nullary()22 void test_cuda_nullary() {
23 Tensor<std::complex<float>, 1, 0, int> in1(2);
24 Tensor<std::complex<float>, 1, 0, int> in2(2);
25 in1.setRandom();
26 in2.setRandom();
27
28 std::size_t float_bytes = in1.size() * sizeof(float);
29 std::size_t complex_bytes = in1.size() * sizeof(std::complex<float>);
30
31 std::complex<float>* d_in1;
32 std::complex<float>* d_in2;
33 float* d_out2;
34 cudaMalloc((void**)(&d_in1), complex_bytes);
35 cudaMalloc((void**)(&d_in2), complex_bytes);
36 cudaMalloc((void**)(&d_out2), float_bytes);
37 cudaMemcpy(d_in1, in1.data(), complex_bytes, cudaMemcpyHostToDevice);
38 cudaMemcpy(d_in2, in2.data(), complex_bytes, cudaMemcpyHostToDevice);
39
40 Eigen::CudaStreamDevice stream;
41 Eigen::GpuDevice gpu_device(&stream);
42
43 Eigen::TensorMap<Eigen::Tensor<std::complex<float>, 1, 0, int>, Eigen::Aligned> gpu_in1(
44 d_in1, 2);
45 Eigen::TensorMap<Eigen::Tensor<std::complex<float>, 1, 0, int>, Eigen::Aligned> gpu_in2(
46 d_in2, 2);
47 Eigen::TensorMap<Eigen::Tensor<float, 1, 0, int>, Eigen::Aligned> gpu_out2(
48 d_out2, 2);
49
50 gpu_in1.device(gpu_device) = gpu_in1.constant(std::complex<float>(3.14f, 2.7f));
51 gpu_out2.device(gpu_device) = gpu_in2.abs();
52
53 Tensor<std::complex<float>, 1, 0, int> new1(2);
54 Tensor<float, 1, 0, int> new2(2);
55
56 assert(cudaMemcpyAsync(new1.data(), d_in1, complex_bytes, cudaMemcpyDeviceToHost,
57 gpu_device.stream()) == cudaSuccess);
58 assert(cudaMemcpyAsync(new2.data(), d_out2, float_bytes, cudaMemcpyDeviceToHost,
59 gpu_device.stream()) == cudaSuccess);
60
61 assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
62
63 for (int i = 0; i < 2; ++i) {
64 VERIFY_IS_APPROX(new1(i), std::complex<float>(3.14f, 2.7f));
65 VERIFY_IS_APPROX(new2(i), std::abs(in2(i)));
66 }
67
68 cudaFree(d_in1);
69 cudaFree(d_in2);
70 cudaFree(d_out2);
71 }
72
73
test_cuda_sum_reductions()74 static void test_cuda_sum_reductions() {
75
76 Eigen::CudaStreamDevice stream;
77 Eigen::GpuDevice gpu_device(&stream);
78
79 const int num_rows = internal::random<int>(1024, 5*1024);
80 const int num_cols = internal::random<int>(1024, 5*1024);
81
82 Tensor<std::complex<float>, 2> in(num_rows, num_cols);
83 in.setRandom();
84
85 Tensor<std::complex<float>, 0> full_redux;
86 full_redux = in.sum();
87
88 std::size_t in_bytes = in.size() * sizeof(std::complex<float>);
89 std::size_t out_bytes = full_redux.size() * sizeof(std::complex<float>);
90 std::complex<float>* gpu_in_ptr = static_cast<std::complex<float>*>(gpu_device.allocate(in_bytes));
91 std::complex<float>* gpu_out_ptr = static_cast<std::complex<float>*>(gpu_device.allocate(out_bytes));
92 gpu_device.memcpyHostToDevice(gpu_in_ptr, in.data(), in_bytes);
93
94 TensorMap<Tensor<std::complex<float>, 2> > in_gpu(gpu_in_ptr, num_rows, num_cols);
95 TensorMap<Tensor<std::complex<float>, 0> > out_gpu(gpu_out_ptr);
96
97 out_gpu.device(gpu_device) = in_gpu.sum();
98
99 Tensor<std::complex<float>, 0> full_redux_gpu;
100 gpu_device.memcpyDeviceToHost(full_redux_gpu.data(), gpu_out_ptr, out_bytes);
101 gpu_device.synchronize();
102
103 // Check that the CPU and GPU reductions return the same result.
104 VERIFY_IS_APPROX(full_redux(), full_redux_gpu());
105
106 gpu_device.deallocate(gpu_in_ptr);
107 gpu_device.deallocate(gpu_out_ptr);
108 }
109
110
test_cuda_product_reductions()111 static void test_cuda_product_reductions() {
112
113 Eigen::CudaStreamDevice stream;
114 Eigen::GpuDevice gpu_device(&stream);
115
116 const int num_rows = internal::random<int>(1024, 5*1024);
117 const int num_cols = internal::random<int>(1024, 5*1024);
118
119 Tensor<std::complex<float>, 2> in(num_rows, num_cols);
120 in.setRandom();
121
122 Tensor<std::complex<float>, 0> full_redux;
123 full_redux = in.prod();
124
125 std::size_t in_bytes = in.size() * sizeof(std::complex<float>);
126 std::size_t out_bytes = full_redux.size() * sizeof(std::complex<float>);
127 std::complex<float>* gpu_in_ptr = static_cast<std::complex<float>*>(gpu_device.allocate(in_bytes));
128 std::complex<float>* gpu_out_ptr = static_cast<std::complex<float>*>(gpu_device.allocate(out_bytes));
129 gpu_device.memcpyHostToDevice(gpu_in_ptr, in.data(), in_bytes);
130
131 TensorMap<Tensor<std::complex<float>, 2> > in_gpu(gpu_in_ptr, num_rows, num_cols);
132 TensorMap<Tensor<std::complex<float>, 0> > out_gpu(gpu_out_ptr);
133
134 out_gpu.device(gpu_device) = in_gpu.prod();
135
136 Tensor<std::complex<float>, 0> full_redux_gpu;
137 gpu_device.memcpyDeviceToHost(full_redux_gpu.data(), gpu_out_ptr, out_bytes);
138 gpu_device.synchronize();
139
140 // Check that the CPU and GPU reductions return the same result.
141 VERIFY_IS_APPROX(full_redux(), full_redux_gpu());
142
143 gpu_device.deallocate(gpu_in_ptr);
144 gpu_device.deallocate(gpu_out_ptr);
145 }
146
147
test_cxx11_tensor_complex()148 void test_cxx11_tensor_complex()
149 {
150 CALL_SUBTEST(test_cuda_nullary());
151 CALL_SUBTEST(test_cuda_sum_reductions());
152 CALL_SUBTEST(test_cuda_product_reductions());
153 }
154