Added unit-tests for SAMAXV and DAMAXV APIs

- Added unit-test cases for accuracy and memory-testing of the
  following kernels :
  - bli_samaxv_zen_int( ... ) and bli_samaxv_zen_int_avx512( ... )
  - bli_damaxv_zen_int( ... ) and bli_damaxv_zen_int_avx512( ... )

- Added test cases to verify the compliance of SAMAXV and DAMAXV
  APIs, through Exception Value Testing(EVT). This is done by
  inducing exception values in the input vector(at two places).
  The induction is controlled by the user, through indices given as
  part of the parameterized test-cases.

AMD-Internal: [CPUPL-4660][CPUPL-4661]
Change-Id: I25b7d54487fa9fb6a30ac13563d1497af8b582ab
This commit is contained in:
Vignesh Balasubramanian
2024-02-27 16:59:33 +05:30
committed by Vignesh Balasubramanian
parent 00b37f30a9
commit 8f4cb485c6
6 changed files with 963 additions and 3 deletions

View File

@@ -0,0 +1,228 @@
/*
BLIS
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name(s) of the copyright holder(s) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gtest/gtest.h>
#include "test_amaxv.h"
class damaxvEVT :
public ::testing::TestWithParam<std::tuple<gtint_t, // n
gtint_t, // incx
gtint_t, // xi, index for exval in x
double, // xi_exval
gtint_t, // xj, index for exval in x
double>> {}; // xj_exval
// Tests using random values as vector elements.
TEST_P( damaxvEVT, NaNInfCheck )
{
using T = double;
//----------------------------------------------------------
// Initialize values from the parameters passed through
// test suite instantiation (INSTANTIATE_TEST_SUITE_P).
//----------------------------------------------------------
// vector length
gtint_t n = std::get<0>(GetParam());
// stride size for x
gtint_t incx = std::get<1>(GetParam());
// index for exval in x
gtint_t xi = std::get<2>(GetParam());
// exval for index xi
T xi_exval = std::get<3>(GetParam());
// index for exval in x
gtint_t xj = std::get<4>(GetParam());
// exval for index xj
T xj_exval = std::get<5>(GetParam());
// Set the threshold for the errors
double thresh = testinghelpers::getEpsilon<T>();
//----------------------------------------------------------
// Call generic test body using those parameters
//----------------------------------------------------------
test_amaxv<T>( n, incx, xi, xi_exval, xj, xj_exval, thresh );
}
// Test-case logger : Used to print the test-case details when vectors have exception value.
// The string format is as follows :
// {blas/cblas/blis}_n(vec_size)_incx(m)(abs_incx)_X_(xi)_(xexval)
class damaxvEVTPrint {
public:
std::string operator()(
testing::TestParamInfo<std::tuple<gtint_t,gtint_t,gtint_t,double,gtint_t,double>> str) const {
gtint_t n = std::get<0>(str.param);
gtint_t incx = std::get<1>(str.param);
gtint_t xi = std::get<2>(str.param);
double xi_exval = std::get<3>(str.param);
gtint_t xj = std::get<4>(str.param);
double xj_exval = std::get<5>(str.param);
#ifdef TEST_BLAS
std::string str_name = "blas_";
#elif TEST_CBLAS
std::string str_name = "cblas_";
#else //#elif TEST_BLIS_TYPED
std::string str_name = "bli_";
#endif
str_name += "_" + std::to_string(n);
std::string incx_str = ( incx >= 0) ? std::to_string(incx) : "m" + std::to_string(std::abs(incx));
str_name += "_" + incx_str;
str_name = str_name + "_X_" + std::to_string(xi) + "_" + testinghelpers::get_value_string(xi_exval);
str_name = str_name + "_" + std::to_string(xj) + "_" + testinghelpers::get_value_string(xj_exval);
return str_name;
}
};
static double NaN = std::numeric_limits<double>::quiet_NaN();
static double Inf = std::numeric_limits<double>::infinity();
/*
Exception value testing on vectors(Zen3) :
DAMAXV currently uses the bli_damaxv_zen_int( ... ) kernel for computation on zen3
machines.
The sizes and indices given in the instantiator are to ensure code coverage inside
the kernel.
Kernel structure for bli_damaxv_zen_int( ... ) is as follows :
bli_damaxv_zen_int() --> bli_vec_absmax_double() --> bli_vec_search_double()
bli_vec_absmax_double() structure:
For unit strides :
Main loop : In blocks of 48 --> L48
Fringe loops : In blocks of 32 --> L32
In blocks of 16 --> L16
In blocks of 8 --> L8
In blocks of 4 --> L4
In blocks of 2 --> L2
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
bli_vec_search_double() structure:
For unit strides :
Main loop : In blocks of 4 --> L4
In blocks of 2 --> L2
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
The sizes chosen are as follows(in accordance to the structure in bli_vec_absmax_double()) :
176 : 3*L48 + L32
175 : 3*L48 + L16 + L8 + L4 + L2 + 1(LScalar)
The following indices are sufficient to ensure code-coverage of loops :
0 <= idx < 144 - In L48
144 <= idx < 160 - In L32(for size 176), in L16(for size 175)
160 <= idx < 168 - In L8
168 <= idx < 172 - In L4
172 <= idx < 174 - In L2
174 <= idx < 175 - In LScalar
These sizes and indices also ensure code coverage for bli_vec_search_double().
The testsuite requires 2 indices(and 2 exception values) to be induced in the vector.
*/
// Exception value testing with unit strides
INSTANTIATE_TEST_SUITE_P(
unitStrides_zen3,
damaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(175), gtint_t(176)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(1)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(143), gtint_t(159),
gtint_t(167), gtint_t(171), gtint_t(173),
gtint_t(174)), // xi, index for exval in xi_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)), // xi_exval
::testing::Values(gtint_t(5), gtint_t(140), gtint_t(155),
gtint_t(163), gtint_t(170), gtint_t(172)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)) // xj_exval
),
::damaxvEVTPrint()
);
/*
Exception value testing on vectors(Zen4) :
damaxv currently uses the bli_damaxv_zen_int( ... ) kernel for computation on zen3
machines.
The sizes and indices given in the instantiator are to ensure code coverage inside
the kernel.
Kernel structure for bli_damaxv_zen_int( ... ) is as follows :
For unit strides :
Main loop : In blocks of 32 --> L32
Fringe loops : In blocks of 8 --> L8
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
The sizes chosen are as follows :
367 - 10*L32 + 5*L8 + 7(LScalar)
The following indices are sufficient to ensure code-coverage of loops :
0 <= idx < 320 - In L32
320 <= idx < 360 - In L8
360 <= idx < 367 - In LScalar
The testsuite requires 2 indices(and 2 exception values) to be induced in the vector.
*/
// Exception value testing with unit strides
INSTANTIATE_TEST_SUITE_P(
unitStrides_zen4,
damaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(367)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(1)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(315),
gtint_t(340), gtint_t(363)), // xi, index for exval in xi_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)), // xi_exval
::testing::Values(gtint_t(1), gtint_t(300),
gtint_t(327), gtint_t(366)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)) // xj_exval
),
::damaxvEVTPrint()
);
// Exception value testing with non-unit strides
INSTANTIATE_TEST_SUITE_P(
nonUnitStrides,
damaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(10)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(3)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(5)), // xi, index for exval in xi_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)), // xi_exval
::testing::Values(gtint_t(5), gtint_t(9)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, double(2.3)) // xj_exval
),
::damaxvEVTPrint()
);

