diff --git a/DataFormats/EcalDigi/plugins/BuildFile.xml b/DataFormats/EcalDigi/plugins/BuildFile.xml
index 500770828ac90..c9beb08d7248a 100644
--- a/DataFormats/EcalDigi/plugins/BuildFile.xml
+++ b/DataFormats/EcalDigi/plugins/BuildFile.xml
@@ -3,3 +3,11 @@
+
+
+
+
+
+
+
+
diff --git a/DataFormats/EcalDigi/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/EcalDigi/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..af964aceaac7c
--- /dev/null
+++ b/DataFormats/EcalDigi/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,5 @@
+#include "DataFormats/EcalDigi/interface/alpaka/EcalDigiDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(EcalDigiDeviceCollection);
diff --git a/DataFormats/EcalRecHit/plugins/BuildFile.xml b/DataFormats/EcalRecHit/plugins/BuildFile.xml
index ee7c656ef4f71..071bf88e6de04 100644
--- a/DataFormats/EcalRecHit/plugins/BuildFile.xml
+++ b/DataFormats/EcalRecHit/plugins/BuildFile.xml
@@ -3,3 +3,11 @@
+
+
+
+
+
+
+
+
diff --git a/DataFormats/EcalRecHit/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/EcalRecHit/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..f5efded924487
--- /dev/null
+++ b/DataFormats/EcalRecHit/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,5 @@
+#include "DataFormats/EcalRecHit/interface/alpaka/EcalUncalibratedRecHitDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(EcalUncalibratedRecHitDeviceCollection);
diff --git a/DataFormats/HcalRecHit/plugins/BuildFile.xml b/DataFormats/HcalRecHit/plugins/BuildFile.xml
index 07725848fdb30..c50aaad71fc44 100644
--- a/DataFormats/HcalRecHit/plugins/BuildFile.xml
+++ b/DataFormats/HcalRecHit/plugins/BuildFile.xml
@@ -3,3 +3,13 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/HcalRecHit/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/HcalRecHit/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..8a2ba97f1751b
--- /dev/null
+++ b/DataFormats/HcalRecHit/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,5 @@
+#include "DataFormats/HcalRecHit/interface/alpaka/HcalRecHitDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(hcal::RecHitDeviceCollection);
diff --git a/DataFormats/ParticleFlowReco/plugins/BuildFile.xml b/DataFormats/ParticleFlowReco/plugins/BuildFile.xml
index e20859b77da70..cd269d52304ed 100644
--- a/DataFormats/ParticleFlowReco/plugins/BuildFile.xml
+++ b/DataFormats/ParticleFlowReco/plugins/BuildFile.xml
@@ -3,3 +3,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/ParticleFlowReco/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/ParticleFlowReco/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..895f83585b52a
--- /dev/null
+++ b/DataFormats/ParticleFlowReco/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,11 @@
+#include
+
+#include "DataFormats/ParticleFlowReco/interface/alpaka/PFClusterDeviceCollection.h"
+#include "DataFormats/ParticleFlowReco/interface/alpaka/PFRecHitDeviceCollection.h"
+#include "DataFormats/ParticleFlowReco/interface/alpaka/PFRecHitFractionDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(reco::PFRecHitDeviceCollection);
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(reco::PFClusterDeviceCollection);
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(reco::PFRecHitFractionDeviceCollection);
diff --git a/DataFormats/Portable/interface/PortableDeviceCollection.h b/DataFormats/Portable/interface/PortableDeviceCollection.h
index ec357e8ecdcc0..ead1773e0068c 100644
--- a/DataFormats/Portable/interface/PortableDeviceCollection.h
+++ b/DataFormats/Portable/interface/PortableDeviceCollection.h
@@ -12,6 +12,7 @@
#include "DataFormats/Common/interface/Uninitialized.h"
#include "DataFormats/Portable/interface/PortableCollectionCommon.h"
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
#include "HeterogeneousCore/AlpakaInterface/interface/memory.h"
@@ -146,4 +147,39 @@ class PortableDeviceCollection {
View view_; //!
};
+namespace ngt {
+
+ // Specialize MemoryCopyTraits for PortableDeviceCollection
+ template
+ struct MemoryCopyTraits> {
+ using value_type = PortableDeviceCollection;
+
+ // Properties are the collection size: T::size_type, or std::array for SoABlocks.
+ using Properties = decltype(std::declval()->metadata().size());
+
+ static Properties properties(value_type const& object) { return object->metadata().size(); }
+
+ template
+ static void initialize(TQueue& queue, value_type& object, Properties const& size)
+ requires(alpaka::isQueue)
+ {
+ // Replace the default-constructed empty object with one where the buffer
+ // has been allocated in global device memory
+ object = value_type(queue, size);
+ }
+
+ static std::vector> regions(value_type& object) {
+ std::byte* address = reinterpret_cast(object.buffer().data());
+ size_t size = alpaka::getExtentProduct(object.buffer());
+ return {{address, size}};
+ }
+
+ static std::vector> regions(value_type const& object) {
+ const std::byte* address = reinterpret_cast(object.buffer().data());
+ size_t size = alpaka::getExtentProduct(object.buffer());
+ return {{address, size}};
+ }
+ };
+} // namespace ngt
+
#endif // DataFormats_Portable_interface_PortableDeviceCollection_h
diff --git a/DataFormats/Portable/interface/PortableDeviceObject.h b/DataFormats/Portable/interface/PortableDeviceObject.h
index 5cbd139a59752..4618c2d26eb95 100644
--- a/DataFormats/Portable/interface/PortableDeviceObject.h
+++ b/DataFormats/Portable/interface/PortableDeviceObject.h
@@ -8,6 +8,7 @@
#include
#include "DataFormats/Common/interface/Uninitialized.h"
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
#include "HeterogeneousCore/AlpakaInterface/interface/memory.h"
@@ -80,4 +81,28 @@ class PortableDeviceObject {
std::optional buffer_;
};
+namespace ngt {
+
+ // Specialize MemoryCopyTraits for PortableDeviceObject
+ template
+ struct MemoryCopyTraits> {
+ template
+ requires(alpaka::isQueue)
+ static void initialize(TQueue& queue, PortableDeviceObject& object) {
+ // Replace the default-constructed empty object with one where the
+ // buffer has been allocated in global device memory
+ object = PortableDeviceObject(queue);
+ }
+
+ static std::vector> regions(PortableDeviceObject& object) {
+ return {{reinterpret_cast(object.data()), sizeof(T)}};
+ }
+
+ static std::vector> regions(PortableDeviceObject const& object) {
+ return {{reinterpret_cast(object.data()), sizeof(T)}};
+ }
+ };
+
+} // namespace ngt
+
#endif // DataFormats_Portable_interface_PortableDeviceObject_h
diff --git a/DataFormats/Portable/interface/PortableHostCollection.h b/DataFormats/Portable/interface/PortableHostCollection.h
index c793fbf6d87fb..52c7c1720b660 100644
--- a/DataFormats/Portable/interface/PortableHostCollection.h
+++ b/DataFormats/Portable/interface/PortableHostCollection.h
@@ -200,8 +200,17 @@ namespace ngt {
// The properties needed to initialize a new PrortableHostCollection are just its size.
static Properties properties(value_type const& object) { return object->metadata().size(); }
- // Replace the default-constructed empty object with one where the buffer has been allocated in pageable system memory.
+ template
+ requires(alpaka::isQueue)
+ static void initialize(TQueue& queue, value_type& object, Properties const& size) {
+ // Replace the default-constructed empty object with one where the buffer
+ // has been allocated in pinned host memory.
+ object = value_type(queue, size);
+ }
+
static void initialize(value_type& object, Properties const& size) {
+ // Replace the default-constructed empty object with one where the buffer
+ // has been allocated in pageable host memory.
object = value_type(cms::alpakatools::host(), size);
}
diff --git a/DataFormats/Portable/interface/PortableHostObject.h b/DataFormats/Portable/interface/PortableHostObject.h
index 1c39278be414b..48cba17f51662 100644
--- a/DataFormats/Portable/interface/PortableHostObject.h
+++ b/DataFormats/Portable/interface/PortableHostObject.h
@@ -121,11 +121,21 @@ namespace ngt {
template
struct MemoryCopyTraits> {
- // This specialisation requires a initialize() method, but does not need to pass any parameters to it.
+ // This specialisation requires an initialize() method, but does not need to
+ // pass any parameters to it.
using Properties = void;
+ template
+ requires(alpaka::isQueue)
+ static void initialize(TQueue& queue, PortableHostObject& object) {
+ // Replace the default-constructed empty object with one where the buffer
+ // has been allocated in pinned host memory
+ object = PortableHostObject(queue);
+ }
+
static void initialize(PortableHostObject& object) {
- // Replace the default-constructed empty object with one where the buffer has been allocated in pageable system memory.
+ // Replace the default-constructed empty object with one where the buffer
+ // has been allocated in pageable host memory.
object = PortableHostObject(cms::alpakatools::host());
}
diff --git a/DataFormats/PortableTestObjects/plugins/BuildFile.xml b/DataFormats/PortableTestObjects/plugins/BuildFile.xml
index bac81f07c93fc..f7eb9c2ad95d7 100644
--- a/DataFormats/PortableTestObjects/plugins/BuildFile.xml
+++ b/DataFormats/PortableTestObjects/plugins/BuildFile.xml
@@ -3,3 +3,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/PortableTestObjects/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/PortableTestObjects/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..18e1114b1f4b8
--- /dev/null
+++ b/DataFormats/PortableTestObjects/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,9 @@
+#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h"
+#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(portabletest::TestDeviceCollection);
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(portabletest::TestDeviceCollection2);
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(portabletest::TestDeviceCollection3);
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(portabletest::TestDeviceObject);
diff --git a/DataFormats/TrackSoA/plugins/BuildFile.xml b/DataFormats/TrackSoA/plugins/BuildFile.xml
index e2d5a430d6ae4..b7d65dcb63c60 100644
--- a/DataFormats/TrackSoA/plugins/BuildFile.xml
+++ b/DataFormats/TrackSoA/plugins/BuildFile.xml
@@ -3,3 +3,11 @@
+
+
+
+
+
+
+
+
diff --git a/DataFormats/TrackSoA/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/TrackSoA/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..a96727d3e3486
--- /dev/null
+++ b/DataFormats/TrackSoA/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,5 @@
+#include "DataFormats/TrackSoA/interface/alpaka/TracksSoACollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(reco::TracksSoACollection);
diff --git a/DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h b/DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h
index 57f2511b72d7a..e56b6a0e9fdb9 100644
--- a/DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h
+++ b/DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h
@@ -54,36 +54,38 @@ namespace ngt {
// Checks if the properties method is defined
template
- concept HasTrivialCopyProperties = requires(T const& object) { MemoryCopyTraits::properties(object); };
+ concept HasTrivialCopyProperties = requires(T const& object) { ngt::MemoryCopyTraits::properties(object); };
// Get the return type of properties(...), if it exists.
template
- requires HasTrivialCopyProperties
- using TrivialCopyProperties = decltype(MemoryCopyTraits::properties(std::declval()));
+ requires ngt::HasTrivialCopyProperties
+ using TrivialCopyProperties = decltype(ngt::MemoryCopyTraits::properties(std::declval()));
// Checks if the declaration of initialize(...) is consistent with the presence or absence of properties.
template
concept HasValidInitialize =
// does not have properties(...) and initialize(object) takes a single argument, or
- (not HasTrivialCopyProperties and requires(T& object) { MemoryCopyTraits::initialize(object); }) or
+ (not ngt::HasTrivialCopyProperties and
+ requires(T& object) { ngt::MemoryCopyTraits::initialize(object); }) or
// does have properties(...) and initialize(object, props) takes two arguments
- (HasTrivialCopyProperties and
- requires(T& object, TrivialCopyProperties props) { MemoryCopyTraits::initialize(object, props); });
+ (ngt::HasTrivialCopyProperties and requires(T& object, ngt::TrivialCopyProperties props) {
+ ngt::MemoryCopyTraits::initialize(object, props);
+ });
// Checks for const and non const memory regions
template
concept HasRegions = requires(T& object, T const& const_object) {
- MemoryCopyTraits::regions(object);
- MemoryCopyTraits::regions(const_object);
+ ngt::MemoryCopyTraits::regions(object);
+ ngt::MemoryCopyTraits::regions(const_object);
};
// Checks if there is a valid specialisation of MemoryCopyTraits for a type T
template
concept HasMemoryCopyTraits =
// Has memory regions declared and
- (HasRegions) and
+ (ngt::HasRegions) and
// has either no initialize(...) or a valid one
- (not requires { &MemoryCopyTraits::initialize; } or HasValidInitialize);
+ (not requires { &ngt::MemoryCopyTraits::initialize; } or ngt::HasValidInitialize);
// Checks if finalize(...) is defined
template
diff --git a/DataFormats/TrivialSerialisation/test/BuildFile.xml b/DataFormats/TrivialSerialisation/test/BuildFile.xml
index 5da9ef00be32e..1ffe7d7e317ff 100644
--- a/DataFormats/TrivialSerialisation/test/BuildFile.xml
+++ b/DataFormats/TrivialSerialisation/test/BuildFile.xml
@@ -2,3 +2,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/TrivialSerialisation/test/alpaka/test_catch2_MemoryCopyTraitsPortable.dev.cc b/DataFormats/TrivialSerialisation/test/alpaka/test_catch2_MemoryCopyTraitsPortable.dev.cc
new file mode 100644
index 0000000000000..0ba52aee959e9
--- /dev/null
+++ b/DataFormats/TrivialSerialisation/test/alpaka/test_catch2_MemoryCopyTraitsPortable.dev.cc
@@ -0,0 +1,363 @@
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+#include "DataFormats/Portable/interface/PortableCollection.h"
+#include "DataFormats/Portable/interface/PortableHostCollection.h"
+#include "DataFormats/Portable/interface/PortableHostObject.h"
+#include "DataFormats/PortableTestObjects/interface/TestSoA.h"
+#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h"
+#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h"
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+
+using namespace ALPAKA_ACCELERATOR_NAMESPACE;
+namespace alpaka_portable_test = ALPAKA_ACCELERATOR_NAMESPACE::portabletest;
+
+/*
+ * Catch2 tests for MemoryCopyTraits specializations of portable types.
+ *
+ * This test verifies that:
+ * - PortableHostCollection has valid MemoryCopyTraits with Properties and initialize()
+ * - PortableHostObject has valid MemoryCopyTraits with initialize() but no Properties
+ * - PortableDeviceCollection has valid MemoryCopyTraits with Properties and initialize()
+ * - PortableDeviceObject has valid MemoryCopyTraits with initialize() but no Properties
+ * - Multi-block collections (SoABlocks2, SoABlocks3) have valid MemoryCopyTraits
+ *
+ * It also tests that data can be correctly copied using the MemoryCopyTraits interface
+ * for both host and device portable types.
+ */
+
+TEST_CASE("Test MemoryCopyTraits with portable types", "[MemoryCopyTraits][Portable]") {
+ auto const& devices = cms::alpakatools::devices();
+ if (devices.empty()) {
+ FAIL("No devices available for the " EDM_STRINGIZE(ALPAKA_ACCELERATOR_NAMESPACE) " backend");
+ }
+
+ SECTION("PortableHostCollection checks") {
+ using HostCollectionType = PortableHostCollection>;
+
+ // PortableHostCollection should have MemoryCopyTraits
+ static_assert(::ngt::HasMemoryCopyTraits);
+ // It should have Properties (the size)
+ static_assert(::ngt::HasTrivialCopyProperties);
+ // It should have a valid initialize()
+ static_assert(::ngt::HasValidInitialize);
+ // It should have regions
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("PortableHostObject checks") {
+ using HostObjectType = PortableHostObject;
+
+ // PortableHostObject should have MemoryCopyTraits
+ static_assert(::ngt::HasMemoryCopyTraits);
+ // It should not have Properties
+ static_assert(not ::ngt::HasTrivialCopyProperties);
+ // It should have regions
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("PortableDeviceCollection checks") {
+ using DeviceCollectionType = alpaka_portable_test::TestDeviceCollection;
+
+ // PortableDeviceCollection should have MemoryCopyTraits
+ static_assert(::ngt::HasMemoryCopyTraits);
+ // It should have Properties (the size)
+ static_assert(::ngt::HasTrivialCopyProperties);
+ // It should have regions
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("PortableDeviceObject checks") {
+ using DeviceObjectType = alpaka_portable_test::TestDeviceObject;
+
+ // PortableDeviceObject should have MemoryCopyTraits
+ static_assert(::ngt::HasMemoryCopyTraits);
+ // It should not have Properties
+ static_assert(not ::ngt::HasTrivialCopyProperties);
+ // It should have regions
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("Multi-block PortableHostCollection checks") {
+ // SoABlocks2
+ using HostCollection2Type = PortableHostCollection;
+ static_assert(::ngt::HasMemoryCopyTraits);
+ static_assert(::ngt::HasTrivialCopyProperties);
+ static_assert(::ngt::HasRegions);
+
+ // SoABlocks3
+ using HostCollection3Type = PortableHostCollection;
+ static_assert(::ngt::HasMemoryCopyTraits);
+ static_assert(::ngt::HasTrivialCopyProperties);
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("Multi-block PortableDeviceCollection checks") {
+ using DeviceCollection2Type = alpaka_portable_test::TestDeviceCollection2;
+ static_assert(::ngt::HasMemoryCopyTraits);
+ static_assert(::ngt::HasTrivialCopyProperties);
+ static_assert(::ngt::HasRegions);
+
+ using DeviceCollection3Type = alpaka_portable_test::TestDeviceCollection3;
+ static_assert(::ngt::HasMemoryCopyTraits);
+ static_assert(::ngt::HasTrivialCopyProperties);
+ static_assert(::ngt::HasRegions);
+ }
+
+ SECTION("PortableHostCollection copy via MemoryCopyTraits") {
+ using HostCollectionType = PortableHostCollection>;
+ const int size = 10;
+
+ for (auto const& device : devices) {
+ Queue queue(device);
+
+ // Create a source collection and fill it with data
+ HostCollectionType source(queue, size);
+ source.view().r() = 3.14;
+ for (int i = 0; i < size; i++) {
+ source.view()[i].x() = i * 10.0 + 1;
+ source.view()[i].y() = i * 10.0 + 2;
+ source.view()[i].z() = i * 10.0 + 3;
+ source.view()[i].id() = i;
+ source.view()[i].flags() = std::array{
+ {static_cast(i), static_cast(i + 1), static_cast(i + 2), static_cast(i + 3)}};
+ source.view()[i].m = Eigen::Matrix::Identity() * i;
+ }
+
+ // Get properties from source
+ auto props = ::ngt::MemoryCopyTraits::properties(source);
+ REQUIRE(props == size);
+
+ // Create a clone and initialize it
+ HostCollectionType clone(edm::kUninitialized);
+ ::ngt::MemoryCopyTraits::initialize(clone, props);
+
+ // Get regions and copy
+ auto sources_regions = ::ngt::MemoryCopyTraits::regions(std::as_const(source));
+ auto targets_regions = ::ngt::MemoryCopyTraits::regions(clone);
+
+ REQUIRE(sources_regions.size() == targets_regions.size());
+ REQUIRE(sources_regions.size() == 1);
+ REQUIRE(sources_regions[0].size_bytes() == targets_regions[0].size_bytes());
+
+ std::memcpy(targets_regions[0].data(), sources_regions[0].data(), sources_regions[0].size_bytes());
+
+ // Verify clone
+ REQUIRE(clone.const_view().r() == source.const_view().r());
+ for (int i = 0; i < size; i++) {
+ REQUIRE(clone.const_view()[i].x() == source.const_view()[i].x());
+ REQUIRE(clone.const_view()[i].y() == source.const_view()[i].y());
+ REQUIRE(clone.const_view()[i].z() == source.const_view()[i].z());
+ REQUIRE(clone.const_view()[i].id() == source.const_view()[i].id());
+ REQUIRE(clone.const_view()[i].flags() == source.const_view()[i].flags());
+ REQUIRE(clone.const_view()[i].m() == source.const_view()[i].m());
+ }
+ }
+ }
+
+ SECTION("PortableHostObject copy via MemoryCopyTraits") {
+ using HostObjectType = PortableHostObject;
+
+ for (auto const& device : devices) {
+ Queue queue(device);
+
+ // Create source object
+ HostObjectType source(cms::alpakatools::host());
+ source->x = 5.0;
+ source->y = 12.0;
+ source->z = 13.0;
+ source->id = 42;
+
+ // Create an uninitialized clone
+ HostObjectType clone(edm::kUninitialized);
+ ::ngt::MemoryCopyTraits::initialize(clone);
+
+ // Get regions and copy
+ auto sources_regions = ::ngt::MemoryCopyTraits::regions(std::as_const(source));
+ auto targets_regions = ::ngt::MemoryCopyTraits::regions(clone);
+
+ REQUIRE(sources_regions.size() == targets_regions.size());
+ REQUIRE(sources_regions.size() == 1);
+ REQUIRE(sources_regions[0].size_bytes() == sizeof(alpaka_portable_test::TestStruct));
+ REQUIRE(targets_regions[0].size_bytes() == sizeof(alpaka_portable_test::TestStruct));
+
+ std::memcpy(targets_regions[0].data(), sources_regions[0].data(), sources_regions[0].size_bytes());
+
+ // Verify clone
+ REQUIRE(clone->x == 5.0);
+ REQUIRE(clone->y == 12.0);
+ REQUIRE(clone->z == 13.0);
+ REQUIRE(clone->id == 42);
+ }
+ }
+
+ SECTION("PortableDeviceCollection copy via MemoryCopyTraits") {
+ using DeviceCollectionType = alpaka_portable_test::TestDeviceCollection;
+ using HostCollectionType = PortableHostCollection>;
+ const int size = 10;
+
+ for (auto const& device : devices) {
+ Queue queue(device);
+
+ // Create a reference host collection with known data
+ HostCollectionType refHost(queue, size);
+ refHost.view().r() = 2.71;
+ for (int i = 0; i < size; i++) {
+ refHost.view()[i].x() = i * 100.0;
+ refHost.view()[i].y() = i * 200.0;
+ refHost.view()[i].z() = i * 300.0;
+ refHost.view()[i].id() = i + 100;
+ refHost.view()[i].flags() = std::array{
+ {static_cast(i), static_cast(i + 1), static_cast(i + 2), static_cast(i + 3)}};
+ refHost.view()[i].m = Eigen::Matrix::Identity() * i;
+ }
+
+ // Create a device collection and copy the reference data to it
+ DeviceCollectionType source(queue, size);
+ alpaka::memcpy(queue, source.buffer(), refHost.buffer());
+ alpaka::wait(queue);
+
+ // Get properties
+ auto props = ::ngt::MemoryCopyTraits::properties(source);
+ REQUIRE(props == size);
+
+ // Create a clone on device
+ DeviceCollectionType clone(edm::kUninitialized);
+ ::ngt::MemoryCopyTraits::initialize(queue, clone, props);
+
+ // Get regions and copy (device-to-device via alpaka)
+ auto sources_regions = ::ngt::MemoryCopyTraits::regions(std::as_const(source));
+ auto targets_regions = ::ngt::MemoryCopyTraits::regions(clone);
+
+ REQUIRE(sources_regions.size() == targets_regions.size());
+ for (size_t i = 0; i < sources_regions.size(); ++i) {
+ REQUIRE(sources_regions[i].size_bytes() == targets_regions[i].size_bytes());
+ auto src_view = alpaka::createView(device, sources_regions[i].data(), sources_regions[i].size_bytes());
+ auto trg_view = alpaka::createView(device, targets_regions[i].data(), targets_regions[i].size_bytes());
+ alpaka::memcpy(queue, trg_view, src_view);
+ }
+ alpaka::wait(queue);
+
+ // Copy the clone back to host to verify
+ HostCollectionType verifyHost(queue, size);
+ alpaka::memcpy(queue, verifyHost.buffer(), clone.buffer());
+ alpaka::wait(queue);
+
+ REQUIRE(verifyHost.const_view().r() == refHost.const_view().r());
+ for (int i = 0; i < size; i++) {
+ REQUIRE(verifyHost.const_view()[i].x() == refHost.const_view()[i].x());
+ REQUIRE(verifyHost.const_view()[i].y() == refHost.const_view()[i].y());
+ REQUIRE(verifyHost.const_view()[i].z() == refHost.const_view()[i].z());
+ REQUIRE(verifyHost.const_view()[i].id() == refHost.const_view()[i].id());
+ REQUIRE(verifyHost.const_view()[i].flags() == refHost.const_view()[i].flags());
+ }
+ }
+ }
+
+ SECTION("PortableDeviceObject copy via MemoryCopyTraits") {
+ using DeviceObjectType = alpaka_portable_test::TestDeviceObject;
+
+ for (auto const& device : devices) {
+ Queue queue(device);
+
+ // Create source object on host, copy to device
+ PortableHostObject hostSource(queue);
+ hostSource->x = 1.0;
+ hostSource->y = 2.0;
+ hostSource->z = 3.0;
+ hostSource->id = 99;
+
+ DeviceObjectType source(queue);
+ alpaka::memcpy(queue, source.buffer(), hostSource.buffer());
+ alpaka::wait(queue);
+
+ // Create an uninitialized clone
+ DeviceObjectType clone(edm::kUninitialized);
+ ::ngt::MemoryCopyTraits::initialize(queue, clone);
+
+ // Get regions and copy
+ auto sources_regions = ::ngt::MemoryCopyTraits::regions(std::as_const(source));
+ auto targets_regions = ::ngt::MemoryCopyTraits::regions(clone);
+
+ REQUIRE(sources_regions.size() == 1);
+ REQUIRE(targets_regions.size() == 1);
+ REQUIRE(sources_regions[0].size_bytes() == sizeof(alpaka_portable_test::TestStruct));
+
+ auto src_view = alpaka::createView(device, sources_regions[0].data(), sources_regions[0].size_bytes());
+ auto trg_view = alpaka::createView(device, targets_regions[0].data(), targets_regions[0].size_bytes());
+ alpaka::memcpy(queue, trg_view, src_view);
+ alpaka::wait(queue);
+
+ // Copy clone back to host and verify
+ PortableHostObject hostClone(queue);
+ alpaka::memcpy(queue, hostClone.buffer(), clone.buffer());
+ alpaka::wait(queue);
+
+ REQUIRE(hostClone->x == 1.0);
+ REQUIRE(hostClone->y == 2.0);
+ REQUIRE(hostClone->z == 3.0);
+ REQUIRE(hostClone->id == 99);
+ }
+ }
+
+ SECTION("Multi-block PortableHostCollection copy via MemoryCopyTraits") {
+ using HostCollection2Type = PortableHostCollection;
+ const int size1 = 8;
+ const int size2 = 12;
+
+ for (auto const& device : devices) {
+ Queue queue(device);
+
+ // Create source with two blocks
+ HostCollection2Type source(queue, size1, size2);
+ source.view().first().r() = 1.23;
+ source.view().second().r2() = 4.56;
+ for (int i = 0; i < size1; i++) {
+ source.view().first()[i].x() = i * 1.0;
+ source.view().first()[i].id() = i;
+ }
+ for (int i = 0; i < size2; i++) {
+ source.view().second()[i].x2() = i * 2.0;
+ source.view().second()[i].id2() = i + 100;
+ }
+
+ // Get properties
+ auto props = ::ngt::MemoryCopyTraits::properties(source);
+ REQUIRE(props[0] == size1);
+ REQUIRE(props[1] == size2);
+
+ // Create clone and initialize
+ HostCollection2Type clone(edm::kUninitialized);
+ ::ngt::MemoryCopyTraits::initialize(clone, props);
+
+ // Copy regions
+ auto sources_regions = ::ngt::MemoryCopyTraits::regions(std::as_const(source));
+ auto targets_regions = ::ngt::MemoryCopyTraits::regions(clone);
+
+ REQUIRE(sources_regions.size() == targets_regions.size());
+ for (size_t i = 0; i < sources_regions.size(); ++i) {
+ REQUIRE(sources_regions[i].size_bytes() == targets_regions[i].size_bytes());
+ std::memcpy(targets_regions[i].data(), sources_regions[i].data(), sources_regions[i].size_bytes());
+ }
+
+ // Verify
+ REQUIRE(clone.const_view().first().r() == 1.23);
+ REQUIRE(clone.const_view().second().r2() == 4.56);
+ for (int i = 0; i < size1; i++) {
+ REQUIRE(clone.const_view().first()[i].x() == i * 1.0);
+ REQUIRE(clone.const_view().first()[i].id() == i);
+ }
+ for (int i = 0; i < size2; i++) {
+ REQUIRE(clone.const_view().second()[i].x2() == i * 2.0);
+ REQUIRE(clone.const_view().second()[i].id2() == i + 100);
+ }
+ }
+ }
+}
diff --git a/DataFormats/VertexSoA/plugins/BuildFile.xml b/DataFormats/VertexSoA/plugins/BuildFile.xml
index 9967a9fbb7ed1..f42c0ddcc28e9 100644
--- a/DataFormats/VertexSoA/plugins/BuildFile.xml
+++ b/DataFormats/VertexSoA/plugins/BuildFile.xml
@@ -3,3 +3,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/VertexSoA/plugins/alpaka/TrivialSerialisation.cc b/DataFormats/VertexSoA/plugins/alpaka/TrivialSerialisation.cc
new file mode 100644
index 0000000000000..51637655ce1a3
--- /dev/null
+++ b/DataFormats/VertexSoA/plugins/alpaka/TrivialSerialisation.cc
@@ -0,0 +1,5 @@
+#include "DataFormats/VertexSoA/interface/alpaka/ZVertexSoACollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h"
+
+DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(reco::ZVertexSoACollection);
diff --git a/HeterogeneousCore/TrivialSerialisation/BuildFile.xml b/HeterogeneousCore/TrivialSerialisation/BuildFile.xml
index 6eeacf9dd884c..d7bfd7e7d5267 100644
--- a/HeterogeneousCore/TrivialSerialisation/BuildFile.xml
+++ b/HeterogeneousCore/TrivialSerialisation/BuildFile.xml
@@ -1,7 +1,11 @@
+
+
+
+
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/Common.h b/HeterogeneousCore/TrivialSerialisation/interface/Common.h
new file mode 100644
index 0000000000000..7a04a21926958
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/Common.h
@@ -0,0 +1,51 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_Common_h
+#define HeterogeneousCore_TrivialSerialisation_interface_Common_h
+
+#include
+#include
+#include
+
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/AnyBuffer.h"
+
+namespace ngt {
+
+ // Helper functions used by both the alpaka and non-alpaka variants of the
+ // Reader and Writer.
+
+ // Return the TrivialCopyProperties for an object, wrapped in an AnyBuffer.
+ // Returns an empty AnyBuffer if MemoryCopyTraits has no properties().
+ template
+ ngt::AnyBuffer get_properties(T const& obj) {
+ if constexpr (not ngt::HasTrivialCopyProperties) {
+ return {};
+ } else {
+ return ngt::AnyBuffer(ngt::MemoryCopyTraits::properties(obj));
+ }
+ }
+
+ // Return the memory regions of an object (mutable)
+ template
+ std::vector> get_regions(T& obj) {
+ static_assert(ngt::HasRegions);
+ return ngt::MemoryCopyTraits::regions(obj);
+ }
+
+ // Return the memory regions of an object (const)
+ template
+ std::vector> get_regions(T const& obj) {
+ static_assert(ngt::HasRegions);
+ return ngt::MemoryCopyTraits::regions(obj);
+ }
+
+ // Call finalize() on an object, if MemoryCopyTraits provides it
+ template
+ void do_finalize(T& obj) {
+ if constexpr (ngt::HasTrivialCopyFinalize) {
+ ngt::MemoryCopyTraits::finalize(obj);
+ }
+ }
+
+} // namespace ngt
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_Common_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/Reader.h b/HeterogeneousCore/TrivialSerialisation/interface/Reader.h
index d358dd9f560bf..c8d26e49ab333 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/Reader.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/Reader.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_Reader_h
-#define TrivialSerialisation_Common_interface_Reader_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_Reader_h
+#define HeterogeneousCore_TrivialSerialisation_interface_Reader_h
#include
#include
@@ -9,10 +9,12 @@
#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "HeterogeneousCore/TrivialSerialisation/interface/AnyBuffer.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/Common.h"
#include "HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h"
namespace ngt {
+ // Reader for host products: extracts properties and memory regions from a Wrapper.
template
class Reader : public ReaderBase {
static_assert(ngt::HasMemoryCopyTraits, "No specialization of MemoryCopyTraits found for type T");
@@ -20,22 +22,11 @@ namespace ngt {
public:
using WrapperType = edm::Wrapper;
- Reader(WrapperType const& wrapper) : ReaderBase(&wrapper) {}
+ explicit Reader(WrapperType const& wrapper) : ReaderBase(&wrapper) {}
- ngt::AnyBuffer parameters() const override {
- if constexpr (not ngt::HasTrivialCopyProperties) {
- // if ngt::MemoryCopyTraits::properties(...) is not declared, do not call it.
- return {};
- } else {
- // if ngt::MemoryCopyTraits::properties(...) is declared, call it and wrap the result in an ngt::AnyBuffer
- return ngt::AnyBuffer(ngt::MemoryCopyTraits::properties(object()));
- }
- }
+ ngt::AnyBuffer parameters() const override { return ngt::get_properties(object()); }
- std::vector> regions() const override {
- static_assert(ngt::HasRegions);
- return ngt::MemoryCopyTraits::regions(object());
- }
+ std::vector> regions() const override { return ngt::get_regions(object()); }
private:
const T& object() const {
@@ -49,4 +40,4 @@ namespace ngt {
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_Reader_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_Reader_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h b/HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h
index f3c871bdbd969..51f6d4dbf384f 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_ReaderBase_h
-#define TrivialSerialisation_Common_interface_ReaderBase_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_ReaderBase_h
+#define HeterogeneousCore_TrivialSerialisation_interface_ReaderBase_h
#include
#include
@@ -10,6 +10,7 @@
namespace ngt {
+ // Base class for reading the memory regions and properties of a serialised product.
class ReaderBase {
public:
ReaderBase(const edm::WrapperBase* ptr) : ptr_(ptr) {}
@@ -25,4 +26,4 @@ namespace ngt {
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_ReaderBase_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_ReaderBase_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h b/HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h
index 06049244ec292..ba30ed0e79c34 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_Serialiser_h
-#define TrivialSerialisation_Common_interface_Serialiser_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_Serialiser_h
+#define HeterogeneousCore_TrivialSerialisation_interface_Serialiser_h
#include
@@ -13,6 +13,7 @@
namespace ngt {
+ // Concrete Serialiser for host products. T is the bare product type (not wrapped).
template
class Serialiser : public SerialiserBase {
public:
@@ -26,4 +27,4 @@ namespace ngt {
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_Serialiser_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_Serialiser_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h b/HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h
index 35fb99273e8a5..90db52e6a3293 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_SerialiserBase_h
-#define TrivialSerialisation_Common_interface_SerialiserBase_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_SerialiserBase_h
+#define HeterogeneousCore_TrivialSerialisation_interface_SerialiserBase_h
#include
@@ -8,6 +8,8 @@
#include "HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h"
namespace ngt {
+
+ // Abstract factory interface for creating Readers and Writers for host products.
class SerialiserBase {
public:
virtual std::unique_ptr writer() = 0;
@@ -17,4 +19,4 @@ namespace ngt {
};
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_SerialiserBase_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_SerialiserBase_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/SerialiserFactory.h b/HeterogeneousCore/TrivialSerialisation/interface/SerialiserFactory.h
index e927bfe643c94..f675c5dbcb173 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/SerialiserFactory.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/SerialiserFactory.h
@@ -1,16 +1,23 @@
-#ifndef TrivialSerialisation_src_SerialiserFactory_h
-#define TrivialSerialisation_src_SerialiserFactory_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_SerialiserFactory_h
+#define HeterogeneousCore_TrivialSerialisation_interface_SerialiserFactory_h
-#include "HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h"
-#include "HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h"
#include "FWCore/PluginManager/interface/PluginFactory.h"
+#include "FWCore/Utilities/interface/stringize.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/Serialiser.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/SerialiserBase.h"
namespace ngt {
+ // Plugin factory for host-product Serialisers, keyed by typeid name.
using SerialiserFactory = edmplugin::PluginFactory;
-}
+} // namespace ngt
-// Helper macro to define Serialiser plugins
-#define DEFINE_TRIVIAL_SERIALISER_PLUGIN(TYPE) \
- DEFINE_EDM_PLUGIN(ngt::SerialiserFactory, ngt::Serialiser, typeid(TYPE).name())
+// Register a Serialiser plugin for a host product type.
+//
+// The plugin is registered under both the mangled typeid name and
+// EDM_STRINGIZE(TYPE). EDM_STRINGIZE(TYPE) is more human-readable, and thus
+// more suitable for Python configuration files.
+#define DEFINE_TRIVIAL_SERIALISER_PLUGIN(TYPE) \
+ DEFINE_EDM_PLUGIN(ngt::SerialiserFactory, ngt::Serialiser, typeid(TYPE).name()); \
+ DEFINE_EDM_PLUGIN2(ngt::SerialiserFactory, ngt::Serialiser, EDM_STRINGIZE(TYPE))
-#endif // TrivialSerialisation_src_SerialiserFactory_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_SerialiserFactory_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/Writer.h b/HeterogeneousCore/TrivialSerialisation/interface/Writer.h
index d4bfc4b7cad22..784ff212f7eb4 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/Writer.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/Writer.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_Writer_h
-#define TrivialSerialisation_Common_interface_Writer_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_Writer_h
+#define HeterogeneousCore_TrivialSerialisation_interface_Writer_h
#include
#include
@@ -8,10 +8,12 @@
#include "DataFormats/Common/interface/Wrapper.h"
#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
#include "HeterogeneousCore/TrivialSerialisation/interface/AnyBuffer.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/Common.h"
#include "HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h"
namespace ngt {
+ // Writer for host products: creates a Wrapper and exposes its memory regions for writing.
template
class Writer : public WriterBase {
static_assert(ngt::HasMemoryCopyTraits, "No specialization of MemoryCopyTraits found for type T");
@@ -28,39 +30,24 @@ namespace ngt {
}
}
- ngt::AnyBuffer uninitialized_parameters() const override {
- if constexpr (not ngt::HasTrivialCopyProperties) {
- // if ngt::MemoryCopyTraits::properties(...) is not declared, do not call it.
- return {};
- } else {
- // if ngt::MemoryCopyTraits::properties(...) is declared, call it and wrap the result in an ngt::AnyBuffer
- return ngt::AnyBuffer(ngt::MemoryCopyTraits::properties(object()));
- }
- }
+ ngt::AnyBuffer uninitialized_parameters() const override { return ngt::get_properties(object()); }
void initialize(ngt::AnyBuffer const& args) override {
if constexpr (not ngt::HasValidInitialize) {
- // If there is no valid initialize(), this shouldn't be present.
+ // if MemoryCopyTraits has no valid initialize(), then the object must be
+ // default-constructible, and thus there is nothing to initialize. Just check
+ // that properties are not present, as they are not needed.
static_assert(not ngt::HasTrivialCopyProperties);
} else if constexpr (not ngt::HasTrivialCopyProperties) {
- // If T has no TrivialCopyProperties, call initialize() without any additional arguments.
ngt::MemoryCopyTraits::initialize(object());
} else {
- // If T has TrivialCopyProperties, cast args to Properties and pass it as an additional argument to initialize().
ngt::MemoryCopyTraits::initialize(object(), args.cast_to>());
}
}
- std::vector> regions() override {
- static_assert(ngt::HasRegions);
- return ngt::MemoryCopyTraits::regions(object());
- }
+ std::vector> regions() override { return ngt::get_regions(object()); }
- void finalize() override {
- if constexpr (ngt::HasTrivialCopyFinalize) {
- ngt::MemoryCopyTraits::finalize(object());
- }
- }
+ void finalize() override { ngt::do_finalize(object()); }
private:
const T& object() const { return static_cast(ptr_.get())->bareProduct(); }
@@ -70,4 +57,4 @@ namespace ngt {
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_Writer_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_Writer_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h b/HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h
index 6fc1f5f12c865..44ec6f2bc9045 100644
--- a/HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h
+++ b/HeterogeneousCore/TrivialSerialisation/interface/WriterBase.h
@@ -1,5 +1,5 @@
-#ifndef TrivialSerialisation_Common_interface_WriterBase_h
-#define TrivialSerialisation_Common_interface_WriterBase_h
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_WriterBase_h
+#define HeterogeneousCore_TrivialSerialisation_interface_WriterBase_h
#include
#include
@@ -10,6 +10,7 @@
namespace ngt {
+ // Base class for creating a new product and exposing its memory regions for writing.
class WriterBase {
public:
WriterBase() = default;
@@ -28,4 +29,4 @@ namespace ngt {
} // namespace ngt
-#endif // TrivialSerialisation_Common_interface_WriterBase_h
+#endif // HeterogeneousCore_TrivialSerialisation_interface_WriterBase_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Reader.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Reader.h
new file mode 100644
index 0000000000000..ecb3f1df69628
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Reader.h
@@ -0,0 +1,41 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_Reader_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_Reader_h
+
+#include
+#include
+#include
+
+#include "DataFormats/Common/interface/Wrapper.h"
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/AnyBuffer.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/Common.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+
+ // Reader for device products.
+ template
+ class Reader : public ::ngt::ReaderBase {
+ static_assert(::ngt::HasMemoryCopyTraits, "No specialization of MemoryCopyTraits found for type T");
+
+ public:
+ using WrapperType = edm::Wrapper;
+
+ // Constructor from Wrapper
+ explicit Reader(WrapperType const& wrapper) : ::ngt::ReaderBase(&wrapper), productPtr_(&wrapper.bareProduct()) {}
+
+ // Constructor from T const& directly.
+ explicit Reader(T const& product) : ::ngt::ReaderBase(nullptr), productPtr_(&product) {}
+
+ ::ngt::AnyBuffer parameters() const override { return ::ngt::get_properties(*productPtr_); }
+
+ std::vector> regions() const override { return ::ngt::get_regions(*productPtr_); }
+
+ private:
+ T const* productPtr_;
+ };
+
+} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_alpaka_Reader_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/ReaderBase.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/ReaderBase.h
new file mode 100644
index 0000000000000..01bf5c2c0cb63
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/ReaderBase.h
@@ -0,0 +1,14 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_ReaderBase_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_ReaderBase_h
+
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/ReaderBase.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+
+ // The alpaka ReaderBase is the same as the host one.
+ using ReaderBase = ::ngt::ReaderBase;
+
+} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_alpaka_ReaderBase_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Serialiser.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Serialiser.h
new file mode 100644
index 0000000000000..78d7829fde6a3
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Serialiser.h
@@ -0,0 +1,41 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_Serialiser_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_Serialiser_h
+
+#include
+
+#include "DataFormats/Common/interface/Wrapper.h"
+#include "DataFormats/Common/interface/WrapperBase.h"
+#include "DataFormats/AlpakaCommon/interface/alpaka/DeviceProductType.h"
+#include "DataFormats/AlpakaCommon/interface/alpaka/EDMetadata.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/Reader.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserBase.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/Writer.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+
+ // Concrete Serialiser for device products.
+ // T is the inner product type (e.g. PortableDeviceCollection<...>).
+ template
+ class Serialiser : public SerialiserBase {
+ public:
+ using WrapperType = edm::Wrapper>;
+
+ std::unique_ptr writer() override { return std::make_unique>(); }
+
+ std::unique_ptr reader(edm::WrapperBase const& wrapper,
+ EDMetadata& metadata,
+ bool tryReuseQueue) override {
+ WrapperType const& w = dynamic_cast(wrapper);
+ if constexpr (detail::useProductDirectly) {
+ return std::make_unique>(w.bareProduct());
+ } else {
+ return std::make_unique>(
+ w.bareProduct().template getSynchronized(metadata, tryReuseQueue));
+ }
+ }
+ };
+
+} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_alpaka_Serialiser_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserBase.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserBase.h
new file mode 100644
index 0000000000000..3afd28e9e350d
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserBase.h
@@ -0,0 +1,26 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserBase_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserBase_h
+
+#include
+
+#include "DataFormats/Common/interface/WrapperBase.h"
+#include "DataFormats/AlpakaCommon/interface/alpaka/EDMetadata.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/ReaderBase.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/WriterBase.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+
+ // Abstract interface for creating Readers and Writers for device products.
+ class SerialiserBase {
+ public:
+ virtual std::unique_ptr writer() = 0;
+ virtual std::unique_ptr reader(const edm::WrapperBase& wrapper,
+ EDMetadata& metadata,
+ bool tryReuseQueue) = 0;
+
+ virtual ~SerialiserBase() = default;
+ };
+} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserBase_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h
new file mode 100644
index 0000000000000..7bb5c21d91bfd
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserFactoryDevice.h
@@ -0,0 +1,30 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserFactoryDevice_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserFactoryDevice_h
+
+#include "DataFormats/Common/interface/DeviceProduct.h"
+#include "FWCore/PluginManager/interface/PluginFactory.h"
+#include "FWCore/Utilities/interface/stringize.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/Serialiser.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/SerialiserBase.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+ using SerialiserFactoryDevice = edmplugin::PluginFactory;
+} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt
+
+// Helper macro to define Serialiser plugins.
+//
+// TYPE is the inner product type (e.g. PortableDeviceCollection<...>), not
+// wrapped in DeviceProduct, and without ALPAKA_ACCELERATOR_NAMESPACE:: attached
+// to it (it is attached here). The plugin is registered under both the mangled
+// typeid name and EDM_STRINGIZE(TYPE). EDM_STRINGIZE(TYPE) is more
+// human-readable, and thus more suitable for Python configuration files.
+#define DEFINE_TRIVIAL_SERIALISER_PLUGIN_DEVICE(TYPE) \
+ DEFINE_EDM_PLUGIN(ALPAKA_ACCELERATOR_NAMESPACE::ngt::SerialiserFactoryDevice, \
+ ALPAKA_ACCELERATOR_NAMESPACE::ngt::Serialiser, \
+ typeid(edm::DeviceProduct).name()); \
+ DEFINE_EDM_PLUGIN2(ALPAKA_ACCELERATOR_NAMESPACE::ngt::SerialiserFactoryDevice, \
+ ALPAKA_ACCELERATOR_NAMESPACE::ngt::Serialiser, \
+ EDM_STRINGIZE(TYPE))
+
+#endif // HeterogeneousCore_TrivialSerialisation_interface_alpaka_SerialiserFactoryDevice_h
diff --git a/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Writer.h b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Writer.h
new file mode 100644
index 0000000000000..ff3c889a2b88f
--- /dev/null
+++ b/HeterogeneousCore/TrivialSerialisation/interface/alpaka/Writer.h
@@ -0,0 +1,84 @@
+#ifndef HeterogeneousCore_TrivialSerialisation_interface_alpaka_Writer_h
+#define HeterogeneousCore_TrivialSerialisation_interface_alpaka_Writer_h
+
+#include
+#include
+#include
+#include
+
+#include "DataFormats/Common/interface/Wrapper.h"
+#include "DataFormats/TrivialSerialisation/interface/MemoryCopyTraits.h"
+#include "DataFormats/AlpakaCommon/interface/alpaka/DeviceProductType.h"
+#include "DataFormats/AlpakaCommon/interface/alpaka/EDMetadata.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/AnyBuffer.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/Common.h"
+#include "HeterogeneousCore/TrivialSerialisation/interface/alpaka/WriterBase.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE::ngt {
+
+ // Writer for device products.
+ // T is the inner product type (e.g. PortableDeviceCollection<...>)
+ template
+ class Writer : public WriterBase {
+ static_assert(::ngt::HasMemoryCopyTraits, "No specialization of MemoryCopyTraits found for type T");
+
+ public:
+ using WrapperType = edm::Wrapper>;
+
+ Writer() : WriterBase(), data_{construct_()} {}
+
+ ::ngt::AnyBuffer uninitialized_parameters() const override { return ::ngt::get_properties(object()); }
+
+ void initialize(Queue& queue, ::ngt::AnyBuffer const& args) override {
+ using Traits = ::ngt::MemoryCopyTraits;
+ if constexpr (::ngt::HasTrivialCopyProperties) {
+ // properties are required to initialize an object of type T
+ using Props = ::ngt::TrivialCopyProperties;
+ static_assert(
+ requires(T& o, Queue& q, Props p) { Traits::initialize(q, o, p); },
+ "MemoryCopyTraits has properties but no initialize(Queue&, T&, Properties const&)");
+ Traits::initialize(queue, object(), args.cast_to());
+ } else {
+ // No properties are required to initialize an object of type T
+ static_assert(
+ requires(T& o, Queue& q) { Traits::initialize(q, o); },
+ "MemoryCopyTraits