Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test marray on device #854

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions tests/marray/marray_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ constexpr sycl::marray<DataT, NumElements> iota_marray() {
std::make_index_sequence<NumElements>());
}

template <class ForwardIt, class T>
void iota(ForwardIt first, ForwardIt last, T value) {
for (; first != last; ++first) *first = value++;
}

} // namespace marray_common

#endif // SYCL_CTS_TEST_MARRAY_MARRAY_COMMON_H
124 changes: 84 additions & 40 deletions tests/marray/marray_constructor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,81 +31,125 @@ template <typename DataT, typename NumElementsT>
class run_marray_constructor_test {
static constexpr std::size_t NumElements = NumElementsT::value;

using marray_t = sycl::marray<DataT, NumElements>;
static constexpr size_t num_test_cases = 7;

private:
template <size_t num_elements = NumElements,
std::enable_if_t<num_elements == 1, bool> = true>
void check_constexpr_single_element() {}
static constexpr const char* check_names[num_test_cases] = {
"default constructor",
"scalar constructor",
"variadic constructor (NumElements DataT instances)",
"variadic constructor (one DataT instance, one marray instance)",
"variadic constructor (one marray instance, one DataT instance)",
"copy constructor",
"copy constructor rval reference"};

template <size_t num_elements = NumElements,
std::enable_if_t<num_elements != 1, bool> = true>
void check_constexpr_single_element() {
// one DataT instance, one marray instance
{
constexpr sycl::marray<DataT, num_elements - 1> ma_const =
marray_common::iota_marray<DataT, num_elements - 1, 2>();
constexpr marray_t ma{1, ma_const};
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK(value_operations::are_equal(ma_inc, ma));
}

// one marray instance, one DataT instance
{
constexpr sycl::marray<DataT, num_elements - 1> ma_const =
marray_common::iota_marray<DataT, num_elements - 1, 1>();
constexpr marray_t ma{ma_const, DataT(num_elements)};
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK(value_operations::are_equal(ma_inc, ma));
}
}

public:
void operator()(const std::string&) {
INFO("for number of elements \"" << NumElements << "\": ");
using marray_t = sycl::marray<DataT, NumElements>;

template <typename IteratorT>
static void run_checks(IteratorT results) {
// default constructor
{
marray_t ma;
CHECK(value_operations::are_equal(ma, DataT{}));
*(results++) = value_operations::are_equal(ma, DataT{});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

() are redundant but it might be clearer too. So no problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right, but since they are unary operators on each side of the expression I think it's one of those cases where the precedence rules get hard to remember, so I personally prefer the parenthesis. 😄

}

// scalar constructor
{
constexpr DataT value{1};
constexpr marray_t ma{value};
CHECK(value_operations::are_equal(ma, value));
*(results++) = value_operations::are_equal(ma, value);
}

// variadic constructor
{
// NumElements DataT instances
constexpr auto a = marray_common::iota_marray<DataT, NumElements, 1>();
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK(value_operations::are_equal(ma_inc, a));
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = value_operations::are_equal(ma_inc, a);

// only compiled when NumElements != 1
check_constexpr_single_element();
if constexpr (NumElements != 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the problem with 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test cases try to construct an marray using a scalar and an marray of size NumElements - 1. If NumElements is 1, then the smaller marray would have to be of size 0. 0-sized marrays are not allowed by the specification based on the following:

The number of elements parameter, NumElements, is a positive value of the std::size_t type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, by looking at the called function.
You just implement the comment, actually. :-)

// one DataT instance, one marray instance
{
constexpr sycl::marray<DataT, NumElements - 1> ma_const =
marray_common::iota_marray<DataT, NumElements - 1, 2>();
constexpr marray_t ma{1, ma_const};
marray_t ma_inc;
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = value_operations::are_equal(ma_inc, ma);
}

// one marray instance, one DataT instance
{
constexpr sycl::marray<DataT, NumElements - 1> ma_const =
marray_common::iota_marray<DataT, NumElements - 1, 1>();
constexpr marray_t ma{ma_const, DataT(NumElements)};
marray_t ma_inc;
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = value_operations::are_equal(ma_inc, ma);
}
} else {
// Two checks were skipped.
*(results++) = true;
*(results++) = true;
}
}

// copy constructor
{
constexpr DataT value{1};
constexpr marray_t rhs{value};
constexpr marray_t ma{rhs};
CHECK(value_operations::are_equal(ma, value));
*(results++) = value_operations::are_equal(ma, value);
}

// copy constructor rval reference
{
constexpr marray_t ma{
marray_common::iota_marray<DataT, NumElements, 1>()};
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK(value_operations::are_equal(ma_inc, ma));
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = value_operations::are_equal(ma_inc, ma);
}
}

public:
void operator()(const std::string&) {
INFO("for number of elements \"" << NumElements << "\": ");

{
INFO("validation on host");

bool check_results[num_test_cases] = {false};
run_checks(check_results);
for (size_t i = 0; i < num_test_cases; ++i) {
INFO(check_names[i]);
CHECK(check_results[i]);
}
}

{
INFO("validation on device");

auto queue = sycl_cts::util::get_cts_object::queue();
bool check_results[num_test_cases] = {false};
{
sycl::buffer<bool, 1> check_results_buff{
check_results, sycl::range<1>{num_test_cases}};

queue
.submit([&](sycl::handler& cgh) {
sycl::accessor check_results_acc{check_results_buff, cgh,
sycl::read_write};
cgh.single_task([=]() { run_checks(check_results_acc.begin()); });
})
.wait_and_throw();
}
run_checks(check_results);
for (size_t i = 0; i < num_test_cases; ++i) {
INFO(check_names[i]);
CHECK(check_results[i]);
}
}
}
};
Expand Down
150 changes: 105 additions & 45 deletions tests/marray/marray_members.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,116 +32,176 @@ template <typename DataT, typename NumElementsT>
class run_marray_members_test {
static constexpr std::size_t NumElements = NumElementsT::value;

using marray_t = sycl::marray<DataT, NumElements>;

private:
template <size_t num_elements,
std::enable_if_t<num_elements != 1, bool> = true>
void check_conversion() {}

template <size_t num_elements,
std::enable_if_t<num_elements == 1, bool> = true>
void check_conversion() {
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
DataT t{ma_inc};
CHECK((t == DataT{1}));
}
static constexpr size_t num_test_cases = 19;

static constexpr const char* check_names[num_test_cases] = {
"implicit conversion",
"size() (noexcept)",
"size() (result)",
"operator[] (before write)",
"operator[] (after write)",
"const operator[]",
"operator=(marray)",
"operator=(T)",
"iterator (increment)",
"iterator (decrement)",
"iterator (equivalence)",
"const iterator (increment)",
"const iterator (decrement)",
"const iterator (equivalence)",
"value_type",
"reference",
"const_reference",
"iterator",
"const_iterator",
};

public:
void operator()(const std::string&) {
INFO("for number of elements \"" << NumElements << "\": ");
using marray_t = sycl::marray<DataT, NumElements>;

template <typename IteratorT>
static void run_checks(IteratorT results) {
// implicit conversion
{
// only compiled when NumElements == 1
check_conversion<NumElements>();
if constexpr (NumElements == 1) {
marray_t ma_inc;
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
DataT t{ma_inc};
*(results++) = (t == DataT{1});
} else {
// One check were skipped.
*(results++) = true;
}
}

// size()
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK(noexcept(ma_inc.size()));
CHECK((ma_inc.size() == NumElements));
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = noexcept(ma_inc.size());
*(results++) = (ma_inc.size() == NumElements);
}

// operator[]
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
CHECK((ma_inc[0] == DataT{1}));
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
*(results++) = (ma_inc[0] == DataT{1});
ma_inc[0] = DataT{0};
CHECK((ma_inc[0] == DataT{0}));
*(results++) = (ma_inc[0] == DataT{0});
}

// const operator[]
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
const marray_t ma_const{ma_inc};
CHECK((ma_const[0] == DataT{1}));
*(results++) = (ma_const[0] == DataT{1});
}

