From 91235b583453bc4646556474e68de3d27e6a8319 Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 15 Nov 2023 18:23:52 +0100 Subject: [PATCH 1/5] Implement PortableObject types PortableHostObject is a class template that wraps a struct type T and an alpaka host buffer, that owns the memory where the struct is allocated. The content of the struct is persistent, while the buffer itself is transient. Specialisations of this template can be persisted, but requre special ROOT read rules to read the data into an alpaka memory buffer. PortableDeviceObject is a class template that wraps a struct type T and an alpaka device buffer, that owns the memory where the struct is allocated. To avoid confusion and ODR-violations, the PortableDeviceObject template cannot be used with the Host device type. Specialisations of this template are transient and cannot be persisted. Add TestHostObject and TestDeviceObject based on a TestStruct. Co-authored-by: Adriano Di Florio Co-authored-by: Breno Orzari Co-authored-by: Dimitris Papagiannis --- .../Portable/interface/PortableDeviceObject.h | 72 +++++++++++++++++ .../Portable/interface/PortableHostObject.h | 81 +++++++++++++++++++ .../Portable/interface/PortableObject.h | 20 +++++ .../interface/alpaka/PortableCollection.h | 8 +- .../interface/alpaka/PortableObject.h | 69 ++++++++++++++++ .../interface/TestHostObject.h | 14 ++++ .../interface/TestStruct.h | 18 +++++ .../interface/alpaka/TestDeviceObject.h | 27 +++++++ .../src/alpaka/classes_cuda.h | 2 + .../src/alpaka/classes_cuda_def.xml | 4 + .../src/alpaka/classes_rocm.h | 2 + .../src/alpaka/classes_rocm_def.xml | 4 + DataFormats/PortableTestObjects/src/classes.h | 2 + .../PortableTestObjects/src/classes_def.xml | 4 + 14 files changed, 322 insertions(+), 5 deletions(-) create mode 100644 DataFormats/Portable/interface/PortableDeviceObject.h create mode 100644 DataFormats/Portable/interface/PortableHostObject.h create mode 100644 DataFormats/Portable/interface/PortableObject.h create mode 100644 DataFormats/Portable/interface/alpaka/PortableObject.h create mode 100644 DataFormats/PortableTestObjects/interface/TestHostObject.h create mode 100644 DataFormats/PortableTestObjects/interface/TestStruct.h create mode 100644 DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h diff --git a/DataFormats/Portable/interface/PortableDeviceObject.h b/DataFormats/Portable/interface/PortableDeviceObject.h new file mode 100644 index 0000000000000..72e12bbdfe80c --- /dev/null +++ b/DataFormats/Portable/interface/PortableDeviceObject.h @@ -0,0 +1,72 @@ +#ifndef DataFormats_Portable_interface_PortableDeviceObject_h +#define DataFormats_Portable_interface_PortableDeviceObject_h + +#include +#include +#include + +#include + +#include "HeterogeneousCore/AlpakaInterface/interface/config.h" +#include "HeterogeneousCore/AlpakaInterface/interface/memory.h" + +// generic object in device memory +template >> +class PortableDeviceObject { + static_assert(not std::is_same_v, + "Use PortableHostObject instead of PortableDeviceObject"); + +public: + using Product = T; + using Buffer = cms::alpakatools::device_buffer; + using ConstBuffer = cms::alpakatools::const_device_buffer; + + PortableDeviceObject() = default; + + PortableDeviceObject(TDev const& device) + // allocate global device memory + : buffer_{cms::alpakatools::make_device_buffer(device)} { + assert(reinterpret_cast(buffer_->data()) % alignof(Product) == 0); + } + + template >> + PortableDeviceObject(TQueue const& queue) + // allocate global device memory with queue-ordered semantic + : buffer_{cms::alpakatools::make_device_buffer(queue)} { + assert(reinterpret_cast(buffer_->data()) % alignof(Product) == 0); + } + + // non-copyable + PortableDeviceObject(PortableDeviceObject const&) = delete; + PortableDeviceObject& operator=(PortableDeviceObject const&) = delete; + + // movable + PortableDeviceObject(PortableDeviceObject&&) = default; + PortableDeviceObject& operator=(PortableDeviceObject&&) = default; + + // default destructor + ~PortableDeviceObject() = default; + + // access the product + Product& value() { return *buffer_->data(); } + Product const& value() const { return *buffer_->data(); } + + Product* data() { return buffer_->data(); } + Product const* data() const { return buffer_->data(); } + + Product& operator*() { return *buffer_->data(); } + Product const& operator*() const { return *buffer_->data(); } + + Product* operator->() { return buffer_->data(); } + Product const* operator->() const { return buffer_->data(); } + + // access the buffer + Buffer buffer() { return *buffer_; } + ConstBuffer buffer() const { return *buffer_; } + ConstBuffer const_buffer() const { return *buffer_; } + +private: + std::optional buffer_; +}; + +#endif // DataFormats_Portable_interface_PortableDeviceObject_h diff --git a/DataFormats/Portable/interface/PortableHostObject.h b/DataFormats/Portable/interface/PortableHostObject.h new file mode 100644 index 0000000000000..348da4f8c505d --- /dev/null +++ b/DataFormats/Portable/interface/PortableHostObject.h @@ -0,0 +1,81 @@ +#ifndef DataFormats_Portable_interface_PortableHostObject_h +#define DataFormats_Portable_interface_PortableHostObject_h + +#include +#include +#include + +#include + +#include "HeterogeneousCore/AlpakaInterface/interface/config.h" +#include "HeterogeneousCore/AlpakaInterface/interface/host.h" +#include "HeterogeneousCore/AlpakaInterface/interface/memory.h" + +// generic object in host memory +template +class PortableHostObject { +public: + using Product = T; + using Buffer = cms::alpakatools::host_buffer; + using ConstBuffer = cms::alpakatools::const_host_buffer; + + PortableHostObject() = default; + + PortableHostObject(alpaka_common::DevHost const& host) + // allocate pageable host memory + : buffer_{cms::alpakatools::make_host_buffer()}, product_{buffer_->data()} { + assert(reinterpret_cast(product_) % alignof(Product) == 0); + } + + template >> + PortableHostObject(TQueue const& queue) + // allocate pinned host memory associated to the given work queue, accessible by the queue's device + : buffer_{cms::alpakatools::make_host_buffer(queue)}, product_{buffer_->data()} { + assert(reinterpret_cast(product_) % alignof(Product) == 0); + } + + // non-copyable + PortableHostObject(PortableHostObject const&) = delete; + PortableHostObject& operator=(PortableHostObject const&) = delete; + + // movable + PortableHostObject(PortableHostObject&&) = default; + PortableHostObject& operator=(PortableHostObject&&) = default; + + // default destructor + ~PortableHostObject() = default; + + // access the product + Product& value() { return *product_; } + Product const& value() const { return *product_; } + + Product* data() { return product_; } + Product const* data() const { return product_; } + + Product& operator*() { return *product_; } + Product const& operator*() const { return *product_; } + + Product* operator->() { return product_; } + Product const* operator->() const { return product_; } + + // access the buffer + Buffer buffer() { return *buffer_; } + ConstBuffer buffer() const { return *buffer_; } + ConstBuffer const_buffer() const { return *buffer_; } + + // part of the ROOT read streamer + static void ROOTReadStreamer(PortableHostObject* newObj, Product& product) { + // destroy the default-constructed object + newObj->~PortableHostObject(); + // use the global "host" object returned by cms::alpakatools::host() + new (newObj) PortableHostObject(cms::alpakatools::host()); + // copy the data from the on-file object to the new one + std::memcpy(newObj->product_, &product, sizeof(Product)); + } + +private: + std::optional buffer_; //! + Product* product_; +}; + +#endif // DataFormats_Portable_interface_PortableHostObject_h diff --git a/DataFormats/Portable/interface/PortableObject.h b/DataFormats/Portable/interface/PortableObject.h new file mode 100644 index 0000000000000..90a33b49d0f0a --- /dev/null +++ b/DataFormats/Portable/interface/PortableObject.h @@ -0,0 +1,20 @@ +#ifndef DataFormats_Portable_interface_PortableObject_h +#define DataFormats_Portable_interface_PortableObject_h + +#include + +#include "HeterogeneousCore/AlpakaInterface/interface/traits.h" + +namespace traits { + + // trait for a generic SoA-based product + template >> + class PortableObjectTrait; + +} // namespace traits + +// type alias for a generic SoA-based product +template >> +using PortableObject = typename traits::PortableObjectTrait::ProductType; + +#endif // DataFormats_Portable_interface_PortableObject_h diff --git a/DataFormats/Portable/interface/alpaka/PortableCollection.h b/DataFormats/Portable/interface/alpaka/PortableCollection.h index deaad34e89c12..0a6abad96dfaf 100644 --- a/DataFormats/Portable/interface/alpaka/PortableCollection.h +++ b/DataFormats/Portable/interface/alpaka/PortableCollection.h @@ -1,7 +1,5 @@ -#ifndef DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h -#define DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h - -#include +#ifndef DataFormats_Portable_interface_alpaka_PortableCollection_h +#define DataFormats_Portable_interface_alpaka_PortableCollection_h #include @@ -68,4 +66,4 @@ namespace cms::alpakatools { }; } // namespace cms::alpakatools -#endif // DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h +#endif // DataFormats_Portable_interface_alpaka_PortableCollection_h diff --git a/DataFormats/Portable/interface/alpaka/PortableObject.h b/DataFormats/Portable/interface/alpaka/PortableObject.h new file mode 100644 index 0000000000000..9b7ba65f8a460 --- /dev/null +++ b/DataFormats/Portable/interface/alpaka/PortableObject.h @@ -0,0 +1,69 @@ +#ifndef DataFormats_Portable_interface_alpaka_PortableObject_h +#define DataFormats_Portable_interface_alpaka_PortableObject_h + +#include + +#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 + using PortableObject = ::PortableHostObject; + +#else + + // generic SoA-based product in device memory + template + using PortableObject = ::PortableDeviceObject; + +#endif // ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED + +} // namespace ALPAKA_ACCELERATOR_NAMESPACE + +namespace traits { + + // specialise the trait for the device provided by the ALPAKA_ACCELERATOR_NAMESPACE + template + class PortableObjectTrait { + using ProductType = ALPAKA_ACCELERATOR_NAMESPACE::PortableObject; + }; + +} // namespace traits + +namespace cms::alpakatools { + template + struct CopyToHost> { + template + static auto copyAsync(TQueue& queue, PortableDeviceObject const& srcData) { + PortableHostObject dstData(queue); + alpaka::memcpy(queue, dstData.buffer(), srcData.buffer()); + return dstData; + } + }; + + template + struct CopyToDevice> { + template + static auto copyAsync(TQueue& queue, PortableHostObject const& srcData) { + using TDevice = typename alpaka::trait::DevType::type; + PortableDeviceObject dstData(queue); + alpaka::memcpy(queue, dstData.buffer(), srcData.buffer()); + return dstData; + } + }; +} // namespace cms::alpakatools + +#endif // DataFormats_Portable_interface_alpaka_PortableObject_h diff --git a/DataFormats/PortableTestObjects/interface/TestHostObject.h b/DataFormats/PortableTestObjects/interface/TestHostObject.h new file mode 100644 index 0000000000000..2bf923fa73b69 --- /dev/null +++ b/DataFormats/PortableTestObjects/interface/TestHostObject.h @@ -0,0 +1,14 @@ +#ifndef DataFormats_PortableTestObjects_interface_TestHostObject_h +#define DataFormats_PortableTestObjects_interface_TestHostObject_h + +#include "DataFormats/Portable/interface/PortableHostObject.h" +#include "DataFormats/PortableTestObjects/interface/TestStruct.h" + +namespace portabletest { + + // struct with x, y, z, id fields in host memory + using TestHostObject = PortableHostObject; + +} // namespace portabletest + +#endif // DataFormats_PortableTestObjects_interface_TestHostObject_h diff --git a/DataFormats/PortableTestObjects/interface/TestStruct.h b/DataFormats/PortableTestObjects/interface/TestStruct.h new file mode 100644 index 0000000000000..08395ae3a4e20 --- /dev/null +++ b/DataFormats/PortableTestObjects/interface/TestStruct.h @@ -0,0 +1,18 @@ +#ifndef DataFormats_PortableTestObjects_interface_TestStruct_h +#define DataFormats_PortableTestObjects_interface_TestStruct_h + +#include + +namespace portabletest { + + // struct with x, y, z, id fields + struct TestStruct { + double x; + double y; + double z; + int32_t id; + }; + +} // namespace portabletest + +#endif // DataFormats_PortableTestObjects_interface_TestStruct_h diff --git a/DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h b/DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h new file mode 100644 index 0000000000000..61f08cc28b7e0 --- /dev/null +++ b/DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h @@ -0,0 +1,27 @@ +#ifndef DataFormats_PortableTestObjects_interface_alpaka_TestDeviceObject_h +#define DataFormats_PortableTestObjects_interface_alpaka_TestDeviceObject_h + +#include "DataFormats/Portable/interface/alpaka/PortableObject.h" +#include "DataFormats/PortableTestObjects/interface/TestHostObject.h" +#include "DataFormats/PortableTestObjects/interface/TestStruct.h" +#include "HeterogeneousCore/AlpakaInterface/interface/config.h" + +namespace ALPAKA_ACCELERATOR_NAMESPACE { + + namespace portabletest { + + // make the names from the top-level portabletest namespace visible for unqualified lookup + // inside the ALPAKA_ACCELERATOR_NAMESPACE::portabletest namespace + using namespace ::portabletest; + + // struct with x, y, z, id fields in device global memory + using TestDeviceObject = PortableObject; + + } // namespace portabletest + +} // namespace ALPAKA_ACCELERATOR_NAMESPACE + +// check that the portable device collection for the host device is the same as the portable host collection +ASSERT_DEVICE_MATCHES_HOST_COLLECTION(portabletest::TestDeviceObject, portabletest::TestHostObject); + +#endif // DataFormats_PortableTestObjects_interface_alpaka_TestDeviceObject_h diff --git a/DataFormats/PortableTestObjects/src/alpaka/classes_cuda.h b/DataFormats/PortableTestObjects/src/alpaka/classes_cuda.h index 923e5de9b3ecf..07a7c0e2991d6 100644 --- a/DataFormats/PortableTestObjects/src/alpaka/classes_cuda.h +++ b/DataFormats/PortableTestObjects/src/alpaka/classes_cuda.h @@ -1,4 +1,6 @@ #include "DataFormats/Common/interface/DeviceProduct.h" #include "DataFormats/Common/interface/Wrapper.h" #include "DataFormats/PortableTestObjects/interface/TestSoA.h" +#include "DataFormats/PortableTestObjects/interface/TestStruct.h" #include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h" +#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h" diff --git a/DataFormats/PortableTestObjects/src/alpaka/classes_cuda_def.xml b/DataFormats/PortableTestObjects/src/alpaka/classes_cuda_def.xml index 598543e8bb697..fc3678362dc71 100644 --- a/DataFormats/PortableTestObjects/src/alpaka/classes_cuda_def.xml +++ b/DataFormats/PortableTestObjects/src/alpaka/classes_cuda_def.xml @@ -2,4 +2,8 @@ + + + + diff --git a/DataFormats/PortableTestObjects/src/alpaka/classes_rocm.h b/DataFormats/PortableTestObjects/src/alpaka/classes_rocm.h index 923e5de9b3ecf..07a7c0e2991d6 100644 --- a/DataFormats/PortableTestObjects/src/alpaka/classes_rocm.h +++ b/DataFormats/PortableTestObjects/src/alpaka/classes_rocm.h @@ -1,4 +1,6 @@ #include "DataFormats/Common/interface/DeviceProduct.h" #include "DataFormats/Common/interface/Wrapper.h" #include "DataFormats/PortableTestObjects/interface/TestSoA.h" +#include "DataFormats/PortableTestObjects/interface/TestStruct.h" #include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h" +#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h" diff --git a/DataFormats/PortableTestObjects/src/alpaka/classes_rocm_def.xml b/DataFormats/PortableTestObjects/src/alpaka/classes_rocm_def.xml index bc61b9fcdfdfa..65ce1c888572b 100644 --- a/DataFormats/PortableTestObjects/src/alpaka/classes_rocm_def.xml +++ b/DataFormats/PortableTestObjects/src/alpaka/classes_rocm_def.xml @@ -2,4 +2,8 @@ + + + + diff --git a/DataFormats/PortableTestObjects/src/classes.h b/DataFormats/PortableTestObjects/src/classes.h index 9405bbfd336e2..c3c2d77702a65 100644 --- a/DataFormats/PortableTestObjects/src/classes.h +++ b/DataFormats/PortableTestObjects/src/classes.h @@ -1,3 +1,5 @@ #include "DataFormats/Common/interface/Wrapper.h" #include "DataFormats/PortableTestObjects/interface/TestHostCollection.h" +#include "DataFormats/PortableTestObjects/interface/TestHostObject.h" #include "DataFormats/PortableTestObjects/interface/TestSoA.h" +#include "DataFormats/PortableTestObjects/interface/TestStruct.h" diff --git a/DataFormats/PortableTestObjects/src/classes_def.xml b/DataFormats/PortableTestObjects/src/classes_def.xml index fa32d49ab8556..54e9bc24249c2 100644 --- a/DataFormats/PortableTestObjects/src/classes_def.xml +++ b/DataFormats/PortableTestObjects/src/classes_def.xml @@ -3,4 +3,8 @@ + + + + From c52f258d67d4401fbbd205168991c6ae7a049046 Mon Sep 17 00:00:00 2001 From: Andrea Bocci Date: Wed, 22 Nov 2023 08:10:05 +0100 Subject: [PATCH 2/5] Implement ROOT read rules for PortableHostObject types --- .../interface/PortableHostObjectReadRules.h | 76 +++++++++++++++++++ .../PortableTestObjects/src/classes.cc | 3 + 2 files changed, 79 insertions(+) create mode 100644 DataFormats/Portable/interface/PortableHostObjectReadRules.h diff --git a/DataFormats/Portable/interface/PortableHostObjectReadRules.h b/DataFormats/Portable/interface/PortableHostObjectReadRules.h new file mode 100644 index 0000000000000..c33e1366ddc81 --- /dev/null +++ b/DataFormats/Portable/interface/PortableHostObjectReadRules.h @@ -0,0 +1,76 @@ +#ifndef DataFormats_Portable_interface_PortableHostObjectReadRules_h +#define DataFormats_Portable_interface_PortableHostObjectReadRules_h + +#include +#include + +#include "DataFormats/Portable/interface/PortableHostObject.h" +#include "FWCore/Utilities/interface/concatenate.h" +#include "FWCore/Utilities/interface/stringize.h" + +// read function for PortableHostObject, called for every event +template +static void readPortableHostObject_v1(char *target, TVirtualObject *from_buffer) { + // extract the actual types + using Object = T; + using Product = typename Object::Product; + + // valid only for PortableHostObject + static_assert(std::is_same_v>); + + // proxy for the object being read from file + struct OnFile { + Product *product_; + }; + + // address in memory of the buffer containing the object being read from file + char *address = static_cast(from_buffer->GetObject()); + // offset of the "product_" data member + static ptrdiff_t product_offset = from_buffer->GetClass()->GetDataMemberOffset("product_"); + // pointer to the Product object being read from file + OnFile onfile = {*(Product **)(address + product_offset)}; + + // pointer to the Object object being constructed in memory + Object *newObj = (Object *)target; + + // move the data from the on-file layout to the newly constructed object + Object::ROOTReadStreamer(newObj, *onfile.product_); +} + +// put set_PortableHostObject_read_rules in the ROOT namespace to let it forward declare GenerateInitInstance +namespace ROOT { + + // set the read rules for PortableHostObject; + // this is called only once, when the dictionary is loaded. + template + static bool set_PortableHostObject_read_rules(std::string const &type) { + // forward declaration + TGenericClassInfo *GenerateInitInstance(T const *); + + // build the read rules + std::vector readrules(1); + ROOT::Internal::TSchemaHelper &rule = readrules[0]; + rule.fTarget = "buffer_,product_"; + rule.fSourceClass = type; + rule.fSource = type + "::Product* product_;"; + rule.fCode = type + "::ROOTReadStreamer(newObj, *onfile.product_)"; + rule.fVersion = "[1-]"; + rule.fChecksum = ""; + rule.fInclude = ""; + rule.fEmbed = false; + rule.fFunctionPtr = reinterpret_cast(::readPortableHostObject_v1); + rule.fAttributes = ""; + + // set the read rules + TGenericClassInfo *instance = GenerateInitInstance((T const *)nullptr); + instance->SetReadRules(readrules); + + return true; + } +} // namespace ROOT + +#define SET_PORTABLEHOSTOBJECT_READ_RULES(OBJECT) \ + static bool EDM_CONCATENATE(set_PortableHostObject_read_rules_done_at_, __LINE__) [[maybe_unused]] = \ + ROOT::set_PortableHostObject_read_rules(EDM_STRINGIZE(OBJECT)) + +#endif // DataFormats_Portable_interface_PortableHostObjectReadRules_h diff --git a/DataFormats/PortableTestObjects/src/classes.cc b/DataFormats/PortableTestObjects/src/classes.cc index 16c2d6fc6a022..e11de1a3d7d36 100644 --- a/DataFormats/PortableTestObjects/src/classes.cc +++ b/DataFormats/PortableTestObjects/src/classes.cc @@ -1,4 +1,7 @@ #include "DataFormats/Portable/interface/PortableHostCollectionReadRules.h" +#include "DataFormats/Portable/interface/PortableHostObjectReadRules.h" #include "DataFormats/PortableTestObjects/interface/TestHostCollection.h" +#include "DataFormats/PortableTestObjects/interface/TestHostObject.h" SET_PORTABLEHOSTCOLLECTION_READ_RULES(portabletest::TestHostCollection); +SET_PORTABLEHOSTOBJECT_READ_RULES(portabletest::TestHostObject); From c3aebf876c561664a09918f13b3302a2d24c6843 Mon Sep 17 00:00:00 2001 From: Andrea Bocci Date: Wed, 22 Nov 2023 08:30:50 +0100 Subject: [PATCH 3/5] Document the PortableObject types --- DataFormats/Portable/README.md | 73 +++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/DataFormats/Portable/README.md b/DataFormats/Portable/README.md index 3c92bdf04bd91..1724c3123d9fc 100644 --- a/DataFormats/Portable/README.md +++ b/DataFormats/Portable/README.md @@ -1,10 +1,71 @@ +## Define portable data formats that wrap a simple C-style `struct` and can be persisted to ROOT files + +### `PortableHostObject` + +`PortableHostObject` is a class template that wraps a `struct` type `T` and an alpaka host buffer, that owns the +memory where the `struct` is allocated. The content of the `struct` is persistent, while the buffer itself is transient. +Specialisations of this template can be persisted, but requre special ROOT read rules to read the data into an alpaka +memory buffer. + +The traditional way to declare these rules would be to add them to the `classes_def.xml` file. This method is described +here for reference, but is deprecated. See below for a simpler method. +For example, to declare the read rules for `portabletest::TestHostObject` based on the `portabletest::TestStruct` `struct`, +one would add to the same `classes_def.xml` file where `portabletest::TestHostObject` is declared: +```xml + + + +``` + +The recommended way to declare these rules is to create a `classes.cc` file along with `classes.h`, and use the +`SET_PORTABLEHOSTOBJECT_READ_RULES` macro. For example, to declare the rules for `portabletest::TestHostObject` one +would create the file `classes.cc` with the content: +```c++ +#include "DataFormats/Portable/interface/PortableHostObjectReadRules.h" +#include "DataFormats/PortableTestObjects/interface/TestHostObject.h" + +SET_PORTABLEHOSTOBJECT_READ_RULES(portabletest::TestHostObject); +``` + +`PortableHostObject` objects can also be read back in "bare ROOT" mode, without any dictionaries. +They have no implicit or explicit references to alpaka (neither as part of the class signature nor as part of its name). +This could make it possible to read them back with different portability solutions in the future. + +### `PortableDeviceObject` + +`PortableDeviceObject` is a class template that wraps a `struct` type `T` and an alpaka device buffer, that +owns the memory where the `struct` is allocated. +To avoid confusion and ODR-violations, the `PortableDeviceObject` template cannot be used with the `Host` +device type. +Specialisations of this template are transient and cannot be persisted. + +### `ALPAKA_ACCELERATOR_NAMESPACE::PortableObject` + +`ALPAKA_ACCELERATOR_NAMESPACE::PortableObject` is a template alias that resolves to either +`PortableHostObject` or `PortableDeviceObject`, depending on the +backend. + +### `PortableObject` + +`PortableObject` is an alias template that resolves to `ALPAKA_ACCELERATOR_NAMESPACE::PortableObject` +for the matching device. + + ## Define portable data formats that wrap SoA data structures and can be persisted to ROOT files ### `PortableHostCollection` `PortableHostCollection` is a class template that wraps a SoA type `T` and an alpaka host buffer, which owns the memory where the SoA is allocated. The content of the SoA is persistent, while the buffer itself is transient. -Specialisations of this template can be persisted, but requre specil ROOT read rules to read the data into a single +Specialisations of this template can be persisted, but requre special ROOT read rules to read the data into a single memory buffer. The original way to declare these rules, now deprecated, is to add them to the `classes_def.xml` file. For example, @@ -24,8 +85,8 @@ would add to the same `classes_def.xml` file where `portabletest::TestHostCollec ``` The new, recommended way to declare these rules is to create a `classes.cc` file along with `classes.h`, and use the -`SET_PORTABLEHOSTCOLLECTION_READ_RULES`. For example, to declare the rules for `portabletest::TestHostCollection` one -would create the file `classes.cc` with the content: +`SET_PORTABLEHOSTCOLLECTION_READ_RULES` macro. For example, to declare the rules for `portabletest::TestHostCollection` +one would create the file `classes.cc` with the content: ```c++ #include "DataFormats/Portable/interface/PortableHostCollectionReadRules.h" #include "DataFormats/PortableTestObjects/interface/TestHostCollection.h" @@ -33,8 +94,7 @@ would create the file `classes.cc` with the content: SET_PORTABLEHOSTCOLLECTION_READ_RULES(portabletest::TestHostCollection); ``` -`PortableHostCollection` can also be read back in "bare ROOT" mode, without any dictionaries. - +`PortableHostCollection` collections can also be read back in "bare ROOT" mode, without any dictionaries. They have no implicit or explicit references to alpaka (neither as part of the class signature nor as part of its name). This could make it possible to read them back with different portability solutions in the future. @@ -61,7 +121,8 @@ for the matching device. ## Notes Modules that are supposed to work with only host types (_e.g._ dealing with de/serialisation, data transfers, _etc._) -should explicitly use the `PortableHostCollection` types. +should explicitly use the `PortableHostObject` and `PortableHostCollection` types. Modules that implement portable interfaces (_e.g._ producers) should use the generic types based on +`ALPAKA_ACCELERATOR_NAMESPACE::PortableObject` or `PortableObject`, and `ALPAKA_ACCELERATOR_NAMESPACE::PortableCollection` or `PortableCollection`. From f950141c7afd98a84de47bab57bfaf41b6e7492f Mon Sep 17 00:00:00 2001 From: Andrea Bocci Date: Tue, 21 Nov 2023 19:11:57 +0100 Subject: [PATCH 4/5] Add a test for writing and reading a PortableTestObject --- .../plugins/TestAlpakaObjectAnalyzer.cc | 78 +++++++++++++++++++ .../AlpakaTest/plugins/alpaka/TestAlgo.dev.cc | 27 +++++++ .../AlpakaTest/plugins/alpaka/TestAlgo.h | 3 + .../plugins/alpaka/TestAlpakaProducer.cc | 18 +++-- HeterogeneousCore/AlpakaTest/test/reader.py | 18 ++++- HeterogeneousCore/AlpakaTest/test/writer.py | 33 +++++--- 6 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 HeterogeneousCore/AlpakaTest/plugins/TestAlpakaObjectAnalyzer.cc diff --git a/HeterogeneousCore/AlpakaTest/plugins/TestAlpakaObjectAnalyzer.cc b/HeterogeneousCore/AlpakaTest/plugins/TestAlpakaObjectAnalyzer.cc new file mode 100644 index 0000000000000..25bb1a00cef44 --- /dev/null +++ b/HeterogeneousCore/AlpakaTest/plugins/TestAlpakaObjectAnalyzer.cc @@ -0,0 +1,78 @@ +#include + +#include "DataFormats/PortableTestObjects/interface/TestHostObject.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/global/EDAnalyzer.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "FWCore/Utilities/interface/InputTag.h" + +class TestAlpakaObjectAnalyzer : public edm::global::EDAnalyzer<> { +public: + TestAlpakaObjectAnalyzer(edm::ParameterSet const& config) + : source_{config.getParameter("source")}, token_{consumes(source_)} { + if (std::string const& eb = config.getParameter("expectBackend"); not eb.empty()) { + expectBackend_ = cms::alpakatools::toBackend(eb); + backendToken_ = consumes(edm::InputTag(source_.label(), "backend", source_.process())); + } + } + + void analyze(edm::StreamID sid, edm::Event const& event, edm::EventSetup const&) const override { + portabletest::TestHostObject const& product = event.get(token_); + + auto const& value = product.value(); + { + edm::LogInfo msg("TestAlpakaObjectAnalyzer"); + msg << source_.encode() << ".data() at " << product.data() << '\n'; + msg << source_.encode() << ".buffer().data() at " << product.buffer().data() << '\n'; + msg << source_.encode() << ".value() = {\n"; + msg << " .x: " << value.x << '\n'; + msg << " .y: " << value.y << '\n'; + msg << " .z: " << value.z << '\n'; + msg << " .id: " << value.id << '\n'; + msg << "}\n"; + } + + // check that the product data is held in the product buffer + assert(product.buffer().data() == product.data()); + + // check that the product content is as expected + assert(value.x == 5.); + assert(value.y == 12.); + assert(value.z == 13.); + assert(value.id == 42); + + // check that the backend is as expected + if (expectBackend_) { + auto backend = static_cast(event.get(backendToken_)); + if (expectBackend_ != backend) { + throw cms::Exception("Assert") << "Expected input backend " << cms::alpakatools::toString(*expectBackend_) + << ", got " << cms::alpakatools::toString(backend); + } + } + } + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("source"); + desc.add("expectBackend", "") + ->setComment( + "Expected backend of the input collection. Empty value means to not perform the check. Default: empty " + "string"); + descriptions.addWithDefaultLabel(desc); + } + +private: + const edm::InputTag source_; + const edm::EDGetTokenT token_; + edm::EDGetTokenT backendToken_; + std::optional expectBackend_; +}; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(TestAlpakaObjectAnalyzer); diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.dev.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.dev.cc index 2e3d0a9286750..9dab03aac0823 100644 --- a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.dev.cc +++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.dev.cc @@ -55,4 +55,31 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { alpaka::exec(queue, workDiv, TestAlgoKernel{}, collection.view(), collection->metadata().size(), xvalue); } + class TestAlgoStructKernel { + public: + template >> + ALPAKA_FN_ACC void operator()(TAcc const& acc, + portabletest::TestDeviceObject::Product* data, + double x, + double y, + double z, + int32_t id) const { + // run on a single thread + if (once_per_grid(acc)) { + data->x = x; + data->y = y; + data->z = z; + data->id = id; + } + } + }; + + void TestAlgo::fillObject( + Queue& queue, portabletest::TestDeviceObject& object, double x, double y, double z, int32_t id) const { + // run on a single thread + auto workDiv = make_workdiv(1, 1); + + alpaka::exec(queue, workDiv, TestAlgoStructKernel{}, object.data(), x, y, z, id); + } + } // namespace ALPAKA_ACCELERATOR_NAMESPACE diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.h b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.h index 4eb7fd6838599..e54a606275b37 100644 --- a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.h +++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.h @@ -2,6 +2,7 @@ #define HeterogeneousCore_AlpakaTest_plugins_alpaka_TestAlgo_h #include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h" +#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h" #include "HeterogeneousCore/AlpakaInterface/interface/config.h" namespace ALPAKA_ACCELERATOR_NAMESPACE { @@ -9,6 +10,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { class TestAlgo { public: void fill(Queue& queue, portabletest::TestDeviceCollection& collection, double xvalue = 0.) const; + void fillObject( + Queue& queue, portabletest::TestDeviceObject& object, double x, double y, double z, int32_t id) const; }; } // namespace ALPAKA_ACCELERATOR_NAMESPACE diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlpakaProducer.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlpakaProducer.cc index eeb58b8b56c8a..d65850985d8fd 100644 --- a/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlpakaProducer.cc +++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlpakaProducer.cc @@ -1,4 +1,5 @@ #include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h" +#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h" #include "FWCore/Framework/interface/Frameworkfwd.h" #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" @@ -18,15 +19,19 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { class TestAlpakaProducer : public global::EDProducer<> { public: TestAlpakaProducer(edm::ParameterSet const& config) - : deviceToken_{produces()}, size_{config.getParameter("size")} {} + : objectToken_{produces()}, collectionToken_{produces()}, size_{config.getParameter("size")} {} void produce(edm::StreamID sid, device::Event& event, device::EventSetup const&) const override { // run the algorithm, potentially asynchronously - portabletest::TestDeviceCollection deviceProduct{size_, event.queue()}; - algo_.fill(event.queue(), deviceProduct); + portabletest::TestDeviceCollection deviceCollection{size_, event.queue()}; + algo_.fill(event.queue(), deviceCollection); - // put the asynchronous product into the event without waiting - event.emplace(deviceToken_, std::move(deviceProduct)); + portabletest::TestDeviceObject deviceObject{event.queue()}; + algo_.fillObject(event.queue(), deviceObject, 5., 12., 13., 42); + + // put the asynchronous products into the event without waiting + event.emplace(objectToken_, std::move(deviceObject)); + event.emplace(collectionToken_, std::move(deviceCollection)); } static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) { @@ -36,7 +41,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { } private: - const device::EDPutToken deviceToken_; + const device::EDPutToken objectToken_; + const device::EDPutToken collectionToken_; const int32_t size_; // implementation of the algorithm diff --git a/HeterogeneousCore/AlpakaTest/test/reader.py b/HeterogeneousCore/AlpakaTest/test/reader.py index b3401d66d66f1..8d65a667fff36 100644 --- a/HeterogeneousCore/AlpakaTest/test/reader.py +++ b/HeterogeneousCore/AlpakaTest/test/reader.py @@ -7,22 +7,32 @@ fileNames = cms.untracked.vstring('file:test.root') ) -# enable logging for the TestAlpakaAnalyzer +# enable logging for the analysers process.MessageLogger.TestAlpakaAnalyzer = cms.untracked.PSet() +process.MessageLogger.TestAlpakaObjectAnalyzer = cms.untracked.PSet() -# analyse the first product +# analyse the first set of products process.testAnalyzer = cms.EDAnalyzer('TestAlpakaAnalyzer', source = cms.InputTag('testProducer') ) +process.testObjectAnalyzer = cms.EDAnalyzer('TestAlpakaObjectAnalyzer', + source = cms.InputTag('testProducer') +) + # analyse the second product process.testAnalyzerSerial = cms.EDAnalyzer('TestAlpakaAnalyzer', source = cms.InputTag('testProducerSerial'), expectBackend = cms.string('SerialSync') ) -process.cuda_path = cms.Path(process.testAnalyzer) +process.testObjectAnalyzerSerial = cms.EDAnalyzer('TestAlpakaObjectAnalyzer', + source = cms.InputTag('testProducerSerial'), + expectBackend = cms.string('SerialSync') +) + +process.device_path = cms.Path(process.testAnalyzer + process.testObjectAnalyzer) -process.serial_path = cms.Path(process.testAnalyzerSerial) +process.serial_path = cms.Path(process.testAnalyzerSerial + process.testObjectAnalyzerSerial) process.maxEvents.input = 10 diff --git a/HeterogeneousCore/AlpakaTest/test/writer.py b/HeterogeneousCore/AlpakaTest/test/writer.py index c61daea62e391..bd8d2775b31ed 100644 --- a/HeterogeneousCore/AlpakaTest/test/writer.py +++ b/HeterogeneousCore/AlpakaTest/test/writer.py @@ -7,8 +7,9 @@ process.load('Configuration.StandardSequences.Accelerators_cff') process.load('HeterogeneousCore.AlpakaCore.ProcessAcceleratorAlpaka_cfi') -# enable logging for the AlpakaService and TestAlpakaAnalyzer +# enable logging for the analysers process.MessageLogger.TestAlpakaAnalyzer = cms.untracked.PSet() +process.MessageLogger.TestAlpakaObjectAnalyzer = cms.untracked.PSet() # either run the producer on a gpu (if available) and copy the product to the cpu, or run the producer directly on the cpu process.testProducer = cms.EDProducer('TestAlpakaProducer@alpaka', @@ -20,11 +21,15 @@ #) ) -# analyse the product +# analyse the first set of products process.testAnalyzer = cms.EDAnalyzer('TestAlpakaAnalyzer', source = cms.InputTag('testProducer') ) +process.testObjectAnalyzer = cms.EDAnalyzer('TestAlpakaObjectAnalyzer', + source = cms.InputTag('testProducer') +) + # run a second producer explicitly on the cpu process.testProducerSerial = cms.EDProducer('alpaka_serial_sync::TestAlpakaProducer', size = cms.int32(99) @@ -37,28 +42,32 @@ # ) #) -# analyse the second product +# analyse the second set of products process.testAnalyzerSerial = cms.EDAnalyzer('TestAlpakaAnalyzer', - source = cms.InputTag('testProducerSerial') + source = cms.InputTag('testProducerSerial'), + expectBackend = cms.string('SerialSync') +) + +process.testObjectAnalyzerSerial = cms.EDAnalyzer('TestAlpakaObjectAnalyzer', + source = cms.InputTag('testProducerSerial'), + expectBackend = cms.string('SerialSync') ) -# write the two products to a 'test.root' file +# write all products to a 'test.root' file process.output = cms.OutputModule('PoolOutputModule', fileName = cms.untracked.string('test.root'), - outputCommands = cms.untracked.vstring( - 'drop *', - 'keep *_testProducer_*_*', - 'keep *_testProducerSerial_*_*', - ) + outputCommands = cms.untracked.vstring('keep *') ) process.process_path = cms.Path( process.testProducer + - process.testAnalyzer) + process.testAnalyzer + + process.testObjectAnalyzer) process.serial_path = cms.Path( process.testProducerSerial + - process.testAnalyzerSerial) + process.testAnalyzerSerial + + process.testObjectAnalyzerSerial) process.output_path = cms.EndPath(process.output) From 1066b18386faf1d0b1e3e4aba8c27019d3f7564a Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 15 Nov 2023 18:45:25 +0100 Subject: [PATCH 5/5] Add alpaka PortableObjects for the beamspot --- DataFormats/BeamSpot/BuildFile.xml | 9 ++++++--- DataFormats/BeamSpot/interface/BeamSpotHost.h | 10 ++++++++++ DataFormats/BeamSpot/interface/BeamSpotPOD.h | 17 +++++++++++------ .../interface/alpaka/BeamSpotDevice.h | 19 +++++++++++++++++++ .../BeamSpot/src/alpaka/classes_cuda.h | 4 ++++ .../BeamSpot/src/alpaka/classes_cuda_def.xml | 5 +++++ .../BeamSpot/src/alpaka/classes_rocm.h | 4 ++++ .../BeamSpot/src/alpaka/classes_rocm_def.xml | 5 +++++ DataFormats/BeamSpot/src/classes.cc | 4 ++++ DataFormats/BeamSpot/src/classes.h | 1 + DataFormats/BeamSpot/src/classes_def.xml | 9 +++++++-- 11 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 DataFormats/BeamSpot/interface/BeamSpotHost.h create mode 100644 DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h create mode 100644 DataFormats/BeamSpot/src/alpaka/classes_cuda.h create mode 100644 DataFormats/BeamSpot/src/alpaka/classes_cuda_def.xml create mode 100644 DataFormats/BeamSpot/src/alpaka/classes_rocm.h create mode 100644 DataFormats/BeamSpot/src/alpaka/classes_rocm_def.xml create mode 100644 DataFormats/BeamSpot/src/classes.cc diff --git a/DataFormats/BeamSpot/BuildFile.xml b/DataFormats/BeamSpot/BuildFile.xml index aa43b789310ee..8d208f41c98ae 100644 --- a/DataFormats/BeamSpot/BuildFile.xml +++ b/DataFormats/BeamSpot/BuildFile.xml @@ -1,10 +1,13 @@ + + + - - - + + + diff --git a/DataFormats/BeamSpot/interface/BeamSpotHost.h b/DataFormats/BeamSpot/interface/BeamSpotHost.h new file mode 100644 index 0000000000000..4a9419d522a4f --- /dev/null +++ b/DataFormats/BeamSpot/interface/BeamSpotHost.h @@ -0,0 +1,10 @@ +#ifndef DataFormats_BeamSpot_interface_BeamSpotHost_h +#define DataFormats_BeamSpot_interface_BeamSpotHost_h + +#include "DataFormats/BeamSpot/interface/BeamSpotPOD.h" +#include "DataFormats/Portable/interface/PortableHostObject.h" + +// simplified representation of the beamspot data, in host memory +using BeamSpotHost = PortableHostObject; + +#endif // DataFormats_BeamSpot_interface_BeamSpotHost_h diff --git a/DataFormats/BeamSpot/interface/BeamSpotPOD.h b/DataFormats/BeamSpot/interface/BeamSpotPOD.h index 5920db6a18930..3c9cfdcfae93b 100644 --- a/DataFormats/BeamSpot/interface/BeamSpotPOD.h +++ b/DataFormats/BeamSpot/interface/BeamSpotPOD.h @@ -1,19 +1,24 @@ #ifndef DataFormats_BeamSpot_interface_BeamSpotPOD_h #define DataFormats_BeamSpot_interface_BeamSpotPOD_h -// This struct is a transient-only, simplified representation of the beamspot -// data used as the underlying type for data transfers and operations in +// This struct is a simplified representation of the beamspot data +// used as the underlying type for data transfers and operations in // heterogeneous code (e.g. in CUDA code). // The covariance matrix is not used in that code, so is left out here. // align to the CUDA L1 cache line size struct alignas(128) BeamSpotPOD { - float x, y, z; // position + float x; // position + float y; + float z; float sigmaZ; - float beamWidthX, beamWidthY; - float dxdz, dydz; - float emittanceX, emittanceY; + float beamWidthX; + float beamWidthY; + float dxdz; + float dydz; + float emittanceX; + float emittanceY; float betaStar; }; diff --git a/DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h b/DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h new file mode 100644 index 0000000000000..cc5a08b68bf2c --- /dev/null +++ b/DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h @@ -0,0 +1,19 @@ +#ifndef DataFormats_BeamSpot_interface_alpaka_BeamSpotDevice_h +#define DataFormats_BeamSpot_interface_alpaka_BeamSpotDevice_h + +#include "DataFormats/BeamSpot/interface/BeamSpotHost.h" +#include "DataFormats/BeamSpot/interface/BeamSpotPOD.h" +#include "DataFormats/Portable/interface/alpaka/PortableObject.h" +#include "HeterogeneousCore/AlpakaInterface/interface/config.h" + +namespace ALPAKA_ACCELERATOR_NAMESPACE { + + // simplified representation of the beamspot data, in device global memory + using BeamSpotDevice = PortableObject; + +} // namespace ALPAKA_ACCELERATOR_NAMESPACE + +// check that the portable device collection for the host device is the same as the portable host collection +ASSERT_DEVICE_MATCHES_HOST_COLLECTION(BeamSpotDevice, BeamSpotHost); + +#endif // DataFormats_BeamSpot_interface_alpaka_BeamSpotDevice_h diff --git a/DataFormats/BeamSpot/src/alpaka/classes_cuda.h b/DataFormats/BeamSpot/src/alpaka/classes_cuda.h new file mode 100644 index 0000000000000..b1cb86030bbe0 --- /dev/null +++ b/DataFormats/BeamSpot/src/alpaka/classes_cuda.h @@ -0,0 +1,4 @@ +#include "DataFormats/BeamSpot/interface/BeamSpotPOD.h" +#include "DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h" +#include "DataFormats/Common/interface/DeviceProduct.h" +#include "DataFormats/Common/interface/Wrapper.h" diff --git a/DataFormats/BeamSpot/src/alpaka/classes_cuda_def.xml b/DataFormats/BeamSpot/src/alpaka/classes_cuda_def.xml new file mode 100644 index 0000000000000..46eaf78f4d965 --- /dev/null +++ b/DataFormats/BeamSpot/src/alpaka/classes_cuda_def.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/DataFormats/BeamSpot/src/alpaka/classes_rocm.h b/DataFormats/BeamSpot/src/alpaka/classes_rocm.h new file mode 100644 index 0000000000000..b1cb86030bbe0 --- /dev/null +++ b/DataFormats/BeamSpot/src/alpaka/classes_rocm.h @@ -0,0 +1,4 @@ +#include "DataFormats/BeamSpot/interface/BeamSpotPOD.h" +#include "DataFormats/BeamSpot/interface/alpaka/BeamSpotDevice.h" +#include "DataFormats/Common/interface/DeviceProduct.h" +#include "DataFormats/Common/interface/Wrapper.h" diff --git a/DataFormats/BeamSpot/src/alpaka/classes_rocm_def.xml b/DataFormats/BeamSpot/src/alpaka/classes_rocm_def.xml new file mode 100644 index 0000000000000..952d2a8909179 --- /dev/null +++ b/DataFormats/BeamSpot/src/alpaka/classes_rocm_def.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/DataFormats/BeamSpot/src/classes.cc b/DataFormats/BeamSpot/src/classes.cc new file mode 100644 index 0000000000000..10a709c00e2f7 --- /dev/null +++ b/DataFormats/BeamSpot/src/classes.cc @@ -0,0 +1,4 @@ +#include "DataFormats/BeamSpot/interface/BeamSpotHost.h" +#include "DataFormats/Portable/interface/PortableHostObjectReadRules.h" + +SET_PORTABLEHOSTOBJECT_READ_RULES(BeamSpotHost); diff --git a/DataFormats/BeamSpot/src/classes.h b/DataFormats/BeamSpot/src/classes.h index 2365c90fdc257..a74d1b571d4b9 100644 --- a/DataFormats/BeamSpot/src/classes.h +++ b/DataFormats/BeamSpot/src/classes.h @@ -1,3 +1,4 @@ #include "DataFormats/BeamSpot/interface/BeamSpot.h" +#include "DataFormats/BeamSpot/interface/BeamSpotHost.h" #include "DataFormats/BeamSpot/interface/BeamSpotPOD.h" #include "DataFormats/Common/interface/Wrapper.h" diff --git a/DataFormats/BeamSpot/src/classes_def.xml b/DataFormats/BeamSpot/src/classes_def.xml index af3d4e4627c58..10a42156d995c 100644 --- a/DataFormats/BeamSpot/src/classes_def.xml +++ b/DataFormats/BeamSpot/src/classes_def.xml @@ -5,6 +5,11 @@ - - + + + + + + +