Skip to content
Open
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
132 changes: 132 additions & 0 deletions test/unit/mem/constCorrectness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,138 @@ TEST_CASE(
}
}

TEST_CASE(
"alpaka::makeView(api, pointer, extents, pitches, alignment) preserves explicit-pitch host metadata and inner "
"constness",
"[mem][view][correctness][makeView]")
{
auto const extents = alpaka::Vec{2u, 3u, 4u};
auto const explicitPitches = alpaka::Vec{80u, 20u, 4u};
alignas(64) std::array<int, 2 * 3 * 5 * 2> mutableStorage{};
alignas(64) std::array<int const, 2 * 3 * 5 * 2> innerConstStorage{};

auto mutableSeedView
= alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{});
auto const& outerConstSeedView = mutableSeedView;
auto innerConstSeedView
= alpaka::makeView(alpaka::api::host, innerConstStorage.data(), extents, alpaka::Alignment<64>{});

auto mutableExplicitPitchView
= alpaka::makeView(mutableSeedView, mutableStorage.data(), extents, explicitPitches, alpaka::Alignment<64>{});
auto const outerConstExplicitPitchView = alpaka::makeView(
outerConstSeedView,
mutableStorage.data(),
extents,
explicitPitches,
alpaka::Alignment<64>{});
auto innerConstExplicitPitchView = alpaka::makeView(
innerConstSeedView,
innerConstStorage.data(),
extents,
explicitPitches,
alpaka::Alignment<64>{});

