Skip to content

Commit dca6722

Browse files
committed
- Fix thrust::complex<T> to always be aligned to sizeof(T) * 2.
- Add unit tests for `thrust::complex<T>` alignment. - Fix a harmless typo in a macro name in `<thrust/detail/alignment.h>`. - Add a `DECLARE_UNITTEST_WITH_NAME` helper macro to the unit test framework. - Make the test framework emit a diagnostic if a device is skipped because device code was not compiled for the device's architecture. Bug 2509847
1 parent 70e6031 commit dca6722

6 files changed

Lines changed: 194 additions & 45 deletions

File tree

testing/complex.cu

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@
1111
and takes a lot of time to run.
1212
*/
1313

14+
template<typename T>
15+
struct TestComplexSizeAndAlignment
16+
{
17+
void operator()()
18+
{
19+
THRUST_STATIC_ASSERT(
20+
sizeof(thrust::complex<T>) == sizeof(T) * 2
21+
);
22+
THRUST_STATIC_ASSERT(
23+
THRUST_ALIGNOF(thrust::complex<T>) == THRUST_ALIGNOF(T) * 2
24+
);
25+
26+
THRUST_STATIC_ASSERT(
27+
sizeof(thrust::complex<T const>) == sizeof(T) * 2
28+
);
29+
THRUST_STATIC_ASSERT(
30+
THRUST_ALIGNOF(thrust::complex<T const>) == THRUST_ALIGNOF(T) * 2
31+
);
32+
}
33+
};
34+
SimpleUnitTest<TestComplexSizeAndAlignment, FloatingPointTypes> TestComplexSizeAndAlignmentInstance;
35+
1436
template<typename T>
1537
struct TestComplexConstructors
1638
{
@@ -282,7 +304,6 @@ struct TestComplexStreamOperators
282304
ASSERT_ALMOST_EQUAL(a,b);
283305
}
284306
};
285-
286307
SimpleUnitTest<TestComplexStreamOperators, FloatingPointTypes> TestComplexStreamOperatorsInstance;
287308

288309
#if THRUST_CPP_DIALECT >= 2011
@@ -308,3 +329,4 @@ struct TestComplexStdComplexDeviceInterop
308329
};
309330
SimpleUnitTest<TestComplexStdComplexDeviceInterop, FloatingPointTypes> TestComplexStdComplexDeviceInteropInstance;
310331
#endif
332+

testing/cuda/complex.cu

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <unittest/unittest.h>
2+
3+
#include <thrust/complex.h>
4+
#include <thrust/detail/preprocessor.h>
5+
#include <thrust/detail/alignment.h>
6+
7+
#include <cuda_fp16.h>
8+
9+
template <typename T, typename VectorT>
10+
void TestComplexAlignment()
11+
{
12+
THRUST_STATIC_ASSERT(
13+
sizeof(thrust::complex<T>) == sizeof(VectorT)
14+
);
15+
THRUST_STATIC_ASSERT(
16+
THRUST_ALIGNOF(thrust::complex<T>) == THRUST_ALIGNOF(VectorT)
17+
);
18+
19+
THRUST_STATIC_ASSERT(
20+
sizeof(thrust::complex<T const>) == sizeof(VectorT)
21+
);
22+
THRUST_STATIC_ASSERT(
23+
THRUST_ALIGNOF(thrust::complex<T const>) == THRUST_ALIGNOF(VectorT)
24+
);
25+
}
26+
DECLARE_UNITTEST_WITH_NAME(
27+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<char, char2>)
28+
, TestComplexCharAlignment
29+
);
30+
DECLARE_UNITTEST_WITH_NAME(
31+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<short, short2>)
32+
, TestComplexShortAlignment
33+
);
34+
DECLARE_UNITTEST_WITH_NAME(
35+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<int, int2>)
36+
, TestComplexIntAlignment
37+
);
38+
DECLARE_UNITTEST_WITH_NAME(
39+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<long, long2>)
40+
, TestComplexLongAlignment
41+
);
42+
DECLARE_UNITTEST_WITH_NAME(
43+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<__half, __half2>)
44+
, TestComplexHalfAlignment
45+
);
46+
DECLARE_UNITTEST_WITH_NAME(
47+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<float, float2>)
48+
, TestComplexFloatAlignment
49+
);
50+
DECLARE_UNITTEST_WITH_NAME(
51+
THRUST_PP_EXPAND_ARGS(TestComplexAlignment<double, double2>)
52+
, TestComplexDoubleAlignment
53+
);

