SWDEV-503089 - Fix and enable disabled HIP tests from math group (#1319)

* SWDEV-503089 - Fix and enable disabled HIP tests from math group

* SWDEV-503089 - Move single precision reduced run to a common function
This commit is contained in:
amilanov-amd
2025-11-26 10:34:05 +01:00
committed by GitHub
parent ee48f6221d
commit da9bb4efae
28 changed files with 313 additions and 575 deletions
@@ -35,7 +35,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T>) { \
ys[i] = func_name##f(x1s[i], x2s[i]); \
} else if constexpr (std::is_same_v<double, T>) { \
@@ -31,7 +31,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(xs[i]); \
} \
}
@@ -42,7 +42,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i]); \
} \
}
@@ -93,7 +93,10 @@ void CastUnaryHalfPrecisionBruteForceTest(kernel_sig<T, Float16> kernel,
ref_sig<RT, RTArg> ref_func,
const ValidatorBuilder& validator_builder) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
uint64_t stop = std::numeric_limits<uint16_t>::max() + 1ul;
const auto reduction_factor = GetTestReductionFactor();
const auto inv_reduction_factor = 1 / reduction_factor;
const auto stop = static_cast<uint64_t>(
std::ceil((std::numeric_limits<uint16_t>::max() + 1ul) * reduction_factor));
const auto max_batch_size =
std::min(GetMaxAllowedDeviceMemoryUsage() / (sizeof(Float16) + sizeof(T)), stop);
LinearAllocGuard<Float16> values{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(Float16)};
@@ -114,10 +117,11 @@ void CastUnaryHalfPrecisionBruteForceTest(kernel_sig<T, Float16> kernel,
const auto sub_batch_size = min_sub_batch_size + (i < tail);
thread_pool.Post([=, &values] {
auto t = v;
auto t = v * inv_reduction_factor;
uint16_t val;
for (auto j = 0u; j < sub_batch_size; ++j) {
val = static_cast<uint16_t>(t++);
val = static_cast<uint16_t>(std::floor(t));
t += inv_reduction_factor;
values.ptr()[base_idx + j] = *reinterpret_cast<Float16*>(&val);
if (std::isnan(values.ptr()[base_idx + j]) || std::isinf(values.ptr()[base_idx + j])) {
values.ptr()[base_idx + j] = 0;
@@ -178,15 +182,24 @@ void CastIntRangeTest(kernel_sig<T, TArg> kernel, ref_sig<RT, RTArg> ref_func,
const TArg a = std::numeric_limits<TArg>::lowest(),
const TArg b = std::numeric_limits<TArg>::max()) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
const auto reduction_factor = GetTestReductionFactor();
const auto inv_reduction_factor = 1 / reduction_factor;
const auto max_batch_size = GetMaxAllowedDeviceMemoryUsage() / (sizeof(T) + sizeof(TArg));
LinearAllocGuard<TArg> values{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(TArg)};
MathTest math_test(kernel, max_batch_size);
bool running = true;
size_t inserted = 0u;
for (TArg v = a; v <= b; v++) {
values.ptr()[inserted++] = v;
if (inserted < max_batch_size) continue;
auto v = static_cast<double>(a);
while (running) {
if (std::floor(v) > b) {
running = false;
} else {
values.ptr()[inserted++] = static_cast<TArg>(std::floor(v));
v += inv_reduction_factor;
if (inserted < max_batch_size) continue;
}
math_test.Run(validator_builder, grid_size, block_size, ref_func, inserted, values.ptr());
inserted = 0u;
@@ -240,17 +253,27 @@ void CastBinaryIntRangeTest(kernel_sig<T1, T2, T2> kernel, ref_sig<T1, T2, T2> r
const T2 a = std::numeric_limits<T2>::lowest(),
const T2 b = std::numeric_limits<T2>::max()) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
const auto reduction_factor = GetTestReductionFactor();
const auto inv_reduction_factor = 1 / reduction_factor;
const auto max_batch_size = GetMaxAllowedDeviceMemoryUsage() / (sizeof(T1) + 2 * sizeof(T2));
LinearAllocGuard<T2> values1{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(T2)};
LinearAllocGuard<T2> values2{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(T2)};
MathTest math_test(kernel, max_batch_size);
bool running = true;
size_t inserted = 0u;
for (T2 v = a; v <= b; v++) {
values1.ptr()[inserted] = v;
values2.ptr()[inserted++] = b - v;
if (inserted < max_batch_size) continue;
auto v = static_cast<double>(a);
while (running) {
if (std::floor(v) > b) {
running = false;
} else {
const auto t = static_cast<T2>(std::floor(v));
values1.ptr()[inserted] = t;
values2.ptr()[inserted++] = b - t;
v += inv_reduction_factor;
if (inserted < max_batch_size) continue;
}
math_test.Run(validator_builder, grid_size, block_size, ref_func, inserted, values1.ptr(),
values2.ptr());
@@ -31,7 +31,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(__half2{xs[i], -xs[i]}); \
} \
}
@@ -42,7 +42,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(__half2{x1s[i], -x1s[i]}, __half2{x2s[i], -x2s[i]}); \
} \
}
@@ -318,7 +318,7 @@ __global__ void __float22half2_rn_kernel(__half2* const ys, const size_t num_xs,
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
ys[i] = __float22half2_rn(make_float2(xs[i], -xs[i]));
}
}
@@ -36,7 +36,7 @@ THE SOFTWARE.
TEST_CASE("Unit_Device_" #kern_name "_Accuracy_Limited_Positive") { \
Float16 (*ref)(float) = kern_name##_ref; \
UnarySinglePrecisionRangeTest(kern_name##_kernel, ref, EqValidatorBuilderFactory<Float16>(), \
std::numeric_limits<float>::min(), 0.f); \
std::numeric_limits<float>::lowest(), 0.f); \
UnarySinglePrecisionRangeTest(kern_name##_kernel, ref, EqValidatorBuilderFactory<Float16>(), \
0.0001f, std::numeric_limits<float>::max()); \
}
@@ -48,7 +48,7 @@ THE SOFTWARE.
TEST_CASE("Unit_Device_" #kern_name "_Accuracy_Positive") { \
Float16 (*ref)(float) = kern_name##_ref; \
UnarySinglePrecisionRangeTest(kern_name##_kernel, ref, EqValidatorBuilderFactory<Float16>(), \
std::numeric_limits<float>::min(), \
std::numeric_limits<float>::lowest(), \
std::numeric_limits<float>::max()); \
}
@@ -688,7 +688,7 @@ __global__ void __hiloint2double_kernel(double* const ys, const size_t num_xs, i
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
ys[i] = __hiloint2double(x1s[i], x2s[i]);
}
}
@@ -33,7 +33,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(xs[i]); \
} \
}
@@ -100,7 +100,7 @@ MATH_UNARY_DP_TEST_DEF_IMPL(__dsqrt_rn, static_cast<double (*)(double)>(std::sqr
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i]); \
} \
}
@@ -206,7 +206,7 @@ MATH_BINARY_DP_TEST_DEF_IMPL(__ddiv_rn, __ddiv_rn_ref, EqValidatorBuilderFactory
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i], x3s[i]); \
} \
}
@@ -34,7 +34,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(xs[i]); \
} \
}
@@ -59,7 +59,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i]); \
} \
}
@@ -85,7 +85,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i], x3s[i]); \
} \
}
@@ -35,7 +35,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(xs[i]); \
} \
} \
@@ -120,7 +120,7 @@ MATH_UNARY_HP_TEST_DEF_IMPL(__hisnan2, __hisnan2_ref, EqValidatorBuilderFactory<
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i]); \
} \
} \
@@ -35,7 +35,8 @@ THE SOFTWARE.
* ------------------------
* - Tests the numerical accuracy of `logf(x)` for all possible inputs and `log(x)` against a
* table of difficult values, followed by a large number of randomly generated values. The results
* are compared against reference function `T std::log(T)`. The maximum ulp error is 1.
* are compared against reference function `T std::log(T)`. The maximum ulp error
* for single precision is 2 and for double precision is 1.
*
* Test source
* ------------------------
@@ -44,7 +45,7 @@ THE SOFTWARE.
* ------------------------
* - HIP_VERSION >= 5.2
*/
MATH_UNARY_WITHIN_ULP_STL_REF_TEST_DEF(log, 1, 1)
MATH_UNARY_WITHIN_ULP_STL_REF_TEST_DEF(log, 2, 1)
/**
* Test Description
@@ -187,7 +188,7 @@ __global__ void ilogb_kernel(int* const ys, const size_t num_xs, T* const xs) {
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
ys[i] = ilogbf(xs[i]);
} else if constexpr (std::is_same_v<double, T>) {
@@ -212,10 +212,17 @@ template <typename F> auto GetOccupancyMaxPotentialBlockSize(F kernel) {
inline size_t GetMaxAllowedDeviceMemoryUsage() {
hipDeviceProp_t props;
HIP_CHECK(hipGetDeviceProperties(&props, 0));
return props.totalGlobalMem * (cmd_options.accuracy_max_memory * 0.01f);
return props.totalGlobalMem > cmd_options.max_memory
? cmd_options.max_memory
: props.totalGlobalMem * (cmd_options.accuracy_max_memory * 0.01f);
}
inline uint64_t GetTestIterationCount() { return cmd_options.accuracy_iterations; }
inline double GetTestReductionFactor() { return cmd_options.reduction_factor * 0.01; }
inline uint64_t GetTestIterationCount() {
return static_cast<uint64_t>(
std::ceil(cmd_options.accuracy_iterations * GetTestReductionFactor()));
}
template <typename T, typename... Ts> using kernel_sig = void (*)(T*, const size_t, Ts*...);
@@ -254,3 +261,71 @@ template <int error_num> void NegativeTestRTCWrapper(const char* program_source)
HIPRTC_CHECK_ERROR(result, HIPRTC_ERROR_COMPILATION);
REQUIRE(error_count == expected_error_count);
}
inline void SinglePrecisionReducedRun(std::function<void(size_t)> run,
const LinearAllocGuard<float>& values, const float a,
const float b, const double reduction_factor,
const size_t max_batch_size) {
bool test_positive = true;
float positive_start = 0.0f;
float positive_end = 0.0f;
bool test_negative = true;
float negative_start = 0.0f;
float negative_end = 0.0f;
if (a < 0 && b <= 0) {
test_positive = false;
negative_start = -b;
negative_end = -a;
}
if (a < 0 && b > 0) {
positive_start = 0.0f;
positive_end = b;
negative_start = 0.0f;
negative_end = -a;
}
if (a >= 0 && b > 0) {
positive_start = a;
positive_end = b;
test_negative = false;
}
const auto inv_reduction_factor = 1 / reduction_factor;
size_t inserted = 0u;
constexpr int radix = std::numeric_limits<float>::radix;
float increment = std::numeric_limits<float>::min() * std::numeric_limits<float>::epsilon();
float limit = std::numeric_limits<float>::min() * radix;
const auto iterate = [&](float start, float end, int positive) {
for (float v = start; v < end; limit *= radix, increment *= radix) {
const auto start_v = v;
double count = 0ul;
while (v < limit && v < end) {
values.ptr()[inserted++] = (v * positive);
count += inv_reduction_factor;
v = start_v + increment * static_cast<uint64_t>(std::floor(count));
if (inserted < max_batch_size) continue;
run(inserted);
inserted = 0u;
}
}
if (inserted > 0u) {
run(inserted);
inserted = 0u;
}
};
if (test_positive) {
iterate(positive_start, positive_end, 1);
}
increment = std::numeric_limits<float>::min() * std::numeric_limits<float>::epsilon();
limit = std::numeric_limits<float>::min() * radix;
if (test_negative) {
iterate(negative_start, negative_end, -1);
}
}
@@ -37,12 +37,12 @@ TEST_CASE("Unit_Device_fmax_fmaxf_Negative_RTC") { NegativeTestRTCWrapper<8>(kFm
MATH_BINARY_WITHIN_ULP_TEST_DEF(fmin, std::fmin, 0, 0)
TEST_CASE("Unit_Device_fmin_fminf_Negative_RTC") { NegativeTestRTCWrapper<8>(kFmin); }
MATH_BINARY_WITHIN_ULP_TEST_DEF(nextafter, std::nextafter, 0, 0)
MATH_BINARY_WITHIN_ULP_TEST_DEF(nextafter, std::nextafter, 1, 1)
TEST_CASE("Unit_Device_nextafter_nextafterf_Negative_RTC") {
NegativeTestRTCWrapper<8>(kNextAfter);
}
MATH_TERNARY_WITHIN_ULP_TEST_DEF(fma, std::fma, 0, 0)
MATH_TERNARY_WITHIN_ULP_TEST_DEF(fma, std::fma, 0, 1)
TEST_CASE("Unit_Device_fma_fmaf_Negative_RTC") { NegativeTestRTCWrapper<12>(kFma); }
__global__ void fdividef_kernel(float* const ys, const size_t num_xs, float* const x1s,
@@ -50,7 +50,7 @@ __global__ void fdividef_kernel(float* const ys, const size_t num_xs, float* con
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
ys[i] = fdividef(x1s[i], x2s[i]);
}
}
@@ -68,7 +68,7 @@ TEST_CASE("Unit_Device_fdividef_Negative_RTC") { NegativeTestRTCWrapper<4>(kFdiv
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = kern_name(xs[i]); \
} \
} \
@@ -123,9 +123,9 @@ class Dummy {
__device__ ~Dummy() {}
};
__global__ void fdividef_kernel_v1(float* x, float y) { float result = fdividef(x, y); }
__global__ void fdividef_kernel_v2(Dummy x, float y) { float result = fdivide(x); }
__global__ void fdividef_kernel_v3(float x, float* y) { float result = fdivide(x); }
__global__ void fdividef_kernel_v4(float x, Dummy y) { float result = fdivide(x); }
__global__ void fdividef_kernel_v2(Dummy x, float y) { float result = fdividef(x, y); }
__global__ void fdividef_kernel_v3(float x, float* y) { float result = fdividef(x, y); }
__global__ void fdividef_kernel_v4(float x, Dummy y) { float result = fdividef(x, y); }
)"};
static constexpr auto kIsFinite{R"(
@@ -35,7 +35,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T1>) { \
ys[i] = func_name##f(x1s[i], x2s[i]); \
} else if constexpr (std::is_same_v<double, T1>) { \
@@ -183,7 +183,7 @@ __global__ void frexp_kernel(std::pair<T, int>* const ys, const size_t num_xs, T
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
ys[i].first = frexpf(xs[i], &ys[i].second);
} else if constexpr (std::is_same_v<double, T>) {
@@ -35,7 +35,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T>) { \
ys[i] = func_name##f(x1s[i], x2s[i], x3s[i], x4s[i]); \
} else if constexpr (std::is_same_v<double, T>) { \
@@ -91,7 +91,7 @@ template <typename T> __global__ void remquo_kernel(std::pair<T, int>* const ys,
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
ys[i].first = remquof(x1s[i], x2s[i], &ys[i].second);
} else if constexpr (std::is_same_v<double, T>) {
@@ -123,7 +123,7 @@ __global__ void modf_kernel(std::pair<T, T>* const ys, const size_t num_xs, T* c
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
ys[i].first = modff(xs[i], &ys[i].second);
} else if constexpr (std::is_same_v<double, T>) {
@@ -265,7 +265,7 @@ MATH_BINARY_KERNEL_DEF(rhypot)
* ------------------------
* - Tests the numerical accuracy of `rhypotf(x, y)` and `rhypot(x, y)`against a table of
* difficult values, followed by a large number of randomly generated values. The maximum ulp error
* for single precision is 2 and for double precision is 1.
* is 2.
*
* Test source
* ------------------------
@@ -278,7 +278,7 @@ TEMPLATE_TEST_CASE("Unit_Device_rhypot_Accuracy_Positive", "", float, double) {
using RT = RefType_t<TestType>;
auto rhypot_ref = [](RT arg1, RT arg2) -> RT { return 1. / std::hypot(arg1, arg2); };
RT (*ref)(RT, RT) = rhypot_ref;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 1;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 2;
BinaryFloatingPointTest(rhypot_kernel<TestType>, ref, ULPValidatorBuilderFactory<TestType>(ulp));
}
@@ -348,7 +348,7 @@ MATH_TERNARY_KERNEL_DEF(rnorm3d)
* ------------------------
* - Tests the numerical accuracy of `rnorm3df(x, y, z)` and `rnorm3d(x, y, z)`against a table of
* difficult values, followed by a large number of randomly generated values. The maximum ulp error
* for single precision is 2 and for double precision is 1.
* is 2.
*
* Test source
* ------------------------
@@ -366,7 +366,7 @@ TEMPLATE_TEST_CASE("Unit_Device_rnorm3d_Accuracy_Positive", "", float, double) {
return 1. / std::sqrt(arg1 * arg1 + arg2 * arg2 + arg3 * arg3);
};
RT (*ref)(RT, RT, RT) = rnorm3d_ref;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 1;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 2;
TernaryFloatingPointTest(rnorm3d_kernel<TestType>, ref,
ULPValidatorBuilderFactory<TestType>(ulp));
}
@@ -438,7 +438,7 @@ MATH_QUATERNARY_KERNEL_DEF(rnorm4d)
* ------------------------
* - Tests the numerical accuracy of `rnorm4df(x, y, z, t)` and `rnorm4d(x, y, z, t)`against a
* table of difficult values, followed by a large number of randomly generated values. The maximum
* ulp error for single precision is 2 and for double precision is 1.
* ulp error is 2.
*
* Test source
* ------------------------
@@ -456,7 +456,7 @@ TEMPLATE_TEST_CASE("Unit_Device_rnorm4d_Accuracy_Positive", "", float, double) {
return 1. / std::sqrt(arg1 * arg1 + arg2 * arg2 + arg3 * arg3 + arg4 * arg4);
};
RT (*ref)(RT, RT, RT, RT) = rnorm4d_ref;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 1;
const auto ulp = std::is_same_v<float, TestType> ? 2 : 2;
QuaternaryFloatingPointTest(rnorm4d_kernel<TestType>, ref,
ULPValidatorBuilderFactory<TestType>(ulp));
}
@@ -488,7 +488,7 @@ TEST_CASE("Unit_Device_rnorm4d_rnorm4df_Negative_RTC") { NegativeTestRTCWrapper<
template <typename T, typename F, typename RF, typename ValidatorBuilder>
void NormSimpleTest(F kernel, RF ref_func, const ValidatorBuilder& validator_builder) {
const auto max_dim = 10000;
const auto max_dim = static_cast<uint64_t>(std::ceil(10000 * GetTestReductionFactor()));
LinearAllocGuard<T> x{LinearAllocs::hipHostMalloc, max_dim * sizeof(T)};
LinearAllocGuard<T> x_dev{LinearAllocs::hipMalloc, max_dim * sizeof(T)};
@@ -33,7 +33,7 @@ THE SOFTWARE.
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(xs[i]); \
} \
}
@@ -359,7 +359,7 @@ MATH_UNARY_SP_TEST_DEF_IMPL(__sincosf_cos, static_cast<double (*)(double)>(std::
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i]); \
} \
}
@@ -493,7 +493,7 @@ MATH_BINARY_SP_TEST_DEF(__fdividef, __fdiv_rn_ref);
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
ys[i] = func_name(x1s[i], x2s[i], x3s[i]); \
} \
}
@@ -32,7 +32,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T>) { \
ys[i] = func_name##f(n[i], xs[i]); \
} else if constexpr (std::is_same_v<double, T>) { \
@@ -96,6 +96,7 @@ void BesselSinglePrecisionRangeTest(kernel_bessel_n_sig<float> kernel,
const ValidatorBuilder& validator_builder, int n_input,
const float a, const float b) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
const auto reduction_factor = GetTestReductionFactor();
const auto max_batch_size = GetMaxAllowedDeviceMemoryUsage() / (sizeof(float) * 2 + sizeof(int));
LinearAllocGuard<int> x1s{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(int)};
LinearAllocGuard<float> x2s{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(float)};
@@ -103,15 +104,11 @@ void BesselSinglePrecisionRangeTest(kernel_bessel_n_sig<float> kernel,
MathTest math_test(kernel, max_batch_size);
std::fill_n(x1s.ptr(), max_batch_size, n_input);
size_t inserted = 0u;
for (float v = a; v != b; v = std::nextafter(v, b)) {
x2s.ptr()[inserted++] = v;
if (inserted < max_batch_size) continue;
const auto run = [&, gs = grid_size, bs = block_size](size_t inserted) {
math_test.Run(validator_builder, gs, bs, ref_func, inserted, x1s.ptr(), x2s.ptr());
};
math_test.Run(validator_builder, grid_size, block_size, ref_func, inserted, x1s.ptr(),
x2s.ptr());
inserted = 0u;
}
SinglePrecisionReducedRun(run, x2s, a, b, reduction_factor, max_batch_size);
}
template <typename T, typename F, typename ValidatorBuilder>
@@ -103,7 +103,7 @@ MATH_UNARY_KERNEL_DEF(erfinv)
* ------------------------
* - Tests the numerical accuracy of `erfinvf(x)` for all possible inputs. The results are
* compared against reference function `double boost::math::erf_inv(double)`. The maximum ulp error
* is 2.
* is 4.
*
* Test source
* ------------------------
@@ -124,7 +124,7 @@ TEST_CASE("Unit_Device_erfinvf_Accuracy_Positive") {
return boost::math::erf_inv(arg);
};
double (*ref)(double) = erfinv_ref;
UnarySinglePrecisionTest(erfinv_kernel<float>, ref, ULPValidatorBuilderFactory<float>(2));
UnarySinglePrecisionTest(erfinv_kernel<float>, ref, ULPValidatorBuilderFactory<float>(4));
}
/**
@@ -535,9 +535,9 @@ MATH_UNARY_KERNEL_DEF(lgamma)
*/
TEST_CASE("Unit_Device_lgammaf_Accuracy_Limited_Positive") {
double (*ref)(double) = std::lgamma;
UnarySinglePrecisionRangeTest(lgamma_kernel<float>, ref, ULPValidatorBuilderFactory<float>(6),
UnarySinglePrecisionRangeTest(lgamma_kernel<float>, ref, ULPValidatorBuilderFactory<float>(7),
std::numeric_limits<float>::lowest(), -11.0001f);
UnarySinglePrecisionRangeTest(lgamma_kernel<float>, ref, ULPValidatorBuilderFactory<float>(6),
UnarySinglePrecisionRangeTest(lgamma_kernel<float>, ref, ULPValidatorBuilderFactory<float>(7),
-2.2636f, std::numeric_limits<float>::max());
}
@@ -35,7 +35,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T>) { \
ys[i] = func_name##f(x1s[i], x2s[i], x3s[i]); \
} else if constexpr (std::is_same_v<double, T>) { \
@@ -36,7 +36,7 @@ TEST_CASE("Unit_Device_cos_cosf_Negative_RTC") { NegativeTestRTCWrapper<4>(kCos)
MATH_UNARY_WITHIN_ULP_TEST_DEF(tan, std::tan, 4, 2)
TEST_CASE("Unit_Device_tan_tanf_Negative_RTC") { NegativeTestRTCWrapper<4>(kTan); }
MATH_UNARY_WITHIN_ULP_TEST_DEF(asin, std::asin, 2, 2)
MATH_UNARY_WITHIN_ULP_TEST_DEF(asin, std::asin, 3, 2)
TEST_CASE("Unit_Device_asin_asinf_Negative_RTC") { NegativeTestRTCWrapper<4>(kAsin); }
MATH_UNARY_WITHIN_ULP_TEST_DEF(acos, std::acos, 2, 2)
@@ -78,7 +78,7 @@ __global__ void sincos_kernel(std::pair<T, T>* const ys, const size_t num_xs, T*
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
sincosf(xs[i], &ys[i].first, &ys[i].second);
} else if constexpr (std::is_same_v<double, T>) {
@@ -109,7 +109,7 @@ __global__ void sincospi_kernel(std::pair<T, T>* const ys, const size_t num_xs,
const auto tid = cg::this_grid().thread_rank();
const auto stride = cg::this_grid().size();
for (auto i = tid; i < num_xs; i += stride) {
for (size_t i = tid; i < num_xs; i += stride) {
if constexpr (std::is_same_v<float, T>) {
sincospif(xs[i], &ys[i].first, &ys[i].second);
} else if constexpr (std::is_same_v<double, T>) {
@@ -34,7 +34,7 @@ namespace cg = cooperative_groups;
const auto tid = cg::this_grid().thread_rank(); \
const auto stride = cg::this_grid().size(); \
\
for (auto i = tid; i < num_xs; i += stride) { \
for (size_t i = tid; i < num_xs; i += stride) { \
if constexpr (std::is_same_v<float, T>) { \
ys[i] = func_name##f(xs[i]); \
} else if constexpr (std::is_same_v<double, T>) { \
@@ -47,7 +47,10 @@ template <typename T, typename RT, typename RTArg, typename ValidatorBuilder>
void UnaryHalfPrecisionBruteForceTest(kernel_sig<T, Float16> kernel, ref_sig<RT, RTArg> ref_func,
const ValidatorBuilder& validator_builder) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
uint64_t stop = std::numeric_limits<uint16_t>::max() + 1ul;
const auto reduction_factor = GetTestReductionFactor();
const auto inv_reduction_factor = 1 / reduction_factor;
const auto stop = static_cast<uint64_t>(
std::ceil((std::numeric_limits<uint16_t>::max() + 1ul) * reduction_factor));
const auto max_batch_size =
std::min(GetMaxAllowedDeviceMemoryUsage() / (sizeof(Float16) + sizeof(T)), stop);
LinearAllocGuard<Float16> values{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(Float16)};
@@ -68,10 +71,11 @@ void UnaryHalfPrecisionBruteForceTest(kernel_sig<T, Float16> kernel, ref_sig<RT,
const auto sub_batch_size = min_sub_batch_size + (i < tail);
thread_pool.Post([=, &values] {
auto t = v;
auto t = v * inv_reduction_factor;
uint16_t val;
for (auto j = 0u; j < sub_batch_size; ++j) {
val = static_cast<uint16_t>(t++);
val = static_cast<uint16_t>(std::floor(t));
t += inv_reduction_factor;
values.ptr()[base_idx + j] = *reinterpret_cast<Float16*>(&val);
}
});
@@ -90,7 +94,10 @@ template <typename T, typename RT, typename RTArg, typename ValidatorBuilder>
void UnarySinglePrecisionBruteForceTest(kernel_sig<T, float> kernel, ref_sig<RT, RTArg> ref_func,
const ValidatorBuilder& validator_builder) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
uint64_t stop = std::numeric_limits<uint32_t>::max() + 1ul;
const auto reduction_factor = GetTestReductionFactor();
const auto inv_reduction_factor = 1 / reduction_factor;
const auto stop = static_cast<uint64_t>(
std::ceil((std::numeric_limits<uint32_t>::max() + 1ul) * reduction_factor));
const auto max_batch_size =
std::min(GetMaxAllowedDeviceMemoryUsage() / (sizeof(float) + sizeof(T)), stop);
LinearAllocGuard<float> values{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(float)};
@@ -111,10 +118,11 @@ void UnarySinglePrecisionBruteForceTest(kernel_sig<T, float> kernel, ref_sig<RT,
const auto sub_batch_size = min_sub_batch_size + (i < tail);
thread_pool.Post([=, &values] {
auto t = v;
auto t = v * inv_reduction_factor;
uint32_t val;
for (auto j = 0u; j < sub_batch_size; ++j) {
val = static_cast<uint32_t>(t++);
val = static_cast<uint32_t>(std::floor(t));
t += inv_reduction_factor;
values.ptr()[base_idx + j] = *reinterpret_cast<float*>(&val);
}
});
@@ -134,19 +142,17 @@ void UnarySinglePrecisionRangeTest(kernel_sig<T, float> kernel, ref_sig<RT, RTAr
const ValidatorBuilder& validator_builder, const float a,
const float b) {
const auto [grid_size, block_size] = GetOccupancyMaxPotentialBlockSize(kernel);
const auto reduction_factor = GetTestReductionFactor();
const auto max_batch_size = GetMaxAllowedDeviceMemoryUsage() / (sizeof(float) + sizeof(T));
LinearAllocGuard<float> values{LinearAllocs::hipHostMalloc, max_batch_size * sizeof(float)};
MathTest math_test(kernel, max_batch_size);
size_t inserted = 0u;
for (float v = a; v != b; v = std::nextafter(v, b)) {
values.ptr()[inserted++] = v;
if (inserted < max_batch_size) continue;
const auto run = [&, gs = grid_size, bs = block_size](size_t inserted) {
math_test.Run(validator_builder, gs, bs, ref_func, inserted, values.ptr());
};
math_test.Run(validator_builder, grid_size, block_size, ref_func, inserted, values.ptr());
inserted = 0u;
}
SinglePrecisionReducedRun(run, values, a, b, reduction_factor, max_batch_size);
}
template <typename T, typename RT, typename RTArg, typename ValidatorBuilder>