GenericSoATemplate

SoAPCATemplate

SoAPositionTemplate

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
#include <Eigen/Core>
#include <Eigen/Dense>

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

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

GENERATE_SOA_LAYOUT(SoAPositionTemplate,
                    SOA_COLUMN(float, x),
                    SOA_COLUMN(float, y),
                    SOA_COLUMN(float, z),
                    SOA_SCALAR(int, detectorType))

using SoAPosition = SoAPositionTemplate<>;
using SoAPositionView = SoAPosition::View;
using SoAPositionConstView = SoAPosition::ConstView;

GENERATE_SOA_LAYOUT(SoAPCATemplate,
                    SOA_COLUMN(float, eigenvalues),
                    SOA_COLUMN(float, eigenvector_1),
                    SOA_COLUMN(float, eigenvector_2),
                    SOA_COLUMN(float, eigenvector_3),
                    SOA_EIGEN_COLUMN(Eigen::Vector3d, candidateDirection))

using SoAPCA = SoAPCATemplate<>;
using SoAPCAView = SoAPCA::View;
using SoAPCAConstView = SoAPCA::ConstView;

GENERATE_SOA_LAYOUT(GenericSoATemplate,
                    SOA_COLUMN(float, xPos),
                    SOA_COLUMN(float, yPos),
                    SOA_COLUMN(float, zPos),
                    SOA_EIGEN_COLUMN(Eigen::Vector3d, candidateDirection))

using GenericSoA = GenericSoATemplate<cms::soa::CacheLineSize::IntelCPU>;
using GenericSoAView = GenericSoA::View;
using GenericSoAConstView = GenericSoA::ConstView;

