Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions DataFormats/SoATemplate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,12 @@ In addition to those fully parametrized templates, two further levels of paramet
mirroring the structure of the underlying structs. The blocks are built via composition,
and access to individual layouts and views is provided by name.

`SoABlocks` also have the possibility of generating methods for the `View` and `ConstView` classes using the macros `SOA_VIEW_METHODS`
and `SOA_CONST_VIEW_METHODS`. Like the macros for the element methods, this can also be called only once, and if more methods
`SoABlocks` also have the possibility of generating methods for the `View` and `ConstView` classes
using the macros `SOA_VIEW_METHODS` and `SOA_CONST_VIEW_METHODS`.
Like the macros for the element methods, this can also be called only once, and if more methods
have to be generated, they must be listed inside the same macro call. Since these methods can be called from the device,
they must be prefixed with the `SOA_HOST_DEVICE` macro and, when possible, with the `constexpr` keyword.

TODOs:
- Add introspection utilities to print the structure and layout of a `SoABlocks` instance.

[An example of utilization is shown below.](#examples)

## ROOT serialization and de-serialization
Expand Down Expand Up @@ -409,6 +407,10 @@ blocksView.scalars().id() = 42;
blocksView.scalars().type() = 1;
blocksView.scalars().energy() = 100.0f;

// SoALayouts support introspection.
// Outputs all blocks contained in the SoABlocks layout,
// including the size of each column in bytes and its associated padding.
std::cout << blocks;
```

## Current status and further improvements
Expand Down
30 changes: 30 additions & 0 deletions DataFormats/SoATemplate/interface/SoABlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
#include "SoACommon.h"
#include "SoALayout.h"

// clang-format off
#define _DECLARE_SOA_BLOCKS_STREAM_INFO_IMPL(VALUE_TYPE, NAME, LAYOUT_NAME) \
_soa_impl_os << BOOST_PP_CAT(NAME, _); \
_soa_impl_offset += LayoutFor<LAYOUT_NAME>::computeDataSize( \
cms::soa::detail::extractSegment<LayoutFor<LAYOUT_NAME>, blocksNumber>(sizes_, index)); \
index += cms::soa::detail::nBlocks<LayoutFor<LAYOUT_NAME>>();
// clang-format on

#define _DECLARE_SOA_BLOCKS_STREAM_INFO(R, DATA, NAME) \
BOOST_PP_IF(BOOST_PP_GREATER(BOOST_PP_TUPLE_ELEM(0, NAME), _VALUE_TYPE_BLOCK), \
BOOST_PP_EMPTY(), \
BOOST_PP_EXPAND(_DECLARE_SOA_BLOCKS_STREAM_INFO_IMPL NAME))

/*
* Declare accessors for the View of each block
*/
Expand Down Expand Up @@ -348,6 +361,23 @@
cms::soa::RangeChecking::Mode RANGE_CHECKING = cms::soa::RangeChecking::Default> \
struct ViewTemplateFreeParams; \
\
SOA_HOST_ONLY \
void soaToStreamInternal(std::ostream & _soa_impl_os) const { \
_soa_impl_os << #CLASS "(["; \
for (auto it = sizes_.begin(); it != sizes_.end(); ++it) { \
if (it != sizes_.begin()) {_soa_impl_os << ", ";} \
_soa_impl_os << *it; \
} \
_soa_impl_os << "] elements, in " << blocksNumber << " blocks, byte alignement= " << alignment << "): \n"; \
_soa_impl_os << " sizeof(" #CLASS "): " << sizeof(CLASS) << "\n"; \
_soa_impl_os << " The " << blocksNumber << " blocks are:\n\n"; \
byte_size_type _soa_impl_offset = 0; \
size_type index = 0; \
_ITERATE_ON_ALL(_DECLARE_SOA_BLOCKS_STREAM_INFO, ~, __VA_ARGS__) \
_soa_impl_os << "Final offset of all blocks = " << _soa_impl_offset << " computeDataSize(...): " \
<< computeDataSize(sizes_) << "\n\n"; \
} \
\
/* Helper function to compute the total number of blocks */ \
static constexpr size_type computeBlocksNumber() { \
size_type soa_blocks_count = 0; \
Expand Down
57 changes: 57 additions & 0 deletions DataFormats/SoATemplate/test/SoAStreamInternal_t.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <array>
#include <iostream>
#include <sstream>

Expand All @@ -7,6 +8,7 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch_all.hpp>

#include "DataFormats/SoATemplate/interface/SoABlocks.h"
#include "DataFormats/SoATemplate/interface/SoALayout.h"

GENERATE_SOA_LAYOUT(SoATemplate,
Expand All @@ -29,6 +31,13 @@ GENERATE_SOA_LAYOUT(SoATemplate,

using SoA = SoATemplate<64, true>;

GENERATE_SOA_LAYOUT(
SoAPositionTemplate, SOA_COLUMN(float, x), SOA_COLUMN(float, y), SOA_COLUMN(float, z), SOA_COLUMN(float, t))

GENERATE_SOA_BLOCKS(SoABlocksTemplate, SOA_BLOCK(soa, SoATemplate), SOA_BLOCK(position, SoAPositionTemplate))

using SoABlocks = SoABlocksTemplate<>;

TEST_CASE("Stream SoA") {
const std::size_t slSize = 32;
const std::size_t slBufferSize = SoA::computeDataSize(slSize);
Expand Down Expand Up @@ -60,4 +69,52 @@ TEST_CASE("Stream SoA") {
oss << soa;

REQUIRE(oss.str() == expected.str());

std::array<cms::soa::size_type, 2> sizes{{42, 66}};

const std::size_t bufferSizeBlocks = SoABlocks::computeDataSize(sizes);
// memory buffer aligned according to the layout requirements
std::unique_ptr<std::byte, decltype(std::free) *> bufferBlocks{
reinterpret_cast<std::byte *>(aligned_alloc(SoABlocks::alignment, bufferSizeBlocks)), std::free};
// SoA layout
SoABlocks blocks{bufferBlocks.get(), sizes};

std::ostringstream blocksOss;
blocksOss << blocks;
// std::cout << blocksOss.str() << std::endl;

std::ostringstream expectedBlocks;
expectedBlocks << "SoABlocksTemplate([42, 66] elements, in 2 blocks, byte alignement= 128): \n"
<< " sizeof(SoABlocksTemplate): 264\n"
<< " The 2 blocks are:\n\n"

<< "SoATemplate(42 elements, byte alignement= 128, @" << blocks.metadata().addressOf_soa() << "): \n"
<< " sizeof(SoATemplate): 200\n"
<< " Column x at offset 0 has size 336 and padding 48\n"
<< " Column y at offset 384 has size 336 and padding 48\n"
<< " Column z at offset 768 has size 336 and padding 48\n"
<< " Eigen value a at offset 1152 has dimension (3 x 1) and per column size 336 and padding 48\n"
<< " Eigen value b at offset 2304 has dimension (3 x 1) and per column size 336 and padding 48\n"
<< " Eigen value r at offset 3456 has dimension (3 x 1) and per column size 336 and padding 48\n"
<< " Column colour at offset 4608 has size 84 and padding 44\n"
<< " Column value at offset 4736 has size 168 and padding 88\n"
<< " Column py at offset 4992 has size 336 and padding 48\n"
<< " Column count at offset 5376 has size 168 and padding 88\n"
<< " Column anotherCount at offset 5632 has size 168 and padding 88\n"
<< " Scalar description at offset 5888 has size 8 and padding 120\n"
<< " Scalar someNumber at offset 6016 has size 4 and padding 124\n"
<< "Final offset = 6144 computeDataSize(...): 6144\n\n"

<< "SoAPositionTemplate(66 elements, byte alignement= 128, @" << blocks.metadata().addressOf_position()
<< "): \n"
<< " sizeof(SoAPositionTemplate): 56\n"
<< " Column x at offset 0 has size 264 and padding 120\n"
<< " Column y at offset 384 has size 264 and padding 120\n"
<< " Column z at offset 768 has size 264 and padding 120\n"
<< " Column t at offset 1152 has size 264 and padding 120\n"
<< "Final offset = 1536 computeDataSize(...): 1536\n\n"

<< "Final offset of all blocks = 7680 computeDataSize(...): 7680\n\n";

REQUIRE(blocksOss.str() == expectedBlocks.str());
}