// operator=(marray)
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
const marray_t ma_const{ma_inc};

marray_t ma_tmp{DataT{0}};
ma_tmp = ma_const;
CHECK(value_operations::are_equal(ma_tmp, ma_const));
*(results++) = value_operations::are_equal(ma_tmp, ma_const);
}

// operator=(T)
{
marray_t ma_tmp{DataT{0}};
ma_tmp = DataT{1};
CHECK(value_operations::are_equal(ma_tmp, marray_t(DataT(1))));
*(results++) = value_operations::are_equal(ma_tmp, marray_t(DataT(1)));
}

// iterator
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);

auto it_ma = ma_inc.begin();
auto it_ma_tmp = it_ma;
it_ma++;
if (NumElements > 1) {
CHECK((*it_ma == DataT(2)));
*(results++) = (*it_ma == DataT(2));
} else {
*(results++) = true;
}
it_ma--;
CHECK((*it_ma == DataT(1)));
CHECK((it_ma == it_ma_tmp));
*(results++) = (*it_ma == DataT(1));
*(results++) = (it_ma == it_ma_tmp);
}

// const iterator
{
marray_t ma_inc;
std::iota(ma_inc.begin(), ma_inc.end(), 1);
marray_common::iota(ma_inc.begin(), ma_inc.end(), 1);
const marray_t ma_const = ma_inc;
auto it_ma = ma_const.begin();
auto it_ma_tmp = it_ma;
it_ma++;
if (NumElements > 1) {
CHECK((*it_ma == DataT(2)));
*(results++) = (*it_ma == DataT(2));
} else {
*(results++) = true;
}
it_ma--;
CHECK((*it_ma == DataT(1)));
CHECK((it_ma == it_ma_tmp));
*(results++) = (*it_ma == DataT(1));
*(results++) = (it_ma == it_ma_tmp);
}

