Skip to content

Commit

Permalink
Test alpaka-based modules and data formats
Browse files Browse the repository at this point in the history
  • Loading branch information
fwyzard committed May 28, 2022
1 parent 328410a commit 48078c0
Show file tree
Hide file tree
Showing 62 changed files with 1,183 additions and 0 deletions.
54 changes: 54 additions & 0 deletions DataFormats/Portable/interface/PortableCollection.h
Original file line number Diff line number Diff line change
@@ -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
66 changes: 66 additions & 0 deletions DataFormats/Portable/interface/PortableHostCollection.h
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions DataFormats/Portable/interface/alpaka/PortableDeviceCollection.h
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions DataFormats/XyzId/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -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>
9 changes: 9 additions & 0 deletions DataFormats/XyzId/README.md
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 10 additions & 0 deletions DataFormats/XyzId/interface/XyzIdHostCollection.h
Original file line number Diff line number Diff line change
@@ -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
162 changes: 162 additions & 0 deletions DataFormats/XyzId/interface/XyzIdSoA.h
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions DataFormats/XyzId/interface/alpaka/XyzIdDeviceCollection.h
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions DataFormats/XyzId/src/alpaka/classes_cuda.h
Original file line number Diff line number Diff line change
@@ -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"
4 changes: 4 additions & 0 deletions DataFormats/XyzId/src/alpaka/classes_cuda_def.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<lcgdict>
<class name="alpaka_cuda_async::XyzIdDeviceCollection" persistent="false"/>
<class name="edm::Wrapper<alpaka_cuda_async::XyzIdDeviceCollection>" persistent="false"/>
</lcgdict>
5 changes: 5 additions & 0 deletions DataFormats/XyzId/src/alpaka/classes_serial.h
Original file line number Diff line number Diff line change
@@ -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"
4 changes: 4 additions & 0 deletions DataFormats/XyzId/src/alpaka/classes_serial_def.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<lcgdict>
<class name="alpaka_serial_sync::XyzIdDeviceCollection"/>
<class name="edm::Wrapper<alpaka_serial_sync::XyzIdDeviceCollection>" splitLevel="0"/>
</lcgdict>
1 change: 1 addition & 0 deletions DataFormats/XyzId/src/classes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "DataFormats/XyzId/interface/XyzIdSoA.h"
3 changes: 3 additions & 0 deletions DataFormats/XyzId/src/classes_def.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<lcgdict>
<class name="XyzIdSoA"/>
</lcgdict>
9 changes: 9 additions & 0 deletions DataFormats/XyzIdCudaAsync/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -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>
1 change: 1 addition & 0 deletions DataFormats/XyzIdCudaAsync/src/classes_cuda.h
1 change: 1 addition & 0 deletions DataFormats/XyzIdCudaAsync/src/classes_cuda_def.xml
Loading

0 comments on commit 48078c0

Please sign in to comment.