SECTION("compile-time explicit pitches stay part of the returned host view contract")
{
// The explicit-pitch overload should keep the host API, vector types, alignment, and mutability encoded by the
// caller instead of rebuilding a packed view.
static_assert(std::same_as<decltype(mutableExplicitPitchView.getApi()), alpaka::api::Host>);
static_assert(std::same_as<decltype(outerConstExplicitPitchView.getApi()), alpaka::api::Host>);
static_assert(std::same_as<decltype(innerConstExplicitPitchView.getApi()), alpaka::api::Host>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(mutableExplicitPitchView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(mutableExplicitPitchView.getPitches())>,
std::remove_cvref_t<decltype(explicitPitches)>>);
static_assert(std::same_as<decltype(mutableExplicitPitchView.getAlignment()), alpaka::Alignment<64>>);
static_assert(!std::is_const_v<std::remove_pointer_t<decltype(mutableExplicitPitchView.data())>>);
static_assert(
!std::is_const_v<std::remove_reference_t<decltype(mutableExplicitPitchView[alpaka::Vec{0u, 0u, 0u}])>>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(outerConstExplicitPitchView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(outerConstExplicitPitchView.getPitches())>,
std::remove_cvref_t<decltype(explicitPitches)>>);
static_assert(std::same_as<decltype(outerConstExplicitPitchView.getAlignment()), alpaka::Alignment<64>>);
static_assert(std::is_const_v<std::remove_pointer_t<decltype(outerConstExplicitPitchView.data())>>);
static_assert(
std::is_const_v<std::remove_reference_t<decltype(outerConstExplicitPitchView[alpaka::Vec{0u, 0u, 0u}])>>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(innerConstExplicitPitchView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(innerConstExplicitPitchView.getPitches())>,
std::remove_cvref_t<decltype(explicitPitches)>>);
static_assert(std::same_as<decltype(innerConstExplicitPitchView.getAlignment()), alpaka::Alignment<64>>);
static_assert(std::is_const_v<std::remove_pointer_t<decltype(innerConstExplicitPitchView.data())>>);
static_assert(
std::is_const_v<std::remove_reference_t<decltype(innerConstExplicitPitchView[alpaka::Vec{0u, 0u, 0u}])>>);
}
}

TEST_CASE(
"alpaka::makeView(api, pointer, extents, alignment) preserves packed host metadata and inner constness",
"[mem][view][correctness][makeView]")
{
auto const extents = alpaka::Vec{2u, 3u, 4u};
auto const packedPitches = alpaka::calculatePitchesFromExtents<int>(extents);
alignas(64) std::array<int, 2 * 3 * 4> mutableStorage{};
alignas(64) std::array<int const, 2 * 3 * 4> innerConstStorage{};

auto mutablePackedView
= alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{});
auto const outerConstPackedView
= alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{});
auto innerConstPackedView
= alpaka::makeView(alpaka::api::host, innerConstStorage.data(), extents, alpaka::Alignment<64>{});

SECTION("compile-time packed pitches stay part of the returned host view contract")
{
// The packed overload should derive the host pitch type from the extents while preserving alignment and
// pointed-to constness.
static_assert(std::same_as<decltype(mutablePackedView.getApi()), alpaka::api::Host>);
static_assert(std::same_as<decltype(outerConstPackedView.getApi()), alpaka::api::Host>);
static_assert(std::same_as<decltype(innerConstPackedView.getApi()), alpaka::api::Host>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(mutablePackedView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(mutablePackedView.getPitches())>,
std::remove_cvref_t<decltype(packedPitches)>>);
static_assert(std::same_as<decltype(mutablePackedView.getAlignment()), alpaka::Alignment<64>>);
static_assert(!std::is_const_v<std::remove_pointer_t<decltype(mutablePackedView.data())>>);
static_assert(!std::is_const_v<std::remove_reference_t<decltype(mutablePackedView[alpaka::Vec{0u, 0u, 0u}])>>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(outerConstPackedView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(outerConstPackedView.getPitches())>,
std::remove_cvref_t<decltype(packedPitches)>>);
static_assert(std::same_as<decltype(outerConstPackedView.getAlignment()), alpaka::Alignment<64>>);
static_assert(std::is_const_v<std::remove_pointer_t<decltype(outerConstPackedView.data())>>);
static_assert(
std::is_const_v<std::remove_reference_t<decltype(outerConstPackedView[alpaka::Vec{0u, 0u, 0u}])>>);

static_assert(std::same_as<
std::remove_cvref_t<decltype(innerConstPackedView.getExtents())>,
std::remove_cvref_t<decltype(extents)>>);
static_assert(std::same_as<
std::remove_cvref_t<decltype(innerConstPackedView.getPitches())>,
std::remove_cvref_t<decltype(packedPitches)>>);
static_assert(std::same_as<decltype(innerConstPackedView.getAlignment()), alpaka::Alignment<64>>);
static_assert(std::is_const_v<std::remove_pointer_t<decltype(innerConstPackedView.data())>>);
static_assert(
std::is_const_v<std::remove_reference_t<decltype(innerConstPackedView[alpaka::Vec{0u, 0u, 0u}])>>);
}
}

TEST_CASE("View::getMdSpan keeps host mutability boundaries", "[mem][view][mdspan][correctness]")
{
alignas(32) std::array<int, 2 * 3> storage{};
Expand Down
39 changes: 39 additions & 0 deletions test/unit/mem/mdIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,45 @@ TEST_CASE("mdIterator host coverage", "[mem][mdIterator][iterator]")
REQUIRE(collectValues(constMdSpan) == visited);
}

SECTION("packed makeView derives packed pitches and getMdSpan keeps that layout")
{
// The packed raw-pointer overload must derive pitches from extents instead of accepting a padded layout, and
// the immediate MdSpan view should expose the same packed contract.
auto const extents = alpaka::Vec{2u, 3u, 4u};
auto const packedPitches = alpaka::calculatePitchesFromExtents<int>(extents);
auto const explicitPitches = alpaka::Vec{80u, 20u, 4u};
alignas(64) std::array<int, 2 * 3 * 4> storage{};
for(std::size_t i = 0; i < storage.size(); ++i)
storage[i] = static_cast<int>(i);

auto packedView = alpaka::makeView(api::host, storage.data(), extents, alpaka::Alignment<64>{});
auto mdSpan = packedView.getMdSpan();

REQUIRE(packedView.getApi() == api::host);
REQUIRE(packedView.getExtents() == extents);
REQUIRE(packedView.getPitches() == packedPitches);
REQUIRE(packedView.getPitches() != explicitPitches);
REQUIRE(packedView.data() == storage.data());
STATIC_REQUIRE(std::is_same_v<decltype(packedView.getAlignment()), alpaka::Alignment<64>>);

storage[15] = 1500;
storage[23] = 2300;
auto const sampleIdx = alpaka::Vec{1u, 0u, 3u};
REQUIRE(packedView[sampleIdx] == 1500);
REQUIRE(&packedView[sampleIdx] == &storage[15]);

REQUIRE(mdSpan.getExtents() == packedView.getExtents());
REQUIRE(mdSpan.getPitches() == packedView.getPitches());
REQUIRE(mdSpan.data() == packedView.data());
STATIC_REQUIRE(std::is_same_v<decltype(mdSpan.getAlignment()), alpaka::Alignment<64>>);

mdSpan[sampleIdx] = 777;
REQUIRE(packedView[sampleIdx] == 777);
REQUIRE(storage[15] == 777);
REQUIRE(storage[23] == 2300);
REQUIRE(&mdSpan[sampleIdx] == &packedView[sampleIdx]);
}

SECTION("pre-increment and post-increment advance one element at a time")
{
// Forward-iterator increments need to preserve the old value for post-increment and return self for
Expand Down
59 changes: 59 additions & 0 deletions test/unit/mem/subDataStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,65 @@ TEST_CASE(
}
}

TEST_CASE(
"alpaka::makeView(api, pointer, extents, pitches, alignment) keeps padded host pitches and subview aliasing",
"[mem][view][SubDataStorage]")
{
auto const extents = alpaka::Vec{2u, 3u, 4u};
auto const explicitPitches = alpaka::Vec{80u, 20u, 4u};
auto const packedPitches = alpaka::calculatePitchesFromExtents<int>(extents);
alignas(64) std::array<int, 40> storage{};
storage.fill(-1);

auto explicitPitchView
= alpaka::makeView(alpaka::api::host, storage.data(), extents, explicitPitches, alpaka::Alignment<64>{});

SECTION("explicit host pitches override the packed layout for indexing")
{
// The explicit-pitch overload must use the caller-provided padded layout instead of silently recomputing a
// packed one from the extents.
REQUIRE(explicitPitchView.getApi() == alpaka::api::host);
REQUIRE(explicitPitchView.getExtents() == extents);
REQUIRE(explicitPitchView.getPitches() == explicitPitches);
REQUIRE(explicitPitchView.data() == storage.data());
REQUIRE(explicitPitches != packedPitches);
STATIC_REQUIRE(std::is_same_v<decltype(explicitPitchView.getAlignment()), alpaka::Alignment<64>>);

storage[5] = -50;
storage[4] = -40;
REQUIRE(explicitPitchView[alpaka::Vec{0u, 1u, 0u}] == -50);

storage[20] = 220;
storage[12] = 120;
REQUIRE(explicitPitchView[alpaka::Vec{1u, 0u, 0u}] == 220);

auto const sampleIdx = alpaka::Vec{1u, 2u, 3u};
explicitPitchView[sampleIdx] = 1323;
REQUIRE(storage[33] == 1323);
REQUIRE(storage[23] == -1);
REQUIRE(&explicitPitchView[sampleIdx] == &storage[33]);
}

SECTION("offset subviews keep the padded pitch contract")
{
// Follow-on subviews should keep the same padded pitches after shifting the origin into the caller-defined
// layout.
auto const offset = alpaka::Vec{1u, 1u, 1u};
auto const subExtents = alpaka::Vec{1u, 2u, 3u};
auto subView = explicitPitchView.getSubView(offset, subExtents);

REQUIRE(subView.getExtents() == subExtents);
REQUIRE(subView.getPitches() == explicitPitchView.getPitches());
REQUIRE(subView.data() == &explicitPitchView[offset]);
STATIC_REQUIRE(std::is_same_v<decltype(subView.getAlignment()), alpaka::Alignment<>>);

subView[alpaka::Vec{0u, 1u, 2u}] = 777;
REQUIRE(explicitPitchView[offset + alpaka::Vec{0u, 1u, 2u}] == 777);
REQUIRE(storage[33] == 777);
REQUIRE(storage[23] == -1);
}
}

TEST_CASE(
"alpaka::View::getSubView(BoundaryDirection) covers host lower upper core and const aliasing",
"[mem][view][SubDataStorage]")
Expand Down