diff --git a/DataFormats/Portable/interface/PortableCollection.h b/DataFormats/Portable/interface/PortableCollection.h
new file mode 100644
index 0000000000000..b257010cde702
--- /dev/null
+++ b/DataFormats/Portable/interface/PortableCollection.h
@@ -0,0 +1,54 @@
+#ifndef DataFormats_Portable_interface_PortableCollection_h
+#define DataFormats_Portable_interface_PortableCollection_h
+
+#include <optional>
+
+#include <alpaka/alpaka.hpp>
+
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h"
+
+// generic SoA-based product
+template <typename T, typename TDev>
+class PortableCollection {
+public:
+  using Buffer = alpaka::Buf<TDev, std::byte, alpaka::DimInt<1u>, uint32_t>;
+
+  PortableCollection() : buffer_{}, layout_{} {}
+
+  PortableCollection(int32_t elements, TDev const &device)
+      : buffer_{alpaka::allocBuf<std::byte, uint32_t>(
+            device, alpaka::Vec<alpaka::DimInt<1u>, uint32_t>{T::compute_size(elements)})},
+        layout_{elements, buffer_->data()} {
+    // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
+    assert(reinterpret_cast<uintptr_t>(buffer_->data()) % T::alignment == 0);
+    alpaka::pin(*buffer_);
+  }
+
+  ~PortableCollection() {}
+
+  // non-copyable
+  PortableCollection(PortableCollection const &) = delete;
+  PortableCollection &operator=(PortableCollection const &) = delete;
+
+  // movable
+  PortableCollection(PortableCollection &&other) = default;
+  PortableCollection &operator=(PortableCollection &&other) = default;
+
+  T &operator*() { return layout_; }
+
+  T const &operator*() const { return layout_; }
+
+  T *operator->() { return &layout_; }
+
+  T const *operator->() const { return &layout_; }
+
+  Buffer &buffer() { return *buffer_; }
+
+  Buffer const &buffer() const { return *buffer_; }
+
+private:
+  std::optional<Buffer> buffer_;  //!
+  T layout_;
+};
+
+#endif  // DataFormats_Portable_interface_PortableCollection_h
diff --git a/DataFormats/Portable/interface/PortableHostCollection.h b/DataFormats/Portable/interface/PortableHostCollection.h
new file mode 100644
index 0000000000000..70878ab5eee0f
--- /dev/null
+++ b/DataFormats/Portable/interface/PortableHostCollection.h
@@ -0,0 +1,66 @@
+#ifndef DataFormats_Portable_interface_PortableHostCollection_h
+#define DataFormats_Portable_interface_PortableHostCollection_h
+
+#include <optional>
+
+#include <alpaka/alpaka.hpp>
+
+#include "DataFormats/Portable/interface/PortableCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+// generic SoA-based product in pinned host memory
+template <typename T>
+class PortableCollection<T, alpaka_common::DevHost> {
+public:
+  using Buffer = alpaka::Buf<alpaka_common::DevHost, std::byte, alpaka::DimInt<1u>, uint32_t>;
+
+  PortableCollection() : buffer_{}, layout_{} {}
+
+  PortableCollection(int32_t elements, alpaka_common::DevHost const &host)
+      : buffer_{alpaka::allocBuf<std::byte, uint32_t>(
+            host, alpaka::Vec<alpaka::DimInt<1u>, uint32_t>{T::compute_size(elements)})},
+        layout_{elements, buffer_->data()} {
+    // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
+    assert(reinterpret_cast<uintptr_t>(buffer_->data()) % T::alignment == 0);
+  }
+
+  template <typename TDev>
+  PortableCollection(int32_t elements, alpaka_common::DevHost const &host, TDev const &device)
+      : buffer_{alpaka::allocMappedBuf<std::byte, uint32_t>(
+            host, device, alpaka::Vec<alpaka::DimInt<1u>, uint32_t>{T::compute_size(elements)})},
+        layout_{elements, buffer_->data()} {
+    // Alpaka set to a default alignment of 128 bytes defining ALPAKA_DEFAULT_HOST_MEMORY_ALIGNMENT=128
+    assert(reinterpret_cast<uintptr_t>(buffer_->data()) % T::alignment == 0);
+  }
+
+  ~PortableCollection() {}
+
+  // non-copyable
+  PortableCollection(PortableCollection const &) = delete;
+  PortableCollection &operator=(PortableCollection const &) = delete;
+
+  // movable
+  PortableCollection(PortableCollection &&other) = default;
+  PortableCollection &operator=(PortableCollection &&other) = default;
+
+  T &operator*() { return layout_; }
+
+  T const &operator*() const { return layout_; }
+
+  T *operator->() { return &layout_; }
+
+  T const *operator->() const { return &layout_; }
+
+  Buffer &buffer() { return *buffer_; }
+
+  Buffer const &buffer() const { return *buffer_; }
+
+private:
+  std::optional<Buffer> buffer_;  //!
+  T layout_;
+};
+
+template <typename T>
+using PortableHostCollection = PortableCollection<T, alpaka_common::DevHost>;
+
+#endif  // DataFormats_Portable_interface_PortableHostCollection_h
diff --git a/DataFormats/Portable/interface/alpaka/PortableDeviceCollection.h b/DataFormats/Portable/interface/alpaka/PortableDeviceCollection.h
new file mode 100644
index 0000000000000..d09b743ca85c9
--- /dev/null
+++ b/DataFormats/Portable/interface/alpaka/PortableDeviceCollection.h
@@ -0,0 +1,15 @@
+#ifndef DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h
+#define DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h
+
+#include "DataFormats/Portable/interface/PortableCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  // generic SoA-based product in device memory
+  template <typename T>
+  using PortableDeviceCollection = PortableCollection<T, Device>;
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#endif  // DataFormats_Portable_interface_alpaka_PortableDeviceCollection_h
diff --git a/DataFormats/XyzId/BuildFile.xml b/DataFormats/XyzId/BuildFile.xml
new file mode 100644
index 0000000000000..142e026c4af60
--- /dev/null
+++ b/DataFormats/XyzId/BuildFile.xml
@@ -0,0 +1,11 @@
+<use name="alpaka"/>
+<use name="rootcore"/>
+<use name="DataFormats/Common"/>
+<use name="DataFormats/Portable" source_only="1"/>
+<use name="FWCore/Utilities" source_only="1"/>
+<use name="HeterogeneousCore/AlpakaInterface" source_only="1"/>
+<flags LCG_DICT_HEADER="classes.h"/>
+<flags LCG_DICT_XML="classes_def.xml"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/DataFormats/XyzId/README.md b/DataFormats/XyzId/README.md
new file mode 100644
index 0000000000000..688d49342bb2c
--- /dev/null
+++ b/DataFormats/XyzId/README.md
@@ -0,0 +1,9 @@
+## Define the alpaka-based SoA data formats
+
+Notes:
+  - do not define a dictionary for `XyzIdHostCollection`, because it is the
+    same class as `alpaka_serial_sync::XyzIdDeviceCollection`;
+  - define the dictionary for `alpaka_cuda_async::XyzIdDeviceCollection` as
+    _transient_ only;
+  - the dictionary for `alpaka_cuda_async::XyzIdDeviceCollection` should be
+    defined in a separate library, to factor out the CUDA dependency.
diff --git a/DataFormats/XyzId/interface/XyzIdHostCollection.h b/DataFormats/XyzId/interface/XyzIdHostCollection.h
new file mode 100644
index 0000000000000..01a99dab85319
--- /dev/null
+++ b/DataFormats/XyzId/interface/XyzIdHostCollection.h
@@ -0,0 +1,10 @@
+#ifndef DataFormats_XyzId_interface_XyzIdHostCollection_h
+#define DataFormats_XyzId_interface_XyzIdHostCollection_h
+
+#include "DataFormats/Portable/interface/PortableHostCollection.h"
+#include "DataFormats/XyzId/interface/XyzIdSoA.h"
+
+// SoA with x, y, z, id fields in pinned host memory
+using XyzIdHostCollection = PortableHostCollection<XyzIdSoA>;
+
+#endif  // DataFormats_XyzId_interface_XyzIdHostCollection_h
diff --git a/DataFormats/XyzId/interface/XyzIdSoA.h b/DataFormats/XyzId/interface/XyzIdSoA.h
new file mode 100644
index 0000000000000..922f5658fed27
--- /dev/null
+++ b/DataFormats/XyzId/interface/XyzIdSoA.h
@@ -0,0 +1,162 @@
+#ifndef DataFormats_XyzId_interface_XyzIdSoA_h
+#define DataFormats_XyzId_interface_XyzIdSoA_h
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#ifdef DEBUG_SOA_CTOR_DTOR
+#include <iostream>
+#endif
+
+#include "FWCore/Utilities/interface/typedefs.h"
+
+// SoA layout with x, y, z, id fields
+class XyzIdSoA {
+public:
+  static constexpr size_t alignment = 128;  // align all fields to 128 bytes
+
+  // constructor
+  XyzIdSoA() : size_(0), buffer_(nullptr), x_(nullptr), y_(nullptr), z_(nullptr), id_(nullptr) {
+#ifdef DEBUG_SOA_CTOR_DTOR
+    std::cout << "XyzIdSoA default constructor" << std::endl;
+#endif
+  }
+
+  XyzIdSoA(int32_t size, void *buffer)
+      : size_(size),
+        buffer_(buffer),
+        x_(reinterpret_cast<double *>(reinterpret_cast<intptr_t>(buffer_))),
+        y_(reinterpret_cast<double *>(reinterpret_cast<intptr_t>(x_) + pad(size * sizeof(double)))),
+        z_(reinterpret_cast<double *>(reinterpret_cast<intptr_t>(y_) + pad(size * sizeof(double)))),
+        id_(reinterpret_cast<int32_t *>(reinterpret_cast<intptr_t>(z_) + pad(size * sizeof(double)))) {
+    assert(size == 0 or (size > 0 and buffer != nullptr));
+#ifdef DEBUG_SOA_CTOR_DTOR
+    std::cout << "XyzIdSoA constructor with " << size_ << " elements at 0x" << buffer_ << std::endl;
+#endif
+  }
+
+#ifdef DEBUG_SOA_CTOR_DTOR
+  ~XyzIdSoA() {
+    if (buffer_) {
+      std::cout << "XyzIdSoA destructor with " << size_ << " elements at 0x" << buffer_ << std::endl;
+    } else {
+      std::cout << "XyzIdSoA destructor wihout data" << std::endl;
+    }
+  }
+#else
+  ~XyzIdSoA() = default;
+#endif
+
+  // non-copyable
+  XyzIdSoA(XyzIdSoA const &) = delete;
+  XyzIdSoA &operator=(XyzIdSoA const &) = delete;
+
+  // movable
+#ifdef DEBUG_SOA_CTOR_DTOR
+  XyzIdSoA(XyzIdSoA &&other)
+      : size_(other.size_), buffer_(other.buffer_), x_(other.x_), y_(other.y_), z_(other.z_), id_(other.id_) {
+    std::cout << "XyzIdSoA move constructor with " << size_ << " elements at 0x" << buffer_ << std::endl;
+    other.buffer_ = nullptr;
+  }
+
+  XyzIdSoA &operator=(XyzIdSoA &&other) {
+    size_ = other.size_;
+    buffer_ = other.buffer_;
+    x_ = other.x_;
+    y_ = other.y_;
+    z_ = other.z_;
+    id_ = other.id_;
+    std::cout << "XyzIdSoA move assignment with " << size_ << " elements at 0x" << buffer_ << std::endl;
+    other.buffer_ = nullptr;
+    return *this;
+  }
+#else
+  XyzIdSoA(XyzIdSoA &&other) = default;
+  XyzIdSoA &operator=(XyzIdSoA &&other) = default;
+#endif
+
+  // global accessors
+  int32_t size() const { return size_; }
+
+  uint32_t extent() const { return compute_size(size_); }
+
+  void *data() { return buffer_; }
+  void const *data() const { return buffer_; }
+
+  // element-wise accessors are not implemented for simplicity
+
+  // field-wise accessors
+  double const &x(int32_t i) const {
+    assert(i >= 0);
+    assert(i < size_);
+    return x_[i];
+  }
+
+  double &x(int32_t i) {
+    assert(i >= 0);
+    assert(i < size_);
+    return x_[i];
+  }
+
+  double const &y(int32_t i) const {
+    assert(i >= 0);
+    assert(i < size_);
+    return y_[i];
+  }
+
+  double &y(int32_t i) {
+    assert(i >= 0);
+    assert(i < size_);
+    return y_[i];
+  }
+
+  double const &z(int32_t i) const {
+    assert(i >= 0);
+    assert(i < size_);
+    return z_[i];
+  }
+
+  double &z(int32_t i) {
+    assert(i >= 0);
+    assert(i < size_);
+    return z_[i];
+  }
+
+  int32_t const &id(int32_t i) const {
+    assert(i >= 0);
+    assert(i < size_);
+    return id_[i];
+  }
+
+  int32_t &id(int32_t i) {
+    assert(i >= 0);
+    assert(i < size_);
+    return id_[i];
+  }
+
+  // pad a size (in bytes) to the next multiple of the alignment
+  static constexpr uint32_t pad(size_t size) { return ((size + alignment - 1) / alignment * alignment); }
+
+  // takes the size in elements, returns the size in bytes
+  static constexpr uint32_t compute_size(int32_t elements) {
+    assert(elements >= 0);
+    return pad(elements * sizeof(double)) +  // x
+           pad(elements * sizeof(double)) +  // y
+           pad(elements * sizeof(double)) +  // z
+           elements * sizeof(int32_t);       // id - no need to pad the last field
+  }
+
+private:
+  // non-owned memory
+  cms_int32_t size_;  // must be the same as ROOT's Int_t
+  void *buffer_;      //!
+
+  // layout
+  double *x_;    //[size_]
+  double *y_;    //[size_]
+  double *z_;    //[size_]
+  int32_t *id_;  //[size_]
+};
+
+#endif  // DataFormats_XyzId_interface_XyzIdSoA_h
diff --git a/DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h b/DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h
new file mode 100644
index 0000000000000..f563ca1fd65ce
--- /dev/null
+++ b/DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h
@@ -0,0 +1,15 @@
+#ifndef DataFormats_XyzId_interface_alpaka_XyzIdDeviceCollection_h
+#define DataFormats_XyzId_interface_alpaka_XyzIdDeviceCollection_h
+
+#include "DataFormats/Portable/interface/alpaka/PortableDeviceCollection.h"
+#include "DataFormats/XyzId/interface/XyzIdSoA.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  // SoA with x, y, z, id fields in device global memory
+  using XyzIdDeviceCollection = PortableDeviceCollection<XyzIdSoA>;
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#endif  // DataFormats_XyzId_interface_alpaka_XyzIdDeviceCollection_h
diff --git a/DataFormats/XyzId/src/alpaka/classes_cuda.h b/DataFormats/XyzId/src/alpaka/classes_cuda.h
new file mode 100644
index 0000000000000..46686e2a72cfc
--- /dev/null
+++ b/DataFormats/XyzId/src/alpaka/classes_cuda.h
@@ -0,0 +1,6 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#define ALPAKA_HOST_ONLY
+
+#include "DataFormats/Common/interface/Wrapper.h"
+#include "DataFormats/XyzId/interface/XyzIdSoA.h"
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
diff --git a/DataFormats/XyzId/src/alpaka/classes_cuda_def.xml b/DataFormats/XyzId/src/alpaka/classes_cuda_def.xml
new file mode 100644
index 0000000000000..c0ccfb0c71efe
--- /dev/null
+++ b/DataFormats/XyzId/src/alpaka/classes_cuda_def.xml
@@ -0,0 +1,4 @@
+<lcgdict>
+  <class name="alpaka_cuda_async::XyzIdDeviceCollection" persistent="false"/>
+  <class name="edm::Wrapper<alpaka_cuda_async::XyzIdDeviceCollection>" persistent="false"/>
+</lcgdict>
diff --git a/DataFormats/XyzId/src/alpaka/classes_serial.h b/DataFormats/XyzId/src/alpaka/classes_serial.h
new file mode 100644
index 0000000000000..47a2e8f03504c
--- /dev/null
+++ b/DataFormats/XyzId/src/alpaka/classes_serial.h
@@ -0,0 +1,5 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+
+#include "DataFormats/Common/interface/Wrapper.h"
+#include "DataFormats/XyzId/interface/XyzIdSoA.h"
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
diff --git a/DataFormats/XyzId/src/alpaka/classes_serial_def.xml b/DataFormats/XyzId/src/alpaka/classes_serial_def.xml
new file mode 100644
index 0000000000000..2d855f273f3b8
--- /dev/null
+++ b/DataFormats/XyzId/src/alpaka/classes_serial_def.xml
@@ -0,0 +1,4 @@
+<lcgdict>
+  <class name="alpaka_serial_sync::XyzIdDeviceCollection"/>
+  <class name="edm::Wrapper<alpaka_serial_sync::XyzIdDeviceCollection>" splitLevel="0"/>
+</lcgdict>
diff --git a/DataFormats/XyzId/src/classes.h b/DataFormats/XyzId/src/classes.h
new file mode 100644
index 0000000000000..2547bae676dfe
--- /dev/null
+++ b/DataFormats/XyzId/src/classes.h
@@ -0,0 +1 @@
+#include "DataFormats/XyzId/interface/XyzIdSoA.h"
diff --git a/DataFormats/XyzId/src/classes_def.xml b/DataFormats/XyzId/src/classes_def.xml
new file mode 100644
index 0000000000000..59c9e3eab4437
--- /dev/null
+++ b/DataFormats/XyzId/src/classes_def.xml
@@ -0,0 +1,3 @@
+<lcgdict>
+  <class name="XyzIdSoA"/>
+</lcgdict>
diff --git a/DataFormats/XyzIdCudaAsync/BuildFile.xml b/DataFormats/XyzIdCudaAsync/BuildFile.xml
new file mode 100644
index 0000000000000..ae79b036a8be7
--- /dev/null
+++ b/DataFormats/XyzIdCudaAsync/BuildFile.xml
@@ -0,0 +1,9 @@
+<use name="alpaka-cuda"/>
+<use name="rootcore"/>
+<use name="DataFormats/Common"/>
+<use name="DataFormats/XyzId"/>
+<flags LCG_DICT_HEADER="classes_cuda.h"/>
+<flags LCG_DICT_XML="classes_cuda_def.xml"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/DataFormats/XyzIdCudaAsync/src/classes_cuda.h b/DataFormats/XyzIdCudaAsync/src/classes_cuda.h
new file mode 120000
index 0000000000000..1f02d4849ccd4
--- /dev/null
+++ b/DataFormats/XyzIdCudaAsync/src/classes_cuda.h
@@ -0,0 +1 @@
+../../XyzId/src/alpaka/classes_cuda.h
\ No newline at end of file
diff --git a/DataFormats/XyzIdCudaAsync/src/classes_cuda_def.xml b/DataFormats/XyzIdCudaAsync/src/classes_cuda_def.xml
new file mode 120000
index 0000000000000..5368a08c26ff4
--- /dev/null
+++ b/DataFormats/XyzIdCudaAsync/src/classes_cuda_def.xml
@@ -0,0 +1 @@
+../../XyzId/src/alpaka/classes_cuda_def.xml
\ No newline at end of file
diff --git a/DataFormats/XyzIdSerialSync/BuildFile.xml b/DataFormats/XyzIdSerialSync/BuildFile.xml
new file mode 100644
index 0000000000000..55fbe28b28abe
--- /dev/null
+++ b/DataFormats/XyzIdSerialSync/BuildFile.xml
@@ -0,0 +1,9 @@
+<use name="alpaka-serial"/>
+<use name="rootcore"/>
+<use name="DataFormats/Common"/>
+<use name="DataFormats/XyzId"/>
+<flags LCG_DICT_HEADER="classes_serial.h"/>
+<flags LCG_DICT_XML="classes_serial_def.xml"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/DataFormats/XyzIdSerialSync/src/classes_serial.h b/DataFormats/XyzIdSerialSync/src/classes_serial.h
new file mode 120000
index 0000000000000..a752a7e7997b1
--- /dev/null
+++ b/DataFormats/XyzIdSerialSync/src/classes_serial.h
@@ -0,0 +1 @@
+../../XyzId/src/alpaka/classes_serial.h
\ No newline at end of file
diff --git a/DataFormats/XyzIdSerialSync/src/classes_serial_def.xml b/DataFormats/XyzIdSerialSync/src/classes_serial_def.xml
new file mode 120000
index 0000000000000..8a0fa91cac09c
--- /dev/null
+++ b/DataFormats/XyzIdSerialSync/src/classes_serial_def.xml
@@ -0,0 +1 @@
+../../XyzId/src/alpaka/classes_serial_def.xml
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaCore/BuildFile.xml b/HeterogeneousCore/AlpakaCore/BuildFile.xml
new file mode 100644
index 0000000000000..f839a92152d40
--- /dev/null
+++ b/HeterogeneousCore/AlpakaCore/BuildFile.xml
@@ -0,0 +1,6 @@
+<use name="FWCore/Framework"/>
+<use name="FWCore/ServiceRegistry"/>
+<use name="HeterogeneousCore/AlpakaInterface"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/HeterogeneousCore/AlpakaCore/interface/MakerMacros.h b/HeterogeneousCore/AlpakaCore/interface/MakerMacros.h
new file mode 100644
index 0000000000000..3096f1f3fcf21
--- /dev/null
+++ b/HeterogeneousCore/AlpakaCore/interface/MakerMacros.h
@@ -0,0 +1,11 @@
+#ifndef HeterogeneousCore_AlpakaCore_interface_MakerMacros_h
+#define HeterogeneousCore_AlpakaCore_interface_MakerMacros_h
+
+#include "FWCore/Framework/interface/MakerMacros.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+// force expanding ALPAKA_ACCELERATOR_NAMESPACE before stringification inside DEFINE_FWK_MODULE
+#define DEFINE_FWK_ALPAKA_MODULE2(name) DEFINE_FWK_MODULE(name)
+#define DEFINE_FWK_ALPAKA_MODULE(name) DEFINE_FWK_ALPAKA_MODULE2(ALPAKA_ACCELERATOR_NAMESPACE::name)
+
+#endif  // HeterogeneousCore_AlpakaCore_interface_MakerMacros_h
diff --git a/HeterogeneousCore/AlpakaInterface/BuildFile.xml b/HeterogeneousCore/AlpakaInterface/BuildFile.xml
new file mode 100644
index 0000000000000..06905828f6ea6
--- /dev/null
+++ b/HeterogeneousCore/AlpakaInterface/BuildFile.xml
@@ -0,0 +1,4 @@
+<use name="alpaka"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/HeterogeneousCore/AlpakaInterface/README.md b/HeterogeneousCore/AlpakaInterface/README.md
new file mode 100644
index 0000000000000..709098b772665
--- /dev/null
+++ b/HeterogeneousCore/AlpakaInterface/README.md
@@ -0,0 +1,6 @@
+## HeterogeneousCore/AlpakaInterface
+
+This package only depends on the `alpaka` header-only external library, and
+provides the interface used by other packages in CMSSW.
+
+It is safe to be used inside DataFormats packages.
diff --git a/HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h b/HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h
new file mode 100644
index 0000000000000..a5ea8c0289594
--- /dev/null
+++ b/HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h
@@ -0,0 +1,164 @@
+#ifndef HeterogeneousCore_AlpakaInterface_interface_alpaka_config_h
+#define HeterogeneousCore_AlpakaInterface_interface_alpaka_config_h
+
+#include <type_traits>
+
+#include <alpaka/alpaka.hpp>
+
+#include "FWCore/Utilities/interface/stringize.h"
+
+namespace alpaka_common {
+
+  // common types and dimensions
+  using Idx = uint32_t;
+  using Extent = uint32_t;
+  using Offsets = Extent;
+
+  using Dim0D = alpaka::DimInt<0u>;
+  using Dim1D = alpaka::DimInt<1u>;
+  using Dim2D = alpaka::DimInt<2u>;
+  using Dim3D = alpaka::DimInt<3u>;
+
+  template <typename TDim>
+  using Vec = alpaka::Vec<TDim, Idx>;
+  using Vec1D = Vec<Dim1D>;
+  using Vec2D = Vec<Dim2D>;
+  using Vec3D = Vec<Dim3D>;
+  using Scalar = Vec<Dim0D>;
+
+  template <typename TDim>
+  using WorkDiv = alpaka::WorkDivMembers<TDim, Idx>;
+  using WorkDiv1D = WorkDiv<Dim1D>;
+  using WorkDiv2D = WorkDiv<Dim2D>;
+  using WorkDiv3D = WorkDiv<Dim3D>;
+
+  // host types
+  using DevHost = alpaka::DevCpu;
+  using PltfHost = alpaka::Pltf<DevHost>;
+
+}  // namespace alpaka_common
+
+#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
+namespace alpaka_cuda_async {
+  using namespace alpaka_common;
+
+  using Platform = alpaka::PltfCudaRt;
+  using Device = alpaka::DevCudaRt;
+  using Queue = alpaka::QueueCudaRtNonBlocking;
+  using Event = alpaka::EventCudaRt;
+
+  template <typename TDim>
+  using Acc = alpaka::AccGpuCudaRt<TDim, Idx>;
+  using Acc1D = Acc<Dim1D>;
+  using Acc2D = Acc<Dim2D>;
+  using Acc3D = Acc<Dim3D>;
+
+}  // namespace alpaka_cuda_async
+
+#ifdef ALPAKA_ACCELERATOR_NAMESPACE
+#define ALPAKA_DUPLICATE_NAMESPACE
+#else
+#define ALPAKA_ACCELERATOR_NAMESPACE alpaka_cuda_async
+#define ALPAKA_TYPE_SUFFIX CudaAsync
+#endif
+
+#endif  // ALPAKA_ACC_GPU_CUDA_ENABLED
+
+#ifdef ALPAKA_ACC_GPU_HIP_ENABLED
+namespace alpaka_hip_async {
+  using namespace alpaka_common;
+
+  using Platform = alpaka::PltfHipRt;
+  using Device = alpaka::DevHipRt;
+  using Queue = alpaka::QueueHipRtNonBlocking;
+  using Event = alpaka::EventHipRt;
+
+  template <typename TDim>
+  using Acc = alpaka::AccGpuHipRt<TDim, Idx>;
+  using Acc1D = Acc<Dim1D>;
+  using Acc2D = Acc<Dim2D>;
+  using Acc3D = Acc<Dim3D>;
+
+}  // namespace alpaka_hip_async
+
+#ifdef ALPAKA_ACCELERATOR_NAMESPACE
+#define ALPAKA_DUPLICATE_NAMESPACE
+#else
+#define ALPAKA_ACCELERATOR_NAMESPACE alpaka_hip_async
+#define ALPAKA_TYPE_SUFFIX HipAsync
+#endif
+
+#endif  // ALPAKA_ACC_GPU_HIP_ENABLED
+
+#ifdef ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+namespace alpaka_serial_sync {
+  using namespace alpaka_common;
+
+  using Platform = alpaka::PltfCpu;
+  using Device = alpaka::DevCpu;
+  using Queue = alpaka::QueueCpuBlocking;
+  using Event = alpaka::EventCpu;
+
+  template <typename TDim>
+  using Acc = alpaka::AccCpuSerial<TDim, Idx>;
+  using Acc1D = Acc<Dim1D>;
+  using Acc2D = Acc<Dim2D>;
+  using Acc3D = Acc<Dim3D>;
+
+}  // namespace alpaka_serial_sync
+
+#ifdef ALPAKA_ACCELERATOR_NAMESPACE
+#define ALPAKA_DUPLICATE_NAMESPACE
+#else
+#define ALPAKA_ACCELERATOR_NAMESPACE alpaka_serial_sync
+#define ALPAKA_TYPE_SUFFIX SerialSync
+#endif
+
+#endif  // ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+
+#ifdef ALPAKA_ACC_CPU_B_TBB_T_SEQ_ENABLED
+namespace alpaka_tbb_async {
+  using namespace alpaka_common;
+
+  using Platform = alpaka::PltfCpu;
+  using Device = alpaka::DevCpu;
+  using Queue = alpaka::QueueCpuNonBlocking;
+  using Event = alpaka::EventCpu;
+
+  template <typename TDim>
+  using Acc = alpaka::AccCpuTbbBlocks<TDim, Idx>;
+  using Acc1D = Acc<Dim1D>;
+  using Acc2D = Acc<Dim2D>;
+  using Acc3D = Acc<Dim3D>;
+
+}  // namespace alpaka_tbb_async
+
+#ifdef ALPAKA_ACCELERATOR_NAMESPACE
+#define ALPAKA_DUPLICATE_NAMESPACE
+#else
+#define ALPAKA_ACCELERATOR_NAMESPACE alpaka_tbb_async
+#define ALPAKA_TYPE_SUFFIX TbbAsync
+#endif
+
+#endif  // ALPAKA_ACC_CPU_B_TBB_T_SEQ_ENABLED
+
+#if defined ALPAKA_DUPLICATE_NAMESPACE
+#error Only one alpaka backend symbol can be defined at the same time: ALPAKA_ACC_GPU_CUDA_ENABLED, ALPAKA_ACC_GPU_HIP_ENABLED, ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED, ALPAKA_ACC_CPU_B_TBB_T_SEQ_ENABLED.
+#endif
+
+#if defined ALPAKA_ACCELERATOR_NAMESPACE
+
+// create a new backend-specific identifier based on the original type name and a backend-specific suffix
+#define ALPAKA_TYPE_ALIAS__(TYPE, SUFFIX) TYPE##SUFFIX
+#define ALPAKA_TYPE_ALIAS_(TYPE, SUFFIX) ALPAKA_TYPE_ALIAS__(TYPE, SUFFIX)
+#define ALPAKA_TYPE_ALIAS(TYPE) ALPAKA_TYPE_ALIAS_(TYPE, ALPAKA_TYPE_SUFFIX)
+
+// declare the backend-specific identifier as an alias for the namespace-based type name
+#define DECLARE_ALPAKA_TYPE_ALIAS(TYPE) using ALPAKA_TYPE_ALIAS(TYPE) = ALPAKA_ACCELERATOR_NAMESPACE::TYPE
+
+// define a null-terminated string containing the backend-specific identifier
+#define ALPAKA_TYPE_ALIAS_NAME(TYPE) EDM_STRINGIZE(ALPAKA_TYPE_ALIAS(TYPE))
+
+#endif  // ALPAKA_ACCELERATOR_NAMESPACE
+
+#endif  // HeterogeneousCore_AlpakaInterface_interface_alpaka_config_h
diff --git a/HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h b/HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h
new file mode 100644
index 0000000000000..39a54b3dffe51
--- /dev/null
+++ b/HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h
@@ -0,0 +1,9 @@
+#ifndef HeterogeneousCore_AlpakaInterface_interface_alpaka_host_h
+#define HeterogeneousCore_AlpakaInterface_interface_alpaka_host_h
+
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+// alpaka host device
+inline const alpaka_common::DevHost host = alpaka::getDevByIdx<alpaka_common::PltfHost>(0u);
+
+#endif  // HeterogeneousCore_AlpakaInterface_interface_alpaka_host_h
diff --git a/HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h b/HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h
new file mode 100644
index 0000000000000..17a8c7d512cd4
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h
@@ -0,0 +1,41 @@
+#ifndef HeterogeneousCore_AlpakaServices_interface_AlpakaService_h
+#define HeterogeneousCore_AlpakaServices_interface_AlpakaService_h
+
+#include <vector>
+
+#include <alpaka/alpaka.hpp>
+
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+namespace edm {
+  class ActivityRegistry;
+  class ConfigurationDescriptions;
+  class ParameterSet;
+}  // namespace edm
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  class AlpakaService {
+  public:
+    AlpakaService(edm::ParameterSet const& config, edm::ActivityRegistry&);
+    ~AlpakaService();
+
+    static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
+
+    bool enabled() const { return enabled_; }
+
+    std::vector<Device> const& devices() const { return devices_; }
+
+    Device const& device(uint32_t index) const { return devices_.at(index); }
+
+  private:
+    bool enabled_ = false;
+    bool verbose_ = false;
+    std::vector<Device> devices_;
+  };
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+DECLARE_ALPAKA_TYPE_ALIAS(AlpakaService);
+
+#endif  // HeterogeneousCore_AlpakaServices_interface_AlpakaService_h
diff --git a/HeterogeneousCore/AlpakaServices/plugins/alpaka/plugins.cc b/HeterogeneousCore/AlpakaServices/plugins/alpaka/plugins.cc
new file mode 100644
index 0000000000000..cda77778585b7
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServices/plugins/alpaka/plugins.cc
@@ -0,0 +1,5 @@
+#include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+#include "HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h"
+
+DEFINE_FWK_SERVICE(ALPAKA_TYPE_ALIAS(AlpakaService));
diff --git a/HeterogeneousCore/AlpakaServices/src/alpaka/AlpakaService.cc b/HeterogeneousCore/AlpakaServices/src/alpaka/AlpakaService.cc
new file mode 100644
index 0000000000000..4e00b3ec9be0f
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServices/src/alpaka/AlpakaService.cc
@@ -0,0 +1,86 @@
+#include <iomanip>
+#include <iostream>
+#include <limits>
+
+#include <boost/core/demangle.hpp>
+
+#include <alpaka/alpaka.hpp>
+
+#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 "HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h"
+
+#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
+#include "FWCore/ServiceRegistry/interface/Service.h"
+#include "HeterogeneousCore/CUDAServices/interface/CUDAService.h"
+#endif  // ALPAKA_ACC_GPU_CUDA_ENABLED
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  AlpakaService::AlpakaService(edm::ParameterSet const& config, edm::ActivityRegistry&)
+      : enabled_(config.getUntrackedParameter<bool>("enabled")),
+        verbose_(config.getUntrackedParameter<bool>("verbose")) {
+#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
+    // rely on the CUDAService to initialise the CUDA devices
+    edm::Service<CUDAService> cudaService;
+#endif  // ALPAKA_ACC_GPU_CUDA_ENABLED
+
+    // TODO
+    //   - handle alpaka caching allocators ?
+    //   - extract and print more information about the platform and devices
+
+    if (not enabled_) {
+      edm::LogInfo("AlpakaService") << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << " disabled by configuration";
+      return;
+    }
+
+#ifdef ALPAKA_ACC_GPU_CUDA_ENABLED
+    if (not cudaService->enabled()) {
+      enabled_ = false;
+      edm::LogInfo("AlpakaService") << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << " disabled by CUDAService";
+      return;
+    }
+#endif  // ALPAKA_ACC_GPU_CUDA_ENABLED
+
+    // enumerate all devices on this platform
+    uint32_t n = alpaka::getDevCount<Platform>();
+    if (n == 0) {
+      const std::string platform = boost::core::demangle(typeid(Platform).name());
+      edm::LogWarning("AlpakaService") << "Could not find any divices on platform " << platform << ".\n"
+                                       << "Disabling " << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << ".";
+      enabled_ = false;
+      return;
+    }
+
+    devices_.reserve(n);
+    for (uint32_t i = 0; i < n; ++i) {
+      devices_.push_back(alpaka::getDevByIdx<Platform>(i));
+      //assert(getDeviceIndex(devices_.back()) == static_cast<int>(i));
+    }
+
+    {
+      const char* suffix[] = {"s.", ":", "s:"};
+      edm::LogInfo out("AlpakaService");
+      out << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << " succesfully initialised.\n";
+      out << "Found " << n << " device" << suffix[n < 2 ? n : 2];
+      for (auto const& device : devices_) {
+        out << "\n  - " << alpaka::getName(device);
+      }
+    }
+  }
+
+  AlpakaService::~AlpakaService() {
+    // TODO
+  }
+
+  void AlpakaService::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+    edm::ParameterSetDescription desc;
+    desc.addUntracked<bool>("enabled", true);
+    desc.addUntracked<bool>("verbose", false);
+
+    descriptions.add(ALPAKA_TYPE_ALIAS_NAME(AlpakaService), desc);
+  }
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/BuildFile.xml b/HeterogeneousCore/AlpakaServicesCudaAsync/BuildFile.xml
new file mode 100644
index 0000000000000..25ca7a0280a51
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/BuildFile.xml
@@ -0,0 +1,11 @@
+<use name="alpaka-cuda"/>
+<use name="boost"/>
+<use name="FWCore/MessageLogger"/>
+<use name="FWCore/ParameterSet"/>
+<use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+<use name="HeterogeneousCore/AlpakaInterface" source_only="1"/>
+<!-- This dependency is added only for the CUDA backend -->
+<use name="HeterogeneousCore/CUDAServices"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/README.md b/HeterogeneousCore/AlpakaServicesCudaAsync/README.md
new file mode 100644
index 0000000000000..1ed2480ba9ef1
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/README.md
@@ -0,0 +1,7 @@
+## HeterogeneousCore/AlpakaServicesCudaAsync
+
+This is a dummy package to emulate the expected behaviour of the build system.
+The .../alpaka/ directories are symlinked from HeterogeneousCore/AlpakaServices
+to avoid the scram error about the inclusion of private source files.
+Its content should eventually be built from HeterogeneousCore/AlpakaServices for
+the cuda async backend.
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/BuildFile.xml b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/BuildFile.xml
new file mode 100644
index 0000000000000..b58a61405ce5b
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/BuildFile.xml
@@ -0,0 +1,12 @@
+<library file="*.cc" name="HeterogeneousCoreAlpakaServicesCudaAsyncPlugins">
+  <use name="alpaka-cuda"/>
+  <use name="FWCore/ServiceRegistry"/>
+  <use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+  <!--
+  The dependency on "HeterogeneousCore/AlpakaServices" should automatically expand to
+  "HeterogeneousCore/AlpakaServices" and "HeterogeneousCore/AlpakaServicesCudaAsync"
+  (if they exist)
+  -->
+  <use name="HeterogeneousCore/AlpakaServicesCudaAsync"/>
+  <flags EDM_PLUGIN="1"/>
+</library>
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/alpaka b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/alpaka
new file mode 120000
index 0000000000000..c07bb7e4fcd38
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/alpaka
@@ -0,0 +1 @@
+../../AlpakaServices/plugins/alpaka
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/plugins.cc b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/plugins.cc
new file mode 100644
index 0000000000000..209f67887da0f
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/plugins/plugins.cc
@@ -0,0 +1,3 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#define ALPAKA_HOST_ONLY
+#include "alpaka/plugins.cc"
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/src/AlpakaService.cc b/HeterogeneousCore/AlpakaServicesCudaAsync/src/AlpakaService.cc
new file mode 100644
index 0000000000000..7cfacc86c0e3a
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/src/AlpakaService.cc
@@ -0,0 +1,3 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#define ALPAKA_HOST_ONLY
+#include "alpaka/AlpakaService.cc"
diff --git a/HeterogeneousCore/AlpakaServicesCudaAsync/src/alpaka b/HeterogeneousCore/AlpakaServicesCudaAsync/src/alpaka
new file mode 120000
index 0000000000000..2bf74ab3a89bd
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesCudaAsync/src/alpaka
@@ -0,0 +1 @@
+../../AlpakaServices/src/alpaka
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/BuildFile.xml b/HeterogeneousCore/AlpakaServicesSerialSync/BuildFile.xml
new file mode 100644
index 0000000000000..55da51db92b65
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/BuildFile.xml
@@ -0,0 +1,9 @@
+<use name="alpaka-serial"/>
+<use name="boost"/>
+<use name="FWCore/MessageLogger"/>
+<use name="FWCore/ParameterSet"/>
+<use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+<use name="HeterogeneousCore/AlpakaInterface" source_only="1"/>
+<export>
+  <lib name="1"/>
+</export>
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/README.md b/HeterogeneousCore/AlpakaServicesSerialSync/README.md
new file mode 100644
index 0000000000000..c80ed197a4207
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/README.md
@@ -0,0 +1,7 @@
+## HeterogeneousCore/AlpakaServicesSerialSync
+
+This is a dummy package to emulate the expected behaviour of the build system.
+The .../alpaka/ directories are symlinked from HeterogeneousCore/AlpakaServices
+to avoid the scram error about the inclusion of private source files.
+Its content should eventually be built from HeterogeneousCore/AlpakaServices for
+the serial sync backend.
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/plugins/BuildFile.xml b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/BuildFile.xml
new file mode 100644
index 0000000000000..62d665c5174f2
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/BuildFile.xml
@@ -0,0 +1,12 @@
+<library file="*.cc" name="HeterogeneousCoreAlpakaServicesSerialSyncPlugins">
+  <use name="alpaka-serial"/>
+  <use name="FWCore/ServiceRegistry"/>
+  <use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+  <!--
+  The dependency on "HeterogeneousCore/AlpakaServices" should automatically expand to
+  "HeterogeneousCore/AlpakaServices" and "HeterogeneousCore/AlpakaServicesSerialSync"
+  (if they exist)
+  -->
+  <use name="HeterogeneousCore/AlpakaServicesSerialSync"/>
+  <flags EDM_PLUGIN="1"/>
+</library>
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/plugins/alpaka b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/alpaka
new file mode 120000
index 0000000000000..c07bb7e4fcd38
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/alpaka
@@ -0,0 +1 @@
+../../AlpakaServices/plugins/alpaka
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/plugins/plugins.cc b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/plugins.cc
new file mode 100644
index 0000000000000..139665715a41e
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/plugins/plugins.cc
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+#include "alpaka/plugins.cc"
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/src/AlpakaService.cc b/HeterogeneousCore/AlpakaServicesSerialSync/src/AlpakaService.cc
new file mode 100644
index 0000000000000..3e62d6a1d9781
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/src/AlpakaService.cc
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+#include "alpaka/AlpakaService.cc"
diff --git a/HeterogeneousCore/AlpakaServicesSerialSync/src/alpaka b/HeterogeneousCore/AlpakaServicesSerialSync/src/alpaka
new file mode 120000
index 0000000000000..2bf74ab3a89bd
--- /dev/null
+++ b/HeterogeneousCore/AlpakaServicesSerialSync/src/alpaka
@@ -0,0 +1 @@
+../../AlpakaServices/src/alpaka
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.dev.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.dev.cc
new file mode 100644
index 0000000000000..26799232178e3
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.dev.cc
@@ -0,0 +1,22 @@
+#include <alpaka/alpaka.hpp>
+
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+#include "XyzIdAlgo.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  void XyzIdAlgo::fill(Queue& queue, XyzIdDeviceCollection& collection) const {
+    auto const& deviceProperties = alpaka::getAccDevProps<Acc1D>(alpaka::getDev(queue));
+    uint32_t maxThreadsPerBlock = deviceProperties.m_blockThreadExtentMax[0];
+
+    uint32_t threadsPerBlock = maxThreadsPerBlock;
+    uint32_t blocksPerGrid = (collection->size() + threadsPerBlock - 1) / threadsPerBlock;
+    uint32_t elementsPerThread = 1;
+    auto workDiv = WorkDiv1D{blocksPerGrid, threadsPerBlock, elementsPerThread};
+
+    alpaka::exec<Acc1D>(queue, workDiv, XyzIdAlgoKernel{}, &collection->id(0), collection->size());
+  }
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.h b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.h
new file mode 100644
index 0000000000000..0c7d65639d535
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlgo.h
@@ -0,0 +1,29 @@
+#ifndef HeterogeneousCore_AlpakaTest_plugins_alpaka_XyzIdAlgo_h
+#define HeterogeneousCore_AlpakaTest_plugins_alpaka_XyzIdAlgo_h
+
+#include <alpaka/alpaka.hpp>
+
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+class XyzIdAlgoKernel {
+public:
+  template <typename TAcc>
+  ALPAKA_FN_ACC void operator()(TAcc const& acc, int32_t* id, int32_t size) const {
+    int32_t idx = alpaka::getIdx<alpaka::Grid, alpaka::Threads>(acc)[0u];
+    if (idx < size) {
+      id[idx] = idx;
+    }
+  }
+};
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  class XyzIdAlgo {
+  public:
+    void fill(Queue& queue, XyzIdDeviceCollection& collection) const;
+  };
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#endif  // HeterogeneousCore_AlpakaTest_plugins_alpaka_XyzIdAlgo_h
diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaAnalyzer.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaAnalyzer.cc
new file mode 100644
index 0000000000000..77009605d16ac
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaAnalyzer.cc
@@ -0,0 +1,53 @@
+// The "Analyzer" makes sense only in the cpu memory space
+#if defined(ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED)
+
+#include <cassert>
+#include <string>
+#include <iostream>
+
+#include "DataFormats/XyzId/interface/XyzIdHostCollection.h"
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/EventSetup.h"
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDAnalyzer.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"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  class XyzIdAlpakaAnalyzer : public edm::stream::EDAnalyzer<> {
+  public:
+    XyzIdAlpakaAnalyzer(edm::ParameterSet const& config)
+        : source_{config.getParameter<edm::InputTag>("source")}, token_{consumes<XyzIdHostCollection>(source_)} {}
+
+    void analyze(edm::Event const& event, edm::EventSetup const&) override {
+      XyzIdHostCollection const& product = event.get(token_);
+
+      for (int32_t i = 0; i < product->size(); ++i) {
+        //std::cout << source_ << "[" << i << "] = " << product->id(i) << std::endl;
+        assert(product->id(i) == i);
+      }
+      std::cout << "XyzIdAlpakaAnalyzer:\n" << source_.encode() << ".size() = " << product->size() << std::endl;
+    }
+
+    static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+      edm::ParameterSetDescription desc;
+      desc.add<edm::InputTag>("source");
+      descriptions.addWithDefaultLabel(desc);
+    }
+
+  private:
+    const edm::InputTag source_;
+    const edm::EDGetTokenT<XyzIdHostCollection> token_;
+  };
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#include "HeterogeneousCore/AlpakaCore/interface/MakerMacros.h"
+DEFINE_FWK_ALPAKA_MODULE(XyzIdAlpakaAnalyzer);
+
+#endif  // defined(ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED)
diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaProducer.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaProducer.cc
new file mode 100644
index 0000000000000..328d4b7e4e681
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaProducer.cc
@@ -0,0 +1,76 @@
+#include <optional>
+#include <string>
+
+#include <alpaka/alpaka.hpp>
+
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/EventSetup.h"
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
+#include "FWCore/ServiceRegistry/interface/Service.h"
+#include "FWCore/Utilities/interface/EDGetToken.h"
+#include "FWCore/Utilities/interface/InputTag.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h"
+#include "HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h"
+
+#include "XyzIdAlgo.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  class XyzIdAlpakaProducer : public edm::stream::EDProducer<> {
+  public:
+    XyzIdAlpakaProducer(edm::ParameterSet const& config)
+        : deviceToken_{produces<XyzIdDeviceCollection>()}, size_{config.getParameter<int32_t>("size")} {}
+
+    void beginStream(edm::StreamID sid) override {
+      // choose a device based on the EDM stream number
+      edm::Service<ALPAKA_TYPE_ALIAS(AlpakaService)> service;
+      if (not service->enabled()) {
+        throw cms::Exception("Configuration") << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << " is disabled.";
+      }
+      auto& devices = service->devices();
+      unsigned int index = sid.value() % devices.size();
+      device_ = devices[index];
+    }
+
+    void produce(edm::Event& event, edm::EventSetup const&) override {
+      // create a queue to submit async work
+      Queue queue{*device_};
+      XyzIdDeviceCollection deviceProduct{size_, *device_};
+
+      // run the algorithm, potentially asynchronously
+      algo_.fill(queue, deviceProduct);
+
+      // wait for any asynchronous work to complete
+      alpaka::wait(queue);
+
+      event.emplace(deviceToken_, std::move(deviceProduct));
+    }
+
+    static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+      edm::ParameterSetDescription desc;
+      desc.add<int32_t>("size");
+      descriptions.addWithDefaultLabel(desc);
+    }
+
+  private:
+    const edm::EDPutTokenT<XyzIdDeviceCollection> deviceToken_;
+    const int32_t size_;
+
+    // device associated to the EDM stream
+    std::optional<Device> device_;
+
+    // implementation of the algorithm
+    XyzIdAlgo algo_;
+  };
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#include "HeterogeneousCore/AlpakaCore/interface/MakerMacros.h"
+DEFINE_FWK_ALPAKA_MODULE(XyzIdAlpakaProducer);
diff --git a/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaTranscriber.cc b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaTranscriber.cc
new file mode 100644
index 0000000000000..33bdbc3ca52c2
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/plugins/alpaka/XyzIdAlpakaTranscriber.cc
@@ -0,0 +1,78 @@
+// The "Transcriber" makes sense only across different memory spaces
+#if defined(ALPAKA_ACC_GPU_CUDA_ENABLED) or defined(ALPAKA_ACC_GPU_HIP_ENABLED)
+
+#include <optional>
+#include <string>
+
+#include <alpaka/alpaka.hpp>
+
+#include "DataFormats/XyzId/interface/XyzIdHostCollection.h"
+#include "DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h"
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/EventSetup.h"
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/stream/EDProducer.h"
+#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
+#include "FWCore/ServiceRegistry/interface/Service.h"
+#include "FWCore/Utilities/interface/EDGetToken.h"
+#include "FWCore/Utilities/interface/InputTag.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/config.h"
+#include "HeterogeneousCore/AlpakaInterface/interface/alpaka/host.h"
+#include "HeterogeneousCore/AlpakaServices/interface/alpaka/AlpakaService.h"
+
+namespace ALPAKA_ACCELERATOR_NAMESPACE {
+
+  class XyzIdAlpakaTranscriber : public edm::stream::EDProducer<> {
+  public:
+    XyzIdAlpakaTranscriber(edm::ParameterSet const& config)
+        : deviceToken_{consumes<XyzIdDeviceCollection>(config.getParameter<edm::InputTag>("source"))},
+          hostToken_{produces<XyzIdHostCollection>()} {}
+
+    void beginStream(edm::StreamID sid) override {
+      // choose a device based on the EDM stream number
+      edm::Service<ALPAKA_TYPE_ALIAS(AlpakaService)> service;
+      if (not service->enabled()) {
+        throw cms::Exception("Configuration") << ALPAKA_TYPE_ALIAS_NAME(AlpakaService) << " is disabled.";
+      }
+      auto& devices = service->devices();
+      unsigned int index = sid.value() % devices.size();
+      device = devices[index];
+    }
+
+    void produce(edm::Event& event, edm::EventSetup const&) override {
+      // create a queue to submit async work
+      Queue queue{*device};
+      XyzIdDeviceCollection const& deviceProduct = event.get(deviceToken_);
+
+      XyzIdHostCollection hostProduct{deviceProduct->size(), host, *device};
+      alpaka::memcpy(queue, hostProduct.buffer(), deviceProduct.buffer());
+
+      // wait for any async work to complete
+      alpaka::wait(queue);
+
+      event.emplace(hostToken_, std::move(hostProduct));
+    }
+
+    static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+      edm::ParameterSetDescription desc;
+      desc.add<edm::InputTag>("source");
+      descriptions.addWithDefaultLabel(desc);
+    }
+
+  private:
+    const edm::EDGetTokenT<XyzIdDeviceCollection> deviceToken_;
+    const edm::EDPutTokenT<XyzIdHostCollection> hostToken_;
+
+    // device associated to the EDM stream
+    std::optional<Device> device;
+  };
+
+}  // namespace ALPAKA_ACCELERATOR_NAMESPACE
+
+#include "HeterogeneousCore/AlpakaCore/interface/MakerMacros.h"
+DEFINE_FWK_ALPAKA_MODULE(XyzIdAlpakaTranscriber);
+
+#endif  // defined(ALPAKA_ACC_GPU_CUDA_ENABLED) or defined(ALPAKA_ACC_GPU_HIP_ENABLED)
diff --git a/HeterogeneousCore/AlpakaTest/test/reader.py b/HeterogeneousCore/AlpakaTest/test/reader.py
new file mode 100644
index 0000000000000..8ad0fe6631f56
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/test/reader.py
@@ -0,0 +1,26 @@
+import FWCore.ParameterSet.Config as cms
+
+process = cms.Process("Reader")
+
+process.source = cms.Source("PoolSource",
+    fileNames = cms.untracked.vstring('file:xyzid.root')
+)
+
+process.load("FWCore.MessageService.MessageLogger_cfi")
+
+process.AlpakaServiceSerialSync = cms.Service("AlpakaServiceSerialSync")
+process.MessageLogger.AlpakaService = cms.untracked.PSet()
+
+process.xyzIdAlpakaAnalyzerFromCuda = cms.EDAnalyzer('alpaka_serial_sync::XyzIdAlpakaAnalyzer',
+    source = cms.InputTag('xyzIdAlpakaTranscriberFromCuda')
+)
+
+process.xyzIdAlpakaAnalyzerSerial = cms.EDAnalyzer('alpaka_serial_sync::XyzIdAlpakaAnalyzer',
+    source = cms.InputTag('xyzIdAlpakaProducerSerial')
+)
+
+process.cuda_path = cms.Path(process.xyzIdAlpakaAnalyzerFromCuda)
+
+process.serial_path = cms.Path(process.xyzIdAlpakaAnalyzerSerial)
+
+process.maxEvents.input = 10
diff --git a/HeterogeneousCore/AlpakaTest/test/writer.py b/HeterogeneousCore/AlpakaTest/test/writer.py
new file mode 100644
index 0000000000000..1888082264c39
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTest/test/writer.py
@@ -0,0 +1,56 @@
+import FWCore.ParameterSet.Config as cms
+
+process = cms.Process("Writer")
+
+process.source = cms.Source("EmptySource")
+
+process.load("FWCore.MessageService.MessageLogger_cfi")
+
+process.add_(cms.Service("CUDAService"))
+process.MessageLogger.CUDAService = cms.untracked.PSet()
+
+process.AlpakaServiceCudaAsync = cms.Service("AlpakaServiceCudaAsync")
+process.AlpakaServiceSerialSync = cms.Service("AlpakaServiceSerialSync")
+process.MessageLogger.AlpakaService = cms.untracked.PSet()
+
+process.xyzIdAlpakaProducerCuda = cms.EDProducer('alpaka_cuda_async::XyzIdAlpakaProducer',
+    size = cms.int32(42)
+)
+
+process.xyzIdAlpakaTranscriberFromCuda = cms.EDProducer('alpaka_cuda_async::XyzIdAlpakaTranscriber',
+    source = cms.InputTag('xyzIdAlpakaProducerCuda')
+)
+
+process.xyzIdAlpakaAnalyzerFromCuda = cms.EDAnalyzer('alpaka_serial_sync::XyzIdAlpakaAnalyzer',
+    source = cms.InputTag('xyzIdAlpakaTranscriberFromCuda')
+)
+
+process.xyzIdAlpakaProducerSerial = cms.EDProducer('alpaka_serial_sync::XyzIdAlpakaProducer',
+    size = cms.int32(42)
+)
+
+process.xyzIdAlpakaAnalyzerSerial = cms.EDAnalyzer('alpaka_serial_sync::XyzIdAlpakaAnalyzer',
+    source = cms.InputTag('xyzIdAlpakaProducerSerial')
+)
+
+process.output = cms.OutputModule("PoolOutputModule",
+    fileName = cms.untracked.string("xyzid.root"),
+    outputCommands = cms.untracked.vstring(
+        'drop *',
+        'keep *_xyzIdAlpakaTranscriberFromCuda_*_*',
+        'keep *_xyzIdAlpakaProducerSerial_*_*',
+  )
+)
+
+process.cuda_path = cms.Path(
+    process.xyzIdAlpakaProducerCuda +
+    process.xyzIdAlpakaTranscriberFromCuda +
+    process.xyzIdAlpakaAnalyzerFromCuda)
+
+process.serial_path = cms.Path(
+    process.xyzIdAlpakaProducerSerial +
+    process.xyzIdAlpakaAnalyzerSerial)
+
+process.output_path = cms.EndPath(process.output)
+
+process.maxEvents.input = 10
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/README.md b/HeterogeneousCore/AlpakaTestCudaAsync/README.md
new file mode 100644
index 0000000000000..8a9d0d206ce07
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/README.md
@@ -0,0 +1,7 @@
+## HeterogeneousCore/AlpakaTestCudaAsync
+
+This is a dummy package to emulate the expected behaviour of the build system.
+The .../alpaka/ directories are symlinked from HeterogeneousCore/AlpakaTest
+to avoid the scram error about the inclusion of private source files.
+Its content should eventually be built from HeterogeneousCore/AlpakaTest for
+the cuda async backend.
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/plugins/BuildFile.xml b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/BuildFile.xml
new file mode 100644
index 0000000000000..8529f569de5b7
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/BuildFile.xml
@@ -0,0 +1,11 @@
+<library file="*.cc *.cu" name="HeterogeneousCoreAlpakaTestCudaAsyncPlugins">
+  <use name="alpaka-cuda"/>
+  <use name="DataFormats/XyzId"/>
+  <use name="DataFormats/XyzIdCudaAsync"/>
+  <use name="FWCore/Framework"/>
+  <use name="FWCore/ParameterSet"/>
+  <use name="FWCore/Utilities"/>
+  <use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+  <use name="HeterogeneousCore/AlpakaInterface" source_only="1"/>
+  <flags EDM_PLUGIN="1"/>
+</library>
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdAlgo.cu b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdAlgo.cu
new file mode 100644
index 0000000000000..a4618c8d71139
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdAlgo.cu
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#include "alpaka/XyzIdAlgo.dev.cc"
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaProducer.cc b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaProducer.cc
new file mode 100644
index 0000000000000..3467195dec554
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaProducer.cc
@@ -0,0 +1,3 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#define ALPAKA_HOST_ONLY
+#include "alpaka/XyzIdAlpakaProducer.cc"
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaTranscriber.cc b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaTranscriber.cc
new file mode 100644
index 0000000000000..2ed64289cf715
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/XyzIdCudaTranscriber.cc
@@ -0,0 +1,3 @@
+#define ALPAKA_ACC_GPU_CUDA_ENABLED
+#define ALPAKA_HOST_ONLY
+#include "alpaka/XyzIdAlpakaTranscriber.cc"
diff --git a/HeterogeneousCore/AlpakaTestCudaAsync/plugins/alpaka b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/alpaka
new file mode 120000
index 0000000000000..9ec1e721cb8fe
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestCudaAsync/plugins/alpaka
@@ -0,0 +1 @@
+../../AlpakaTest/plugins/alpaka
\ No newline at end of file
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/README.md b/HeterogeneousCore/AlpakaTestSerialSync/README.md
new file mode 100644
index 0000000000000..64acdcc267cf6
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/README.md
@@ -0,0 +1,7 @@
+## HeterogeneousCore/AlpakaTestSerialSync
+
+This is a dummy package to emulate the expected behaviour of the build system.
+The .../alpaka/ directories are symlinked from HeterogeneousCore/AlpakaTest
+to avoid the scram error about the inclusion of private source files.
+Its content should eventually be built from HeterogeneousCore/AlpakaTest for
+the serial sync backend.
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/plugins/BuildFile.xml b/HeterogeneousCore/AlpakaTestSerialSync/plugins/BuildFile.xml
new file mode 100644
index 0000000000000..67cf1ce54e721
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/plugins/BuildFile.xml
@@ -0,0 +1,11 @@
+<library file="*.cc" name="HeterogeneousCoreAlpakaTestSerialSyncPlugins">
+  <use name="alpaka-serial"/>
+  <use name="DataFormats/XyzId"/>
+  <use name="DataFormats/XyzIdSerialSync"/>
+  <use name="FWCore/Framework"/>
+  <use name="FWCore/ParameterSet"/>
+  <use name="FWCore/Utilities"/>
+  <use name="HeterogeneousCore/AlpakaCore" source_only="1"/>
+  <use name="HeterogeneousCore/AlpakaInterface" source_only="1"/>
+  <flags EDM_PLUGIN="1"/>
+</library>
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAlgo.cc b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAlgo.cc
new file mode 100644
index 0000000000000..e923455e18aa8
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAlgo.cc
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+#include "alpaka/XyzIdAlgo.dev.cc"
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAnalyzer.cc b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAnalyzer.cc
new file mode 100644
index 0000000000000..e8ead247dbca9
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdAnalyzer.cc
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+#include "alpaka/XyzIdAlpakaAnalyzer.cc"
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdProducer.cc b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdProducer.cc
new file mode 100644
index 0000000000000..a5c73492c455c
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/plugins/XyzIdProducer.cc
@@ -0,0 +1,2 @@
+#define ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
+#include "alpaka/XyzIdAlpakaProducer.cc"
diff --git a/HeterogeneousCore/AlpakaTestSerialSync/plugins/alpaka b/HeterogeneousCore/AlpakaTestSerialSync/plugins/alpaka
new file mode 120000
index 0000000000000..9ec1e721cb8fe
--- /dev/null
+++ b/HeterogeneousCore/AlpakaTestSerialSync/plugins/alpaka
@@ -0,0 +1 @@
+../../AlpakaTest/plugins/alpaka
\ No newline at end of file