TEST_CASE("SoAGenericView") {
  // common number of elements for the SoAs
  const std::size_t elems = 17;

  // buffer sizes
  const std::size_t positionBufferSize = SoAPosition::computeDataSize(elems);
  const std::size_t pcaBufferSize = SoAPCA::computeDataSize(elems);

  // memory buffer for the SoA of positions
  std::unique_ptr<std::byte, decltype(std::free) *> bufferPos{
      reinterpret_cast<std::byte *>(aligned_alloc(SoAPosition::alignment, positionBufferSize)), std::free};
  // memory buffer for the SoA of the PCA
  std::unique_ptr<std::byte, decltype(std::free) *> bufferPCA{
      reinterpret_cast<std::byte *>(aligned_alloc(SoAPCA::alignment, pcaBufferSize)), std::free};

  // SoA Layouts
  SoAPosition position{bufferPos.get(), elems};
  SoAPCA pca{bufferPCA.get(), elems};

  // SoA Views
  SoAPositionView positionView{position};
  SoAPositionConstView positionConstView{position};
  SoAPCAView pcaView{pca};
  SoAPCAConstView pcaConstView{pca};

  // fill up
  for (size_t i = 0; i < elems; i++) {
    positionView[i] = {i * 1.0f, i * 2.0f, i * 3.0f};
  }
  positionView.detectorType() = 1;

  float time = 0.01;
  for (size_t i = 0; i < elems; i++) {
    pcaView[i].eigenvector_1() = positionView[i].x() / time;
    pcaView[i].eigenvector_2() = positionView[i].y() / time;
    pcaView[i].eigenvector_3() = positionView[i].z() / time;
    pcaView[i].candidateDirection()(0) = positionView[i].x() / time;
    pcaView[i].candidateDirection()(1) = positionView[i].y() / time;
    pcaView[i].candidateDirection()(2) = positionView[i].z() / time;
  }

  SECTION("Generic View") {
    // addresses and size of the SoA columns
    const auto posRecs = positionView.records();
    const auto pcaRecs = pcaView.records();

    // building the View with runtime check for the size
    GenericSoAView genericView(posRecs.x(), posRecs.y(), posRecs.z(), pcaRecs.candidateDirection());

    // Check for equality of memory addresses
    REQUIRE(genericView.metadata().addressOf_xPos() == positionView.metadata().addressOf_x());
    REQUIRE(genericView.metadata().addressOf_yPos() == positionView.metadata().addressOf_y());
    REQUIRE(genericView.metadata().addressOf_zPos() == positionView.metadata().addressOf_z());
    REQUIRE(genericView.metadata().addressOf_candidateDirection() == pcaView.metadata().addressOf_candidateDirection());

    // Check for reference to original SoA
    genericView[3].xPos() = 0.;
    REQUIRE(genericView[3].xPos() == positionConstView[3].x());
  }

  SECTION("Generic ConstView") {
    // addresses and size of the SoA columns
    const auto posRecs = positionConstView.records();
    const auto pcaRecs = pcaConstView.records();

    // building the ConstView with runtime check for the size
    GenericSoAConstView genericConstView(posRecs.x(), posRecs.y(), posRecs.z(), pcaRecs.candidateDirection());

    // Check for equality of memory addresses
    REQUIRE(genericConstView.metadata().addressOf_xPos() == positionConstView.metadata().addressOf_x());
    REQUIRE(genericConstView.metadata().addressOf_yPos() == positionConstView.metadata().addressOf_y());
    REQUIRE(genericConstView.metadata().addressOf_zPos() == positionConstView.metadata().addressOf_z());
    REQUIRE(genericConstView.metadata().addressOf_candidateDirection() ==
            pcaConstView.metadata().addressOf_candidateDirection());
  }

  SECTION("Generic ConstView from Views") {
    // addresses and size of the SoA columns
    const auto posRecs = positionView.records();
    const auto pcaRecs = pcaView.records();

    // building the ConstView with runtime check for the size
    GenericSoAConstView genericConstView(posRecs.x(), posRecs.y(), posRecs.z(), pcaRecs.candidateDirection());

    // Check for reference to the Generic SoA - it is possible to modify the ConstView by reference modifying the Views
    positionView[3].x() = 0.;
    REQUIRE(genericConstView[3].xPos() == positionView[3].x());
  }

  SECTION("Deep copy the Generic View") {
    // building the Layout
    const std::size_t genericBufferSize = GenericSoA::computeDataSize(elems);
    std::unique_ptr<std::byte, decltype(std::free) *> bufferGeneric{
        reinterpret_cast<std::byte *>(aligned_alloc(GenericSoA::alignment, genericBufferSize)), std::free};
    GenericSoA genericSoA(bufferGeneric.get(), elems);

    // building the Generic View
    const auto posRecs = positionView.records();
    const auto pcaRecs = pcaView.records();
    GenericSoAView genericView(posRecs.x(), posRecs.y(), posRecs.z(), pcaRecs.candidateDirection());

    // aggregate the columns from the view with runtime check for the size
    genericSoA.deepCopy(genericView);

    // building the View of the new SoA
    GenericSoAView genericSoAView{genericSoA};

    // Check for inequality of memory addresses
    REQUIRE(genericSoAView.metadata().addressOf_xPos() != positionConstView.metadata().addressOf_x());
    REQUIRE(genericSoAView.metadata().addressOf_yPos() != positionConstView.metadata().addressOf_y());
    REQUIRE(genericSoAView.metadata().addressOf_zPos() != positionConstView.metadata().addressOf_z());
    REQUIRE(genericSoAView.metadata().addressOf_candidateDirection() !=
            pcaConstView.metadata().addressOf_candidateDirection());

    // Check for column alignments
    REQUIRE(0 ==
            reinterpret_cast<uintptr_t>(genericSoAView.metadata().addressOf_xPos()) % decltype(genericSoA)::alignment);
    REQUIRE(0 ==
            reinterpret_cast<uintptr_t>(genericSoAView.metadata().addressOf_yPos()) % decltype(genericSoA)::alignment);
    REQUIRE(0 ==
            reinterpret_cast<uintptr_t>(genericSoAView.metadata().addressOf_zPos()) % decltype(genericSoA)::alignment);
    REQUIRE(0 == reinterpret_cast<uintptr_t>(genericSoAView.metadata().addressOf_candidateDirection()) %
                     decltype(genericSoA)::alignment);

    // Check for contiguity of columns
    REQUIRE(reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_xPos()) +
                cms::soa::alignSize(elems * sizeof(float), GenericSoA::alignment) ==
            reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_yPos()));
    REQUIRE(reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_yPos()) +
                cms::soa::alignSize(elems * sizeof(float), GenericSoA::alignment) ==
            reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_zPos()));
    REQUIRE(reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_zPos()) +
                cms::soa::alignSize(elems * sizeof(float), GenericSoA::alignment) ==
            reinterpret_cast<std::byte *>(genericSoAView.metadata().addressOf_candidateDirection()));

    // Ckeck the correctness of the copy
    for (size_t i = 0; i < elems; i++) {
      REQUIRE(genericSoAView[i].xPos() == positionConstView[i].x());
      REQUIRE(genericSoAView[i].yPos() == positionConstView[i].y());
      REQUIRE(genericSoAView[i].zPos() == positionConstView[i].z());
      REQUIRE(genericSoAView[i].candidateDirection()(0) == pcaConstView[i].candidateDirection()(0));
      REQUIRE(genericSoAView[i].candidateDirection()(1) == pcaConstView[i].candidateDirection()(1));
      REQUIRE(genericSoAView[i].candidateDirection()(2) == pcaConstView[i].candidateDirection()(2));
    }

    // Check for the independency of the aggregated SoA
    genericSoAView[3].xPos() = 0.;
    REQUIRE(genericSoAView[3].xPos() != positionView[3].x());
  }
}