Skip to content

Commit

Permalink
Test workdiv construction by user-def vector and improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mehmetyusufoglu authored and psychocoderHPC committed Mar 14, 2024
1 parent 23229ef commit d9348ea
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 21 deletions.
5 changes: 5 additions & 0 deletions test/unit/workDiv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ append_recursive_files_add_to_src_group("src/" "src/" "cpp" _FILES_SOURCE)
alpaka_add_executable(
${_TARGET_NAME}
${_FILES_SOURCE})

target_include_directories(
${_TARGET_NAME}
PRIVATE "src")

target_link_libraries(
${_TARGET_NAME}
PRIVATE common)
Expand Down
112 changes: 112 additions & 0 deletions test/unit/workDiv/src/FooVec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* Copyright 2022 Sergei Bastrakov, Jan Stephan, Mehmet Yusufoglu
* SPDX-License-Identifier: MPL-2.0
*/

#pragma once

#include <alpaka/dim/Traits.hpp>
#include <alpaka/elem/Traits.hpp>
#include <alpaka/extent/Traits.hpp>
#include <alpaka/vec/Vec.hpp>

#include <array>
#include <iostream>

//! User defined vector for testing the usability of any vector type.
//!
//! \tparam TVal The data type.
//! \tparam N Vector size as a non-type parameter.
template<typename TVal, std::size_t N>
class FooVec
{
public:
static_assert(N <= 3, "Size must be 3 or smaller");
std::array<TVal, N> arr;

// Default Constructor
FooVec()
{
arr.fill(TVal());
}

// Constructor with initializer list
FooVec(std::initializer_list<TVal> initList)
{
if(initList.size() <= N)
{
std::copy(initList.begin(), initList.end(), arr.begin());
}
else
{
throw std::out_of_range("Initializer list size exceeds array size");
}
}

// Example member function to print the contents of the array
void printArray() const
{
for(auto const& element : arr)
{
std::cout << element << ' ';
}
std::cout << std::endl;
}
};

namespace alpaka::trait
{

//! The DimType specialization for the user defined vector
//! \tparam TVal The data type.
//! \tparam N Vector size as a non-type parameter.
template<typename TVal, size_t N>
struct DimType<FooVec<TVal, N>>
{
using type = alpaka::DimInt<N>;
};

//! The ElemType specialization for the user defined vector
//! \tparam TVal The data type.
//! \tparam N Vector size as a non-type parameter.
template<typename TVal, size_t N>
struct ElemType<FooVec<TVal, N>>
{
using type = TVal;
};

//! The IdxType specialization for the user defined vecto
//! \tparam TVal The data type.
//! \tparam N Vector size as a non-type parameter.
template<typename TVal, size_t N>
struct IdxType<FooVec<TVal, N>>
{
using type = std::size_t;
};

//! Specialization for the user defined vector type FooVec. This specialization makes the vector usable in
//! WorkDivMembers construction. Since alpaka vectors use z-y-x order, FooVec is reversed.
//! \tparam TVal The element type of the vector type
//! \tparam N The size of the vector type
template<typename TVal, size_t N>
struct GetExtents<FooVec<TVal, N>>
{
ALPAKA_NO_HOST_ACC_WARNING
ALPAKA_FN_HOST_ACC constexpr auto operator()(FooVec<TVal, N> const& extent) const
-> alpaka::Vec<DimInt<N>, TVal>
{
alpaka::Vec<DimInt<N>, TVal> v{};
#if BOOST_COMP_NVCC && BOOST_COMP_NVCC < BOOST_VERSION_NUMBER(11, 3, 0)
if(DimInt<N>::value > 0)
#else
if constexpr(DimInt<N>::value > 0)
#endif
{
// Reverse the vector since the dimensions ordered as z-y-x in alpaka
for(unsigned i = 0; i < DimInt<N>::value; i++)
v[i] = extent.arr[DimInt<N>::value - i - 1];
}

return v;
}
};
} // namespace alpaka::trait
68 changes: 47 additions & 21 deletions test/unit/workDiv/src/WorkDivHelpersTest.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* Copyright 2022 Sergei Bastrakov, Jan Stephan, Bernhard Manfred Gruber
/* Copyright 2022 Sergei Bastrakov, Jan Stephan, Bernhard Manfred Gruber, Mehmet Yusufoglu
* SPDX-License-Identifier: MPL-2.0
*/

#include "FooVec.hpp"

#include <alpaka/acc/AccDevProps.hpp>
#include <alpaka/test/KernelExecutionFixture.hpp>
#include <alpaka/test/acc/TestAccs.hpp>
Expand All @@ -10,8 +12,6 @@
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>

#include <tuple>

namespace
{
template<typename TAcc>
Expand Down Expand Up @@ -141,44 +141,70 @@ TEMPLATE_LIST_TEST_CASE("isValidWorkDiv", "[workDiv]", alpaka::test::TestAccs)
}