View File

@@ -0,0 +1,203 @@
/*
BLIS
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name(s) of the copyright holder(s) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gtest/gtest.h>
#include "test_amaxv.h"
class samaxvEVT :
public ::testing::TestWithParam<std::tuple<gtint_t, // n
gtint_t, // incx
gtint_t, // xi, index for exval in x
float, // xi_exval
gtint_t, // xj, index for exval in x
float>> {}; // xj_exval
// Tests using random values as vector elements.
TEST_P( samaxvEVT, NaNInfCheck )
{
using T = float;
//----------------------------------------------------------
// Initialize values from the parameters passed through
// test suite instantiation (INSTANTIATE_TEST_SUITE_P).
//----------------------------------------------------------
// vector length
gtint_t n = std::get<0>(GetParam());
// stride size for x
gtint_t incx = std::get<1>(GetParam());
// index for exval in x
gtint_t xi = std::get<2>(GetParam());
// exval for index xi
T xi_exval = std::get<3>(GetParam());
// index for exval in x
gtint_t xj = std::get<4>(GetParam());
// exval for index xj
T xj_exval = std::get<5>(GetParam());
// Set the threshold for the errors
double thresh = testinghelpers::getEpsilon<T>();
//----------------------------------------------------------
// Call generic test body using those parameters
//----------------------------------------------------------
test_amaxv<T>( n, incx, xi, xi_exval, xj, xj_exval, thresh );
}
// Test-case logger : Used to print the test-case details when vectors have exception value.
// The string format is as follows :
// {blas/cblas/blis}_n(vec_size)_incx(m)(abs_incx)_X_(xi)_(xexval)
class samaxvEVTPrint {
public:
std::string operator()(
testing::TestParamInfo<std::tuple<gtint_t,gtint_t,gtint_t,float,gtint_t,float>> str) const {
gtint_t n = std::get<0>(str.param);
gtint_t incx = std::get<1>(str.param);
gtint_t xi = std::get<2>(str.param);
float xi_exval = std::get<3>(str.param);
gtint_t xj = std::get<4>(str.param);
float xj_exval = std::get<5>(str.param);
#ifdef TEST_BLAS
std::string str_name = "blas_";
#elif TEST_CBLAS
std::string str_name = "cblas_";
#else //#elif TEST_BLIS_TYPED
std::string str_name = "bli_";
#endif
str_name += "_" + std::to_string(n);
std::string incx_str = ( incx >= 0) ? std::to_string(incx) : "m" + std::to_string(std::abs(incx));
str_name += "_" + incx_str;
str_name = str_name + "_X_" + std::to_string(xi) + "_" + testinghelpers::get_value_string(xi_exval);
str_name = str_name + "_" + std::to_string(xj) + "_" + testinghelpers::get_value_string(xj_exval);
return str_name;
}
};
static float NaN = std::numeric_limits<float>::quiet_NaN();
static float Inf = std::numeric_limits<float>::infinity();
/*
Exception value testing on vectors(Zen3) :
SAMAXV currently uses the bli_samaxv_zen_int( ... ) kernel for computation on zen3
machines.
The sizes and indices given in the instantiator are to ensure code coverage inside
the kernel.
Kernel structure for bli_samaxv_zen_int( ... ) is as follows :
Main loop : In blocks of 8 --> L8
Fringe loops : Element-wise loop --> LScalar
The sizes chosen are as follows :
61 - 7*L8 + 5(LScalar)
The following indices are sufficient to ensure code-coverage of loops :
0 <= idx < 56 - In L8
56 <= idx < 61 - In LScalar
The testsuite requires 2 indices(and 2 exception values) to set exception values in the vector.
*/
// Exception value testing with unit strides
INSTANTIATE_TEST_SUITE_P(
unitStrides_zen3,
samaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(61)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(1)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(48),
gtint_t(55), gtint_t(57)), // xi, index for exval in xi_exval
::testing::Values(NaN, -Inf, Inf, float(2.3)), // xi_exval
::testing::Values(gtint_t(1), gtint_t(33),
gtint_t(50), gtint_t(60)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, float(2.3)) // xj_exval
),
::samaxvEVTPrint()
);
/*
Exception value testing on vectors(Zen4) :
SAMAXV currently uses the bli_samaxv_zen_int_avx512( ... ) kernel for computation on zen3
machines.
The sizes and indices given in the instantiator are to ensure code coverage inside
the kernel.
Kernel structure for bli_samaxv_zen_int_avx512( ... ) is as follows :
For unit strides :
Main loop : In blocks of 80 --> L80
Fringe loops : In blocks of 16 --> L16
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
The sizes chosen are as follows :
461 - 5*L80 + 3*L16 + 13(LScalar)
The following indices are sufficient to ensure code-coverage of loops :
0 <= idx < 400 - In L80
400 <= idx < 448 - In L16
448 <= idx < 461 - In LScalar
The testsuite requires 2 indices(and 2 exception values) to set exception values in the vector.
*/
// Exception value testing with unit strides
INSTANTIATE_TEST_SUITE_P(
unitStrides_zen4,
samaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(461)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(1)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(347),
gtint_t(420), gtint_t(459)), // xi, index for exval in xi_exval
::testing::Values(NaN, -Inf, Inf, float(2.3)), // xi_exval
::testing::Values(gtint_t(101), gtint_t(252),
gtint_t(447), gtint_t(450)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, float(2.3)) // xj_exval
),
::samaxvEVTPrint()
);
// Exception value testing with non-unit strides
INSTANTIATE_TEST_SUITE_P(
nonUnitStrides,
samaxvEVT,
::testing::Combine(
::testing::Values(gtint_t(10)), // n, size of vectors with unit-stride
::testing::Values(gtint_t(3)), // stride size for x
::testing::Values(gtint_t(0), gtint_t(5)), // xi, index for exval in xi_exval
::testing::Values(NaN, Inf, -Inf, float(2.3)), // xi_exval
::testing::Values(gtint_t(1), gtint_t(9)), // xj, index for exval in xj_exval
::testing::Values(NaN, -Inf, Inf, float(2.3)) // xj_exval
),
::samaxvEVTPrint()
);

