Skip to content

Commit

Permalink
Merge pull request #43310 from makortel/portableCollectionDef
Browse files Browse the repository at this point in the history
Allow Portable{Collection,Object}<T, TDev> to be used also independently of ALPAKA_ACCELERATOR_NAMESPACE
  • Loading branch information
cmsbuild authored Jan 8, 2024
2 parents 0a086bd + 1143991 commit 1b67f09
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 106 deletions.
41 changes: 39 additions & 2 deletions DataFormats/Portable/interface/PortableCollection.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,55 @@
#ifndef DataFormats_Portable_interface_PortableCollection_h
#define DataFormats_Portable_interface_PortableCollection_h

#include "HeterogeneousCore/AlpakaInterface/interface/traits.h"
#include <alpaka/alpaka.hpp>

#include "DataFormats/Portable/interface/PortableHostCollection.h"
#include "DataFormats/Portable/interface/PortableDeviceCollection.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToDevice.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"

namespace traits {

// trait for a generic SoA-based product
template <typename T, typename TDev, typename = std::enable_if_t<alpaka::isDevice<TDev>>>
class PortableCollectionTrait;
struct PortableCollectionTrait {
using CollectionType = PortableDeviceCollection<T, TDev>;
};

// specialise for host device
template <typename T>
struct PortableCollectionTrait<T, alpaka_common::DevHost> {
using CollectionType = PortableHostCollection<T>;
};

} // namespace traits

// type alias for a generic SoA-based product
template <typename T, typename TDev, typename = std::enable_if_t<alpaka::isDevice<TDev>>>
using PortableCollection = typename traits::PortableCollectionTrait<T, TDev>::CollectionType;

// define how to copy PortableCollection between host and device
namespace cms::alpakatools {
template <typename TLayout, typename TDevice>
struct CopyToHost<PortableDeviceCollection<TLayout, TDevice>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableDeviceCollection<TLayout, TDevice> const& srcData) {
PortableHostCollection<TLayout> dstData(srcData->metadata().size(), queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};

template <typename TLayout>
struct CopyToDevice<PortableHostCollection<TLayout>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableHostCollection<TLayout> const& srcData) {
using TDevice = typename alpaka::trait::DevType<TQueue>::type;
PortableDeviceCollection<TLayout, TDevice> dstData(srcData->metadata().size(), queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};
} // namespace cms::alpakatools

#endif // DataFormats_Portable_interface_PortableCollection_h
45 changes: 41 additions & 4 deletions DataFormats/Portable/interface/PortableObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,55 @@

#include <type_traits>

#include "HeterogeneousCore/AlpakaInterface/interface/traits.h"
#include <alpaka/alpaka.hpp>

#include "DataFormats/Portable/interface/PortableHostObject.h"
#include "DataFormats/Portable/interface/PortableDeviceObject.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToDevice.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"

namespace traits {

// trait for a generic SoA-based product
// trait for a generic struct-based product
template <typename T, typename TDev, typename = std::enable_if_t<alpaka::isDevice<TDev>>>
class PortableObjectTrait;
struct PortableObjectTrait {
using ProductType = PortableDeviceObject<T, TDev>;
};

// specialise for host device
template <typename T>
struct PortableObjectTrait<T, alpaka_common::DevHost> {
using ProductType = PortableHostObject<T>;
};

} // namespace traits

// type alias for a generic SoA-based product
// type alias for a generic struct-based product
template <typename T, typename TDev, typename = std::enable_if_t<alpaka::isDevice<TDev>>>
using PortableObject = typename traits::PortableObjectTrait<T, TDev>::ProductType;

// define how to copy PortableObject between host and device
namespace cms::alpakatools {
template <typename TProduct, typename TDevice>
struct CopyToHost<PortableDeviceObject<TProduct, TDevice>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableDeviceObject<TProduct, TDevice> const& srcData) {
PortableHostObject<TProduct> dstData(queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};

template <typename TProduct>
struct CopyToDevice<PortableHostObject<TProduct>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableHostObject<TProduct> const& srcData) {
using TDevice = typename alpaka::trait::DevType<TQueue>::type;
PortableDeviceObject<TProduct, TDevice> dstData(queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};
} // namespace cms::alpakatools

#endif // DataFormats_Portable_interface_PortableObject_h
52 changes: 2 additions & 50 deletions DataFormats/Portable/interface/alpaka/PortableCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,18 @@
#include <alpaka/alpaka.hpp>

#include "DataFormats/Portable/interface/PortableCollection.h"
#include "DataFormats/Portable/interface/PortableHostCollection.h"
#include "DataFormats/Portable/interface/PortableDeviceCollection.h"
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToDevice.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"

// This header is not used by PortableCollection, but is included here to automatically
// provide its content to users of ALPAKA_ACCELERATOR_NAMESPACE::PortableCollection.
#include "HeterogeneousCore/AlpakaInterface/interface/AssertDeviceMatchesHostCollection.h"

namespace ALPAKA_ACCELERATOR_NAMESPACE {

#if defined ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
// ... or any other CPU-based accelerators

// generic SoA-based product in host memory
template <typename T>
using PortableCollection = ::PortableHostCollection<T>;

#else

// generic SoA-based product in device memory
// generic SoA-based product in the device (that may be host) memory
template <typename T>
using PortableCollection = ::PortableDeviceCollection<T, Device>;

#endif // ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
using PortableCollection = ::PortableCollection<T, Device>;

} // namespace ALPAKA_ACCELERATOR_NAMESPACE

namespace traits {

// specialise the trait for the device provided by the ALPAKA_ACCELERATOR_NAMESPACE
template <typename T>
class PortableCollectionTrait<T, ALPAKA_ACCELERATOR_NAMESPACE::Device> {
using CollectionType = ALPAKA_ACCELERATOR_NAMESPACE::PortableCollection<T>;
};

} // namespace traits