//! Test the constructors of WorkDivMembers using 3D extent, 3D extent with zero elements and 2D extents
//! Test using any vector type in WorkDivMembers construction.
TEST_CASE("WorkDivMembers", "[workDiv]")
{
using Idx = std::size_t;
using Dim3D = alpaka::DimInt<3>;
using Vec3D = alpaka::Vec<Dim3D, Idx>;

auto blocksPerGrid3D = Vec3D{1u, 2u, 3u};
auto const threadsPerBlock3D = Vec3D{2u, 4u, 6u};
auto const elementsPerThread3D = Vec3D::all(static_cast<Idx>(1u));
auto const threadsPerBlock3D = Vec3D{2u, 2u, 2u};
auto blocksPerGrid3D = Vec3D{1u, 1u, 1u};

// Arguments: {1,2,3},{2,4,6},{1,1,1}
auto ref3D = alpaka::WorkDivMembers<Dim3D, Idx>{blocksPerGrid3D, threadsPerBlock3D, elementsPerThread3D};
// call WorkDivMembers without explicit class template types
// Call without explicitly specifying explicit WorkDivMembers class template parameter types
auto workDiv3D = alpaka::WorkDivMembers(blocksPerGrid3D, threadsPerBlock3D, elementsPerThread3D);
CHECK(workDiv3D == ref3D);
CHECK(ref3D == workDiv3D);

// change blocks per grid, assign zero to an element
blocksPerGrid3D = Vec3D{3u, 3u, 0u};
// Change blocks per grid
blocksPerGrid3D = Vec3D{3u, 6u, 9u};
// Arguments: {3,6,9},{2,4,6},{1,1,1}
ref3D = alpaka::WorkDivMembers<Dim3D, Idx>{blocksPerGrid3D, threadsPerBlock3D, elementsPerThread3D};
// call without explicit template parameter types
// Call without explicitly specifying explicit WorkDivMembers class template parameter types
workDiv3D = alpaka::WorkDivMembers(blocksPerGrid3D, threadsPerBlock3D, elementsPerThread3D);
CHECK(workDiv3D == ref3D);
CHECK(ref3D == workDiv3D);

// test using 2D vectors
// Test using 2D vectors
using Dim2D = alpaka::DimInt<2>;
using Vec2D = alpaka::Vec<Dim2D, Idx>;

auto const threadsPerBlock2D = Vec2D{2u, 2u};
auto const blocksPerGrid2D = Vec2D{1u, 1u};
auto const blocksPerGrid2D = Vec2D{6u, 9u};
auto const threadsPerBlock2D = Vec2D{4u, 6u};
auto const elementsPerThread2D = Vec2D::all(static_cast<Idx>(1u));

// Arguments: {6,9},{4,6},{1,1}. The order of each input is y-x since alpaka vector uses z-y-x ordering
auto const ref2D = alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2D, threadsPerBlock2D, elementsPerThread2D};
auto const workDiv2D = alpaka::WorkDivMembers(blocksPerGrid2D, threadsPerBlock2D, elementsPerThread2D);
CHECK(workDiv2D == ref2D);
CHECK(ref2D == workDiv2D);

// Test using different input types, reduced to given explicit class template types
auto ref2DimUsingMixed
= alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2D, threadsPerBlock3D, elementsPerThread3D};
CHECK(workDiv2D == ref2DimUsingMixed);
// Test using initializer lists. Arguments: {6,9},{4,6},{1,1}. The order of initializer list is y-x since alpaka
// vector uses z-y-x ordering
auto const workDiv2DUsingInitList = alpaka::WorkDivMembers<Dim2D, Idx>({6, 9}, {4, 6}, {1, 1});
CHECK(ref2D == workDiv2DUsingInitList);

ref2DimUsingMixed = alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2D, threadsPerBlock3D, elementsPerThread2D};
CHECK(workDiv2D == ref2DimUsingMixed);
// Test using different input types with different number of dimensions(ranks), number of dimensions reduced to
// given explicit class template type number of dimensions (e.g. Dim2D) in the call. Arguments: {6,9},{2,4,6},{1,1}
auto worDiv2DUsingMixedRanks
= alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2D, threadsPerBlock3D, elementsPerThread3D};
// Since the first element of threadsPerBlock3D is along Z-axis, it is removed
CHECK(ref2D == worDiv2DUsingMixedRanks);

worDiv2DUsingMixedRanks
= alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2D, threadsPerBlock3D, elementsPerThread2D};
CHECK(ref2D == worDiv2DUsingMixedRanks);

// Test the construction by using a user-defined type FooVec
//
// Test WorkDivMembers using the arguments of the type FooVec
auto const blocksPerGrid2DFoo = FooVec<size_t, 2u>{9u, 6u};
auto const threadsPerBlock2DFoo = FooVec<size_t, 2u>{6u, 4u};
auto const elementsPerThread2DFoo = FooVec<size_t, 2u>{1u, 1u};

// Arguments: {9,6},{6,4},{1,1}. These arguments are reversed at GetExtents specialization of FooVec
// FooVec assumes the list is ordered as x-y-z
auto const workDiv2DUsingFooVec
= alpaka::WorkDivMembers<Dim2D, Idx>{blocksPerGrid2DFoo, threadsPerBlock2DFoo, elementsPerThread2DFoo};
CHECK(ref2D == workDiv2DUsingFooVec);
}

0 comments on commit d9348ea

Please sign in to comment.