View File

@@ -4,7 +4,7 @@
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved.
Copyright (C) 2023 - 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -43,7 +43,7 @@
*/
template<typename T>
void test_amaxv( gtint_t n, gtint_t incx, double thresh )
static void test_amaxv( gtint_t n, gtint_t incx, double thresh )
{
//----------------------------------------------------------
// Initialize vectors with random numbers.
@@ -63,5 +63,41 @@ void test_amaxv( gtint_t n, gtint_t incx, double thresh )
//----------------------------------------------------------
// Compute component-wise error.
//----------------------------------------------------------
EXPECT_EQ( idx, idx_ref );
computediff( idx, idx_ref );
}
/**
* @brief Generic test body for amaxv operation with extreme values.
*/
template<typename T>
static void test_amaxv( gtint_t n, gtint_t incx, gtint_t xi, T xi_exval,
gtint_t xj, T xj_exval, double thresh )
{
//----------------------------------------------------------
// Initialize vectors with random numbers.
//----------------------------------------------------------
std::vector<T> x = testinghelpers::get_random_vector<T>( -10, 10, n, incx );
// Update the value at index xi to an extreme value, x_exval.
if ( -1 < xi && xi < n ) x[xi * abs(incx)] = xi_exval;
else return;
// Update the value at index yi to an extreme value, y_exval.
if ( -1 < xj && xj < n ) x[xj * abs(incx)] = xj_exval;
else return;
//----------------------------------------------------------
// Call reference implementation to get ref results.
//----------------------------------------------------------
gtint_t idx_ref = testinghelpers::ref_amaxv<T>( n, x.data(), incx );
//----------------------------------------------------------
// Call BLIS function.
//----------------------------------------------------------
gtint_t idx = amaxv<T>( n, x.data(), incx );
//----------------------------------------------------------
// Compute component-wise error.
//----------------------------------------------------------
computediff( idx, idx_ref, true );
}