testing/unittest/cuda/testframework.cu

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ bool binary_exists_for_current_device()
1212
// we didn't compile a binary compatible with the current device
1313
cudaFuncAttributes attr;
1414
cudaError_t error = cudaFuncGetAttributes(&attr, dummy_kernel);
15-
return error == cudaSuccess;
15+
16+
// clear the CUDA global error state if we just set it, so that
17+
// check_cuda_error doesn't complain
18+
if (cudaSuccess != error) (void)cudaGetLastError();
19+
20+
return cudaSuccess == error;
1621
}
1722

1823
void list_devices(void)
@@ -159,13 +164,17 @@ bool CUDATestDriver::run_tests(const ArgumentSet &args, const ArgumentMap &kwarg
159164
// set the device
160165
cudaSetDevice(*device);
161166

162-
cudaDeviceSynchronize();
163-
164167
// check if a binary exists for this device
165168
// if none exists, skip the device silently unless this is the only one we're targeting
166169
if(devices.size() > 1 && !binary_exists_for_current_device())
167170
{
168-
continue;
171+
// note which device we're skipping
172+
cudaDeviceProp deviceProp;
173+
cudaGetDeviceProperties(&deviceProp, *device);
174+
175+
std::cout << "Skipping Device " << *device << ": \"" << deviceProp.name << "\"" << std::endl;
176+
177+
continue;
169178
}
170179

171180
if(!concise)

testing/unittest/testframework.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,16 @@ class TEST##UnitTest : public UnitTest { \
351351
}; \
352352
TEST##UnitTest TEST##Instance
353353

354+
#define DECLARE_UNITTEST_WITH_NAME(TEST, NAME) \
355+
class NAME##UnitTest : public UnitTest { \
356+
public: \
357+
NAME##UnitTest() : UnitTest(#NAME) {} \
358+
void run(){ \
359+
TEST(); \
360+
} \
361+
}; \
362+
NAME##UnitTest NAME##Instance
363+
354364
// Macro to create host and device versions of a
355365
// unit test for a bunch of data types
356366
#define DECLARE_VECTOR_UNITTEST(VTEST) \

thrust/complex.h

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,80 @@ namespace thrust
6363
* \{
6464
*/
6565

66+
namespace detail
67+
{
68+
69+
template <typename T, std::size_t Align>
70+
struct complex_storage;
71+
72+
#if __cplusplus >= 201103L \
73+
&& (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_GCC) \
74+
&& (THRUST_GCC_VERSION >= 40800)
75+
// C++11 implementation, excluding GCC 4.7, which doesn't have `alignas`.
76+
template <typename T, std::size_t Align>
77+
struct complex_storage
78+
{
79+
struct alignas(Align) type { T x; T y; };
80+
};
81+
#elif (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_MSVC) \
82+
|| ( (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_GCC) \
83+
&& (THRUST_GCC_VERSION < 40300))
84+
// C++03 implementation for MSVC and GCC <= 4.2.
85+
//
86+
// We have to implement `aligned_type` with specializations for MSVC
87+
// and GCC 4.2 and older because they require literals as arguments to
88+
// their alignment attribute.
89+
90+
#if (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_MSVC)
91+
// MSVC implementation.
92+
#define THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(X) \
93+
template <typename T> \
94+
struct complex_storage<T, X> \
95+
{ \
96+
__declspec(align(X)) struct type { T x; T y; }; \
97+
}; \
98+
/**/
99+
#else
100+
// GCC <= 4.2 implementation.
101+
#define THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(X) \
102+
template <typename T> \
103+
struct complex_storage<T, X> \
104+
{ \
105+
struct type { T x; T y; } __attribute__((aligned(X))); \
106+
}; \
107+
/**/
108+
#endif
109+
110+
// The primary template is a fallback, which doesn't specify any alignment.
111+
// It's only used when T is very large and we're using an older compilers
112+
// which we have to fully specialize each alignment case.
113+
template <typename T, std::size_t Align>
114+
struct complex_storage
115+
{
116+
T x; T y;
117+
};
118+
119+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(1);
120+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(2);
121+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(4);
122+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(8);
123+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(16);
124+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(32);
125+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(64);
126+
THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION(128);
127+
128+
#undef THRUST_DEFINE_COMPLEX_STORAGE_SPECIALIZATION
129+
#else
130+
// C++03 implementation for GCC > 4.2, Clang, PGI, ICPC, and xlC.
131+
template <typename T, std::size_t Align>
132+
struct complex_storage
133+
{
134+
struct type { T x; T y; } __attribute__((aligned(Align)));
135+
};
136+
#endif
137+
138+
} // end namespace detail
139+
66140
/*! \p complex is the Thrust equivalent to <tt>std::complex</tt>. It is
67141
* functionally identical to it, but can also be used in device code which
68142
* <tt>std::complex</tt> currently cannot.
@@ -377,31 +451,7 @@ struct complex
377451
operator std::complex<T>() const { return std::complex<T>(real(), imag()); }
378452

379453
private:
380-
/*! \cond
381-
*/
382-
struct generic_storage_type { T x; T y; };
383-
/*! \endcond
384-
*/
385-
386-
#if THRUST_DEVICE_COMPILER == THRUST_DEVICE_COMPILER_NVCC
387-
typedef typename detail::conditional<
388-
detail::is_same<T, float>::value, float2,
389-
typename detail::conditional<
390-
detail::is_same<T, float const>::value, float2 const,
391-
typename detail::conditional<
392-
detail::is_same<T, double>::value, double2,
393-
typename detail::conditional<
394-
detail::is_same<T, double const>::value, double2 const,
395-
generic_storage_type
396-
>::type
397-
>::type
398-
>::type
399-
>::type storage_type;
400-
#else
401-
typedef generic_storage_type storage_type;
402-
#endif
403-
404-
storage_type data;
454+
typename detail::complex_storage<T, sizeof(T) * 2>::type data;
405455
};
406456