namespace cms::alpakatools {
template <typename TLayout, typename TDevice>
struct CopyToHost<PortableDeviceCollection<TLayout, TDevice>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableDeviceCollection<TLayout, TDevice> const& srcData) {
PortableHostCollection<TLayout> dstData(srcData->metadata().size(), queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};

template <typename TLayout>
struct CopyToDevice<PortableHostCollection<TLayout>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableHostCollection<TLayout> const& srcData) {
using TDevice = typename alpaka::trait::DevType<TQueue>::type;
PortableDeviceCollection<TLayout, TDevice> dstData(srcData->metadata().size(), queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};
} // namespace cms::alpakatools

#endif // DataFormats_Portable_interface_alpaka_PortableCollection_h
52 changes: 2 additions & 50 deletions DataFormats/Portable/interface/alpaka/PortableObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,18 @@
#include <alpaka/alpaka.hpp>

#include "DataFormats/Portable/interface/PortableObject.h"
#include "DataFormats/Portable/interface/PortableHostObject.h"
#include "DataFormats/Portable/interface/PortableDeviceObject.h"
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToDevice.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"

// This header is not used by PortableObject, but is included here to automatically
// provide its content to users of ALPAKA_ACCELERATOR_NAMESPACE::PortableObject.
#include "HeterogeneousCore/AlpakaInterface/interface/AssertDeviceMatchesHostCollection.h"

namespace ALPAKA_ACCELERATOR_NAMESPACE {

#if defined ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
// ... or any other CPU-based accelerators

// generic SoA-based product in host memory
template <typename T>
using PortableObject = ::PortableHostObject<T>;

#else

// generic SoA-based product in device memory
// generic struct-based product in the device (that may be host) memory
template <typename T>
using PortableObject = ::PortableDeviceObject<T, Device>;

#endif // ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
using PortableObject = ::PortableObject<T, Device>;

} // namespace ALPAKA_ACCELERATOR_NAMESPACE

namespace traits {

// specialise the trait for the device provided by the ALPAKA_ACCELERATOR_NAMESPACE
template <typename T>
class PortableObjectTrait<T, ALPAKA_ACCELERATOR_NAMESPACE::Device> {
using ProductType = ALPAKA_ACCELERATOR_NAMESPACE::PortableObject<T>;
};

} // namespace traits

namespace cms::alpakatools {
template <typename TProduct, typename TDevice>
struct CopyToHost<PortableDeviceObject<TProduct, TDevice>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableDeviceObject<TProduct, TDevice> const& srcData) {
PortableHostObject<TProduct> dstData(queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};

template <typename TProduct>
struct CopyToDevice<PortableHostObject<TProduct>> {
template <typename TQueue>
static auto copyAsync(TQueue& queue, PortableHostObject<TProduct> const& srcData) {
using TDevice = typename alpaka::trait::DevType<TQueue>::type;
PortableDeviceObject<TProduct, TDevice> dstData(queue);
alpaka::memcpy(queue, dstData.buffer(), srcData.buffer());
return dstData;
}
};
} // namespace cms::alpakatools

#endif // DataFormats_Portable_interface_alpaka_PortableObject_h
5 changes: 5 additions & 0 deletions DataFormats/Portable/test/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<bin name="TestDataFormatsPortableOnHost" file="test_catch2_main.cc,portableCollectionOnHost.cc,portableObjectOnHost.cc">
<use name="DataFormats/Portable"/>
<use name="DataFormats/SoATemplate"/>
<use name="catch2"/>
</bin>
25 changes: 25 additions & 0 deletions DataFormats/Portable/test/portableCollectionOnHost.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <catch.hpp>

#include "DataFormats/Portable/interface/PortableCollection.h"
#include "DataFormats/Portable/interface/PortableHostCollection.h"
#include "DataFormats/SoATemplate/interface/SoACommon.h"
#include "DataFormats/SoATemplate/interface/SoALayout.h"
#include "DataFormats/SoATemplate/interface/SoAView.h"

namespace {
GENERATE_SOA_LAYOUT(TestLayout, SOA_COLUMN(double, x), SOA_COLUMN(int32_t, id))

using TestSoA = TestLayout<>;

constexpr auto s_tag = "[PortableCollection]";
} // namespace

// This test is currently mostly about the code compiling
TEST_CASE("Use of PortableCollection<T, TDev> on host code", s_tag) {
auto const size = 10;
PortableCollection<TestSoA, alpaka::DevCpu> coll(size, cms::alpakatools::host());

SECTION("Tests") { REQUIRE(coll->metadata().size() == size); }

static_assert(std::is_same_v<PortableCollection<TestSoA, alpaka::DevCpu>, PortableHostCollection<TestSoA>>);
}
23 changes: 23 additions & 0 deletions DataFormats/Portable/test/portableObjectOnHost.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <catch.hpp>

#include "DataFormats/Portable/interface/PortableObject.h"
#include "DataFormats/Portable/interface/PortableHostObject.h"

namespace {
struct Test {
int a;
float b;
};

constexpr auto s_tag = "[PortableObject]";
} // namespace

// This test is currently mostly about the code compiling
TEST_CASE("Use of PortableObject<T> on host code", s_tag) {
PortableObject<Test, alpaka::DevCpu> obj(cms::alpakatools::host());
obj->a = 42;

SECTION("Tests") { REQUIRE(obj->a == 42); }

static_assert(std::is_same_v<PortableObject<Test, alpaka::DevCpu>, PortableHostObject<Test>>);
}
2 changes: 2 additions & 0 deletions DataFormats/Portable/test/test_catch2_main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>

0 comments on commit 1b67f09

Please sign in to comment.