View File

@@ -0,0 +1,201 @@
/*
BLIS
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name(s) of the copyright holder(s) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gtest/gtest.h>
#include "test_amaxv_ukr.h"
class damaxvUkr :
public ::testing::TestWithParam<std::tuple<damaxv_ker_ft, // Function pointer type for damaxv kernels
gtint_t, // n
gtint_t, // incx
bool>> {}; // is_memory_test
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(damaxvUkr);
// Tests using random integers as vector elements.
TEST_P( damaxvUkr, AccuracyCheck )
{
using T = double;
//----------------------------------------------------------
// Initialize values from the parameters passed through
// test suite instantiation (INSTANTIATE_TEST_SUITE_P).
//----------------------------------------------------------
// Assign the kernel address to the function pointer
damaxv_ker_ft ukr_fp = std::get<0>(GetParam());
// vector length:
gtint_t n = std::get<1>(GetParam());
// stride size for x:
gtint_t incx = std::get<2>(GetParam());
// is_memory_test
bool is_memory_test = std::get<3>(GetParam());
// Set the threshold for the errors:
double thresh = testinghelpers::getEpsilon<T>();
//----------------------------------------------------------
// Call generic test body using those parameters
//----------------------------------------------------------
test_amaxv_ukr<T, damaxv_ker_ft>( ukr_fp, n, incx, thresh, is_memory_test );
}
// Test-case logger : Used to print the test-case details for unit testing the kernels.
// NOTE : The kernel name is the prefix in instantiator name, and thus is not printed
// with this logger.
class damaxvUkrPrint {
public:
std::string operator()(
testing::TestParamInfo<std::tuple<damaxv_ker_ft,gtint_t,gtint_t,bool>> str) const {
gtint_t n = std::get<1>(str.param);
gtint_t incx = std::get<2>(str.param);
bool is_memory_test = std::get<3>(str.param);
std::string str_name = "n" + std::to_string(n);
std::string incx_str = ( incx >= 0) ? std::to_string(incx) : "m" + std::to_string(std::abs(incx));
str_name += "_incx" + incx_str;
str_name += ( is_memory_test ) ? "_mem_test_enabled" : "_mem_test_disabled";
return str_name;
}
};
#if defined(BLIS_KERNELS_ZEN) && defined(GTEST_AVX2FMA3)
/*
Unit testing for functionality of bli_damaxv_zen_int kernel.
The code structure for bli_damaxv_zen_int( ... ) is as follows :
bli_damaxv_zen_int() --> bli_vec_absmax_double() --> bli_vec_search_double()
bli_vec_absmax_double() structure:
For unit strides :
Main loop : In blocks of 48 --> L48
Fringe loops : In blocks of 32 --> L32
In blocks of 16 --> L16
In blocks of 8 --> L8
In blocks of 4 --> L4
In blocks of 2 --> L2
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
bli_vec_search_double() structure:
For unit strides :
Main loop : In blocks of 4 --> L4
In blocks of 2 --> L2
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
*/
// Unit testing with unit strides, across all loops.
INSTANTIATE_TEST_SUITE_P(
bli_damaxv_zen_int_unitStrides,
damaxvUkr,
::testing::Combine(
::testing::Values(bli_damaxv_zen_int), // kernel address
::testing::Values(gtint_t(48), // for size n, L48
gtint_t(32), // L32
gtint_t(16), // L16
gtint_t(8), // L8
gtint_t(4), // L4
gtint_t(2), // L2
gtint_t(1), // LScalar
gtint_t(144), // 3*L48
gtint_t(176), // 3*L48 + L32
gtint_t(175)), // 3*L48 + L16 + L8 + L4 + L2 + LScalar
::testing::Values(gtint_t(1)), // incx
::testing::Values(false, true) // is_memory_test
),
::damaxvUkrPrint()
);
// Unit testing with non-unit strides.
INSTANTIATE_TEST_SUITE_P(
bli_damaxv_zen_int_nonUnitStrides,
damaxvUkr,
::testing::Combine(
::testing::Values(bli_damaxv_zen_int), // kernel address
::testing::Values(gtint_t(10), // n, size of the vector
gtint_t(25)),
::testing::Values(gtint_t(5)), // incx
::testing::Values(false, true) // is_memory_test
),
::damaxvUkrPrint()
);
#endif
#if defined(BLIS_KERNELS_ZEN4) && defined(GTEST_AVX512)
/*
Unit testing for functionality of bli_damaxv_zen_int_avx512 kernel.
The code structure for bli_damaxv_zen_int_avx512( ... ) is as follows :
For unit strides :
Main loop : In blocks of 32 --> L32
Fringe loops : In blocks of 8 --> L8
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
*/
// Unit testing with unit strides, across all loops.
INSTANTIATE_TEST_SUITE_P(
bli_damaxv_zen_int_avx512_unitStrides,
damaxvUkr,
::testing::Combine(
::testing::Values(bli_damaxv_zen_int_avx512), // kernel address
::testing::Values(gtint_t(32), // for size n, L32
gtint_t(16), // 2*L8
gtint_t(8), // L8
gtint_t(7), // LScalar
gtint_t(160), // 5*L32
gtint_t(168), // 5*L32 + L8
gtint_t(175), // 5*L32 + L8 + 7(LScalar)
gtint_t(191)), // 5*L32 + 3*L8 + 7(LScalar)
::testing::Values(gtint_t(1)), // incx
::testing::Values(false, true) // is_memory_test
),
::damaxvUkrPrint()
);
// Unit testing with non-unit strides.
INSTANTIATE_TEST_SUITE_P(
bli_damaxv_zen_int_avx512_nonUnitStrides,
damaxvUkr,
::testing::Combine(
::testing::Values(bli_damaxv_zen_int_avx512), // kernel address
::testing::Values(gtint_t(10), // n, size of the vector
gtint_t(25)),
::testing::Values(gtint_t(5)), // incx
::testing::Values(false, true) // is_memory_test
),
::damaxvUkrPrint()
);
#endif

