From a459f9a35800a5c19b14603511aef4e61cd0fcb5 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Thu, 28 Oct 2021 15:47:17 +0200 Subject: [PATCH] support multiple selecting record coords in Split --- include/llama/mapping/Split.hpp | 93 +++++++++++++++++++-------------- tests/dump.cpp | 12 +++++ tests/mapping.Split.cpp | 69 +++++++++++++++++++++--- 3 files changed, 128 insertions(+), 46 deletions(-) diff --git a/include/llama/mapping/Split.hpp b/include/llama/mapping/Split.hpp index 2f1dc05542..e0e4c0e94b 100644 --- a/include/llama/mapping/Split.hpp +++ b/include/llama/mapping/Split.hpp @@ -10,46 +10,65 @@ namespace llama::mapping auto partitionRecordDim(Record, RecordCoord) { using namespace boost::mp11; + using Rec = Record; if constexpr(sizeof...(Coords) == 0) { - using With = Record, FirstCoord>>; - using Without = mp_erase_c, FirstCoord, FirstCoord + 1>; - return mp_list{}; + using Part1 = Record>; + using Part2 = mp_erase_c; + return mp_list{}; } else { - using Result = decltype(partitionRecordDim( - Record, FirstCoord>>{}, - RecordCoord{})); - using With = mp_replace_at_c, FirstCoord, mp_first>; - using Without = mp_replace_at_c, FirstCoord, mp_second>; - return mp_list{}; + using FieldTag = GetTag>; + using FieldType = GetType>; + using InnerPartition = decltype(partitionRecordDim(FieldType{}, RecordCoord{})); + using Part1 = Record>>; + using Part2 = mp_replace_at_c>>; + return mp_list{}; } } - template< - std::size_t FirstDstCoord, - std::size_t... DstCoords, - std::size_t FirstSkippedCoord, - std::size_t... SkippedCoords> - constexpr auto offsetCoord( - RecordCoord, - RecordCoord) + template + struct PartitionFoldOpImpl { - if constexpr(FirstDstCoord < FirstSkippedCoord) - return RecordCoord{}; - else if constexpr(FirstDstCoord > FirstSkippedCoord) - return RecordCoord{}; - else - return cat( - RecordCoord{}, - offsetCoord(RecordCoord{}, RecordCoord{})); + using Part1Before = boost::mp11::mp_first; + using Part2Before = boost::mp11::mp_second; + using R = decltype(partitionRecordDim(Part2Before{}, GetCoordFromTags{})); + using Part1After = boost::mp11::mp_first; + using Part2After = boost::mp11::mp_second; + + using type = boost::mp11::mp_list, Part2After>; + }; + + template + using PartitionFoldOp = typename PartitionFoldOpImpl::type; + + template + auto partitionRecordDim(Record, boost::mp11::mp_list) + { + using namespace boost::mp11; + using Initial = mp_list, Record>; // initially, nothing selected for mapping 1 + return mp_fold, RCs>, 1>...>, Initial, PartitionFoldOp>{}; } + + template + inline constexpr bool isSelected = RecordCoordCommonPrefixIsSame; + + template + struct IsSelectedPredicate + { + template + using fn = boost::mp11::mp_bool>; + }; + + template + inline constexpr bool isSelected> = boost::mp11:: + mp_any_of_q, IsSelectedPredicate>::value; } // namespace internal /// Mapping which splits off a part of the record dimension and maps it differently then the rest. - /// \tparam RecordCoordForMapping1 A \ref RecordCoord selecting the part of the record dimension to be mapped - /// differently. + /// \tparam RecordCoordForMapping1 A \ref RecordCoord or a list of RecordCoords selecting the part of the record + /// dimension to be mapped differently. /// \tparam MappingTemplate1 The mapping used for the selected part of the record dimension. /// \tparam MappingTemplate2 The mapping used for the not selected part of the record dimension. /// \tparam SeparateBlobs If true, both pieces of the record dimension are mapped to separate blobs. @@ -107,19 +126,13 @@ namespace llama::mapping LLAMA_FN_HOST_ACC_INLINE constexpr auto blobNrAndOffset(ArrayIndex ai, RecordCoord = {}) const -> NrAndOffset { - if constexpr(RecordCoordCommonPrefixIsSame>) - { - using namespace boost::mp11; - // zero all coordinate values that are part of RecordCoordForMapping1 - using Prefix = mp_repeat_c, RecordCoordForMapping1::size>; - using Suffix = mp_drop_c, RecordCoordForMapping1::size>; - return mapping1.blobNrAndOffset(ai, RecordCoordFromList>{}); - } + using Tags = boost::mp11::mp_drop_c>, 1>; + + if constexpr(internal::isSelected, RecordCoordForMapping1>) + return mapping1.blobNrAndOffset(ai, GetCoordFromTags{}); else { - constexpr auto dstCoord - = internal::offsetCoord(RecordCoord{}, RecordCoordForMapping1{}); - auto nrAndOffset = mapping2.blobNrAndOffset(ai, dstCoord); + auto nrAndOffset = mapping2.blobNrAndOffset(ai, GetCoordFromTags{}); if constexpr(SeparateBlobs) nrAndOffset.nr += Mapping1::blobCount; else @@ -136,7 +149,7 @@ namespace llama::mapping }; template< - typename RecordCoordForMapping1, + typename RecordCoordsForMapping1, template typename MappingTemplate1, template @@ -148,7 +161,7 @@ namespace llama::mapping using type = Split< ArrayExtents, RecordDim, - RecordCoordForMapping1, + RecordCoordsForMapping1, MappingTemplate1, MappingTemplate2, SeparateBlobs>; diff --git a/tests/dump.cpp b/tests/dump.cpp index ce6a3b419d..0382c6a180 100644 --- a/tests/dump.cpp +++ b/tests/dump.cpp @@ -220,6 +220,18 @@ TEST_CASE("dump.ParticleUnaligned.Split.AoSoA8.SoA.One.AoS") true>{extents}); } +TEST_CASE("dump.ParticleUnaligned.Split.Multilist.SoA.One") +{ + // split out Pos and Vel into SoA, the rest into One + dump(llama::mapping::Split< + ArrayExtents, + Particle, + boost::mp11::mp_list, llama::RecordCoord<2>>, + llama::mapping::PreconfiguredSoA<>::type, + llama::mapping::AlignedOne, + true>{extents}); +} + TEST_CASE("AoS.Aligned") { const auto mapping = llama::mapping::AlignedAoS{extents}; diff --git a/tests/mapping.Split.cpp b/tests/mapping.Split.cpp index 226635fc71..8328d3da5c 100644 --- a/tests/mapping.Split.cpp +++ b/tests/mapping.Split.cpp @@ -3,6 +3,14 @@ #include #include +TEST_CASE("Split.partitionRecordDim.OneMemberRecord") +{ + using RecordDim = llama::Record>; + using R = decltype(llama::mapping::internal::partitionRecordDim(RecordDim{}, llama::RecordCoord<0>{})); + STATIC_REQUIRE(std::is_same_v, RecordDim>); + STATIC_REQUIRE(std::is_same_v, llama::Record<>>); +} + TEST_CASE("Split.partitionRecordDim.Vec3I") { using R = decltype(llama::mapping::internal::partitionRecordDim(Vec3I{}, llama::RecordCoord<1>{})); @@ -22,17 +30,25 @@ TEST_CASE("Split.partitionRecordDim.Particle") std::is_same_v< boost::mp11::mp_second, llama::Record< - llama::Field< - tag::Pos, - llama::Record< - llama::Field, - llama::Field, - llama::Field>>, + llama::Field, llama::Field, llama::Field, llama::Field>>, llama::Field>>); } +TEST_CASE("Split.partitionRecordDim.Particle.List") +{ + using R = decltype(llama::mapping::internal::partitionRecordDim( + Particle{}, + boost::mp11::mp_list, llama::RecordCoord<2>>{})); + STATIC_REQUIRE(std::is_same_v< + boost::mp11::mp_first, + llama::Record, llama::Field>>); + STATIC_REQUIRE(std::is_same_v< + boost::mp11::mp_second, + llama::Record, llama::Field>>); +} + TEST_CASE("Split.SoA_SingleBlob.AoS_Packed.1Buffer") { using ArrayExtents = llama::ArrayExtentsDynamic<2>; @@ -106,3 +122,44 @@ TEST_CASE("Split.AoSoA8.AoS_Packed.One.SoA_SingleBlob.4Buffer") // std::ofstream{"Split.AoSoA8.AoS.One.SoA.4Buffer.svg"} << llama::toSvg(mapping); } + + +TEST_CASE("Split.Multilist.SoA.One") +{ + // split out Pos and Vel into SoA, the rest into One + using ArrayExtents = llama::ArrayExtentsDynamic<1>; + auto extents = ArrayExtents{32}; + auto mapping = llama::mapping::Split< + ArrayExtents, + Particle, + boost::mp11::mp_list, llama::RecordCoord<2>>, + llama::mapping::PreconfiguredSoA<>::type, + llama::mapping::AlignedOne, + true>{extents}; + + CHECK(mapping.blobNrAndOffset<0, 0>({0}) == llama::NrAndOffset{0, 0}); + CHECK(mapping.blobNrAndOffset<0, 1>({0}) == llama::NrAndOffset{1, 0}); + CHECK(mapping.blobNrAndOffset<0, 2>({0}) == llama::NrAndOffset{2, 0}); + CHECK(mapping.blobNrAndOffset<1>({0}) == llama::NrAndOffset{6, 0}); + CHECK(mapping.blobNrAndOffset<2, 0>({0}) == llama::NrAndOffset{3, 0}); + CHECK(mapping.blobNrAndOffset<2, 1>({0}) == llama::NrAndOffset{4, 0}); + CHECK(mapping.blobNrAndOffset<2, 2>({0}) == llama::NrAndOffset{5, 0}); + CHECK(mapping.blobNrAndOffset<3, 0>({0}) == llama::NrAndOffset{6, 4}); + CHECK(mapping.blobNrAndOffset<3, 1>({0}) == llama::NrAndOffset{6, 5}); + CHECK(mapping.blobNrAndOffset<3, 2>({0}) == llama::NrAndOffset{6, 6}); + CHECK(mapping.blobNrAndOffset<3, 3>({0}) == llama::NrAndOffset{6, 7}); + + CHECK(mapping.blobNrAndOffset<0, 0>({31}) == llama::NrAndOffset{0, 31 * 8}); + CHECK(mapping.blobNrAndOffset<0, 1>({31}) == llama::NrAndOffset{1, 31 * 8}); + CHECK(mapping.blobNrAndOffset<0, 2>({31}) == llama::NrAndOffset{2, 31 * 8}); + CHECK(mapping.blobNrAndOffset<1>({31}) == llama::NrAndOffset{6, 0}); + CHECK(mapping.blobNrAndOffset<2, 0>({31}) == llama::NrAndOffset{3, 31 * 8}); + CHECK(mapping.blobNrAndOffset<2, 1>({31}) == llama::NrAndOffset{4, 31 * 8}); + CHECK(mapping.blobNrAndOffset<2, 2>({31}) == llama::NrAndOffset{5, 31 * 8}); + CHECK(mapping.blobNrAndOffset<3, 0>({31}) == llama::NrAndOffset{6, 4}); + CHECK(mapping.blobNrAndOffset<3, 1>({31}) == llama::NrAndOffset{6, 5}); + CHECK(mapping.blobNrAndOffset<3, 2>({31}) == llama::NrAndOffset{6, 6}); + CHECK(mapping.blobNrAndOffset<3, 3>({31}) == llama::NrAndOffset{6, 7}); + + // std::ofstream{"Split.AoSoA8.AoS.One.SoA.4Buffer.svg"} << llama::toSvg(mapping); +}