407457

thrust/detail/alignment.h

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ struct aligned_type;
100100
#if __cplusplus >= 201103L \
101101
&& (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_GCC) \
102102
&& (THRUST_GCC_VERSION >= 40800)
103-
// GCC 4.7 doesn't have `alignas`.
103+
// C++11 implementation, excluding GCC 4.7, which doesn't have `alignas`.
104104
template <std::size_t Align>
105105
struct aligned_type
106106
{
@@ -109,39 +109,44 @@ struct aligned_type;
109109
#elif (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_MSVC) \
110110
|| ( (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_GCC) \
111111
&& (THRUST_GCC_VERSION < 40300))
112+
// C++03 implementation for MSVC and GCC <= 4.2.
113+
//
112114
// We have to implement `aligned_type` with specializations for MSVC
113115
// and GCC 4.2.x and older because they require literals as arguments to
114116
// their alignment attribute.
115117

116118
#if (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_MSVC)
117-
#define THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(X) \
119+
// MSVC implementation.
120+
#define THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(X) \
118121
template <> \
119-
struct aligned_type<X> \
122+
struct aligned_type<X> \
120123
{ \
121124
__declspec(align(X)) struct type {}; \
122125
}; \
123126
/**/
124127
#else
125-
#define THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(X) \
128+
// GCC <= 4.2 implementation.
129+
#define THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(X) \
126130
template <> \
127-
struct aligned_type<X> \
131+
struct aligned_type<X> \
128132
{ \
129133
struct type {} __attribute__((aligned(X))); \
130134
}; \
131135
/**/
132136
#endif
133137

134-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(1);
135-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(2);
136-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(4);
137-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(8);
138-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(16);
139-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(32);
140-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(64);
141-
THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION(128);
142-
143-
#undef THRUST_DEFINE_ALIGNED_BYTE_SPECIALIZATION
138+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(1);
139+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(2);
140+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(4);
141+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(8);
142+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(16);
143+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(32);
144+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(64);
145+
THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION(128);
146+
147+
#undef THRUST_DEFINE_ALIGNED_TYPE_SPECIALIZATION
144148
#else
149+
// C++03 implementation for GCC > 4.2, Clang, PGI, ICPC, and xlC.
145150
template <std::size_t Align>
146151
struct aligned_type
147152
{

0 commit comments

Comments
 (0)