View File

@@ -0,0 +1,177 @@
/*
BLIS
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name(s) of the copyright holder(s) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gtest/gtest.h>
#include "test_amaxv_ukr.h"
class samaxvUkr :
public ::testing::TestWithParam<std::tuple<samaxv_ker_ft, // Function pointer type for samaxv kernels
gtint_t, // n
gtint_t, // incx
bool>> {}; // is_memory_test
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(samaxvUkr);
// Tests using random integers as vector elements.
TEST_P( samaxvUkr, AccuracyCheck )
{
using T = float;
//----------------------------------------------------------
// Initialize values from the parameters passed through
// test suite instantiation (INSTANTIATE_TEST_SUITE_P).
//----------------------------------------------------------
// Assign the kernel address to the function pointer
samaxv_ker_ft ukr_fp = std::get<0>(GetParam());
// vector length:
gtint_t n = std::get<1>(GetParam());
// stride size for x:
gtint_t incx = std::get<2>(GetParam());
// is_memory_test
bool is_memory_test = std::get<3>(GetParam());
// Set the threshold for the errors:
double thresh = testinghelpers::getEpsilon<T>();
//----------------------------------------------------------
// Call generic test body using those parameters
//----------------------------------------------------------
test_amaxv_ukr<T, samaxv_ker_ft>( ukr_fp, n, incx, thresh, is_memory_test );
}
// Test-case logger : Used to print the test-case details for unit testing the kernels.
// NOTE : The kernel name is the prefix in instantiator name, and thus is not printed
// with this logger.
class samaxvUkrPrint {
public:
std::string operator()(
testing::TestParamInfo<std::tuple<samaxv_ker_ft,gtint_t,gtint_t,bool>> str) const {
gtint_t n = std::get<1>(str.param);
gtint_t incx = std::get<2>(str.param);
bool is_memory_test = std::get<3>(str.param);
std::string str_name = "n" + std::to_string(n);
std::string incx_str = ( incx >= 0) ? std::to_string(incx) : "m" + std::to_string(std::abs(incx));
str_name += "_incx" + incx_str;
str_name += ( is_memory_test ) ? "_mem_test_enabled" : "_mem_test_disabled";
return str_name;
}
};
#if defined(BLIS_KERNELS_ZEN) && defined(GTEST_AVX2FMA3)
/*
Unit testing for functionality of bli_samaxv_zen_int kernel.
The code structure for bli_samaxv_zen_int( ... ) is as follows :
For unit strides :
Main loop : In blocks of 8 --> L8
Fringe loops : Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
*/
// Unit testing with unit strides, across all loops.
INSTANTIATE_TEST_SUITE_P(
bli_samaxv_zen_int_unitStrides,
samaxvUkr,
::testing::Combine(
::testing::Values(bli_samaxv_zen_int), // kernel address
::testing::Values(gtint_t(8), // for size n, L8
gtint_t(7), // LScalar
gtint_t(40), // 5*L8
gtint_t(47)), // 5*L8 + LScalar
::testing::Values(gtint_t(1)), // incx
::testing::Values(false, true) // is_memory_test
),
::samaxvUkrPrint()
);
// Unit testing with non-unit strides.
INSTANTIATE_TEST_SUITE_P(
bli_samaxv_zen_int_nonUnitStrides,
samaxvUkr,
::testing::Combine(
::testing::Values(bli_samaxv_zen_int), // kernel address
::testing::Values(gtint_t(10), // n, size of the vector
gtint_t(25)),
::testing::Values(gtint_t(5)), // incx
::testing::Values(false, true) // is_memory_test
),
::samaxvUkrPrint()
);
#endif
#if defined(BLIS_KERNELS_ZEN4) && defined(GTEST_AVX512)
/*
Unit testing for functionality of bli_samaxv_zen_int_avx512 kernel.
The code structure for bli_samaxv_zen_int_avx512( ... ) is as follows :
For unit strides :
Main loop : In blocks of 80 --> L80
Fringe loops : In blocks of 16 --> L16
Element-wise loop --> LScalar
For non-unit strides : A single loop, to process element wise.
*/
// Unit testing with unit strides, across all loops.
INSTANTIATE_TEST_SUITE_P(
bli_samaxv_zen_int_avx512_unitStrides,
samaxvUkr,
::testing::Combine(
::testing::Values(bli_samaxv_zen_int_avx512), // kernel address
::testing::Values(gtint_t(80), // for size n, L80
gtint_t(48), // 3*L16
gtint_t(16), // L16
gtint_t(11), // 11(LScalar)
gtint_t(317)), // 3*L80 + 4*L16 + 13(LScalar)
::testing::Values(gtint_t(1)), // incx
::testing::Values(false, true) // is_memory_test
),
::samaxvUkrPrint()
);
// Unit testing with non-unit strides.
INSTANTIATE_TEST_SUITE_P(
bli_samaxv_zen_int_avx512_nonUnitStrides,
samaxvUkr,
::testing::Combine(
::testing::Values(bli_samaxv_zen_int_avx512), // kernel address
::testing::Values(gtint_t(10), // n, size of the vector
gtint_t(25)),
::testing::Values(gtint_t(5)), // incx
::testing::Values(false, true) // is_memory_test
),
::samaxvUkrPrint()
);
#endif