// member types
{
STATIC_CHECK(std::is_same_v<typename marray_t::value_type, DataT>);
STATIC_CHECK(std::is_same_v<typename marray_t::reference, DataT&>);
STATIC_CHECK(
std::is_same_v<typename marray_t::const_reference, const DataT&>);
STATIC_CHECK(std::is_same_v<typename marray_t::iterator, DataT*>);
STATIC_CHECK(
std::is_same_v<typename marray_t::const_iterator, const DataT*>);
*(results++) = std::is_same_v<typename marray_t::value_type, DataT>;
*(results++) = std::is_same_v<typename marray_t::reference, DataT&>;
*(results++) =
std::is_same_v<typename marray_t::const_reference, const DataT&>;
*(results++) = std::is_same_v<typename marray_t::iterator, DataT*>;
*(results++) =
std::is_same_v<typename marray_t::const_iterator, const DataT*>;
}
}

public:
void operator()(const std::string&) {
INFO("for number of elements \"" << NumElements << "\": ");

{
INFO("validation on host");

bool check_results[num_test_cases] = {false};
run_checks(check_results);
for (size_t i = 0; i < num_test_cases; ++i) {
INFO(check_names[i]);
CHECK(check_results[i]);
}
}

{
INFO("validation on device");

auto queue = sycl_cts::util::get_cts_object::queue();
bool check_results[num_test_cases] = {false};
{
sycl::buffer<bool, 1> check_results_buff{
check_results, sycl::range<1>{num_test_cases}};

queue
.submit([&](sycl::handler& cgh) {
sycl::accessor check_results_acc{check_results_buff, cgh,
sycl::read_write};
cgh.single_task([=]() { run_checks(check_results_acc.begin()); });
})
.wait_and_throw();
}
run_checks(check_results);
for (size_t i = 0; i < num_test_cases; ++i) {
INFO(check_names[i]);
CHECK(check_results[i]);
}
}
}
};
Expand Down
Loading