View File

@@ -0,0 +1,115 @@
/*
BLIS
An object-based framework for developing high-performance BLAS-like
libraries.
Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name(s) of the copyright holder(s) nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <stdexcept>
#include "level1/amaxv/amaxv.h"
#include "level1/ref_amaxv.h"
#include "inc/check_error.h"
#include "common/testing_helpers.h"
/**
* @brief Test body for amaxv micro-kernels
*/
template<typename T, typename FT>
void test_amaxv_ukr( FT ukr_fp, gtint_t n, gtint_t incx, double thresh, bool is_memory_test = false )
{
// Pointers to obtain the required memory.
T *x, *x_copy;
gtint_t size_x = testinghelpers::buff_dim( n, incx ) * sizeof( T );
// Create the objects for the input operand
// The kernel does not expect the memory to be aligned
testinghelpers::ProtectedBuffer x_buffer( size_x, false, is_memory_test );
// Creating x_copy, to save the contents of x(without any redzones)
testinghelpers::ProtectedBuffer x_copy_buffer( size_x, false, false );
// Acquire the first set of greenzones for x and y
x = ( T* )x_buffer.greenzone_1;
x_copy = ( T* )x_copy_buffer.greenzone_1; // For x_copy, there is no greenzone_2
// Initiaize the memory with random data
testinghelpers::datagenerators::randomgenerators( -10, 10, n, incx, x );
// Copying the contents of x to x_copy
memcpy( x_copy, x, size_x );
dim_t idx;
// Add signal handler for segmentation fault
testinghelpers::ProtectedBuffer::start_signal_handler();
try
{
// Call the ukr function.
// This call is made irrespective of is_memory_test.
// This will check for out of bounds access with first redzone(if memory test is true)
// Else, it will just call the ukr function.
ukr_fp( n, x, incx, &idx, nullptr );
if ( is_memory_test )
{
// Acquire the pointers near the second redzone
x = ( T* )x_buffer.greenzone_2;
// Copy the data for x and y accordingly
memcpy( x, x_copy, size_x );
// Call the ukr function, to check with the second redzone.
ukr_fp( n, x, incx, &idx, nullptr );
}
}
catch(const std::exception& e)
{
// Reset to default signal handler
testinghelpers::ProtectedBuffer::stop_signal_handler();
// Show failure in case seg fault was detected
FAIL() << "Memory Test Failed";
}
// Reset to default signal handler
testinghelpers::ProtectedBuffer::stop_signal_handler();
//----------------------------------------------------------
// Call reference implementation to get ref results.
//----------------------------------------------------------
dim_t idx_ref = testinghelpers::ref_amaxv<T>( n, x, incx );
//----------------------------------------------------------
// Compute component-wise error.
//----------------------------------------------------------
EXPECT_EQ( idx, idx_ref );
}