Skip to content

Commit

Permalink
This adds a new vector wrapper class that allows for an SoA layout, i…
Browse files Browse the repository at this point in the history
…n particular, to enable us to use the Vc::Vector type efficiently. The new storage/vector keeps an array-like data structure, that holds the vector elements (say, x, y, z). Both the array type, as well as the value type of the elements are templated (storage/vector< algebraic vector dim, aos/soa value type (scalar vs e.g SIMD vector), array-like storage for the algebraic vector elements >), so that combinations like these are possible:

            3-dim AoS std::array based vector (not necessary, since this would essentially duplicate the array plugin, while begin more complicated): storage::vector<3, scalar_t, std::array>
            3-dim AoS vertical vectorized (Not there, yet, but would re-implement the current vc_vc plugin, while making the extra vc_array4 wrapper superfluous): storage::vector<3, scalar_t, Vc::SimdArray>
            3-dim SoA of size N, std::array based: storage::vector<3, std::array<scalar_t, N>, std::array>
            3-dim vetorized SoA (in this PR): storage::vector<3, Vc::Vector<scalar_t>, std::array>

        Also adds benchmarks to compare to the std::array and Eigen AoS plugins. The benchmarks contain a base class that holds the basic configuration (e.g. number of warmup samples) and a derived vector benchmark class that holds the samples of random inititialized vectors and is templated on the kind of vector operation to be benchmarked (unary and binary are possible). The benchmarks for the getter namespace also make use of the vector benchmark class. The benchmarks for single and double precision are then instantiated per plugin, including a prescription on how to produce a random vector.
  • Loading branch information
niermann999 committed Mar 30, 2023
1 parent de546e3 commit c8fa79b
Show file tree
Hide file tree
Showing 38 changed files with 2,062 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@
*.exe
*.out
*.app

# Local folders
/build
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,10 @@ if( BUILD_TESTING AND ALGEBRA_PLUGINS_BUILD_TESTING )
add_subdirectory( tests )
endif()

# Set up the benchmarks.
if( ALGEBRA_PLUGINS_BUILD_BENCHMARKS )
add_subdirectory( benchmarks )
endif()

# Set up the packaging of the project.
include( algebra-plugins-packaging )
74 changes: 74 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Algebra plugins library, part of the ACTS project (R&D line)
#
# (c) 2023 CERN for the benefit of the ACTS project
#
# Mozilla Public License Version 2.0

# Set the default C++ compiler flags.
include( algebra-plugins-compiler-options-cpp )

# Set up an INTERFACE library for the common header(s).
add_library( algebra_bench_common INTERFACE )
target_include_directories( algebra_bench_common INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/common/include" )
if( "${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC" )
target_compile_definitions( algebra_bench_common INTERFACE
-D_USE_MATH_DEFINES )
endif()
add_library( algebra::bench_common ALIAS algebra_bench_common )

# Set up all of the (available) "host" benchmarks.
add_library( algebra_bench_array INTERFACE )
target_include_directories( algebra_bench_array INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/array/include>" )
target_link_libraries(algebra_bench_array INTERFACE algebra::array_cmath
algebra::common_storage)
add_library( algebra::bench_array ALIAS algebra_bench_array )

algebra_add_benchmark( array_getter
"array/array_getter.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_array algebra::array_cmath )
algebra_add_benchmark( array_vector
"array/array_vector.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_array algebra::array_cmath )

if( ALGEBRA_PLUGINS_INCLUDE_EIGEN )
add_library( algebra_bench_eigen INTERFACE )
target_include_directories( algebra_bench_eigen INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/eigen/include>" )
target_link_libraries(algebra_bench_eigen INTERFACE algebra::eigen_eigen
algebra::common_storage)
add_library( algebra::bench_eigen ALIAS algebra_bench_eigen )

algebra_add_benchmark( eigen_getter
"eigen/eigen_getter.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_eigen algebra::eigen_eigen )
algebra_add_benchmark( eigen_vector
"eigen/eigen_vector.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_eigen algebra::eigen_eigen )
endif()

if( ALGEBRA_PLUGINS_INCLUDE_VC )
if( NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang" )
add_library( algebra_bench_vc_soa INTERFACE )
target_include_directories( algebra_bench_vc_soa INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/vc_soa/include>" )
target_link_libraries(algebra_bench_vc_soa INTERFACE
algebra::vc_soa
algebra::common_storage)
add_library( algebra::bench_vc_soa ALIAS algebra_bench_vc_soa )

algebra_add_benchmark( vc_soa_getter
"vc_soa/vc_soa_getter.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_vc_soa algebra::vc_soa )
algebra_add_benchmark( vc_soa_vector
"vc_soa/vc_soa_vector.cpp"
LINK_LIBRARIES benchmark::benchmark algebra::bench_common
algebra::bench_vc_soa algebra::vc_soa )
endif()
endif()
93 changes: 93 additions & 0 deletions benchmarks/array/array_getter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/** Algebra plugins library, part of the ACTS project
*
* (c) 2023 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/

// Project include(s)
#include "algebra/array_cmath.hpp"
#include "benchmark/array/data_generator.hpp"
#include "benchmark/common/benchmark_getter.hpp"

// Benchmark include
#include <benchmark/benchmark.h>

// System include(s)
#include <string>

using namespace algebra;

/// Run vector benchmarks
int main(int argc, char** argv) {

constexpr std::size_t n_samples{160000};
constexpr std::size_t n_warmup{static_cast<std::size_t>(0.1 * n_samples)};

//
// Prepare benchmarks
//
algebra::benchmark_base::configuration cfg{};
cfg.n_samples(n_samples).n_warmup(n_warmup);
cfg.do_sleep(false);

vector_unaryOP_bm<array::vector3, float, bench_op::phi> v_phi_s{cfg};
vector_unaryOP_bm<array::vector3, float, bench_op::theta> v_theta_s{cfg};
vector_unaryOP_bm<array::vector3, float, bench_op::perp> v_perp_s{cfg};
vector_unaryOP_bm<array::vector3, float, bench_op::norm> v_norm_s{cfg};
vector_unaryOP_bm<array::vector3, float, bench_op::eta> v_eta_s{cfg};

vector_unaryOP_bm<array::vector3, double, bench_op::phi> v_phi_d{cfg};
vector_unaryOP_bm<array::vector3, double, bench_op::theta> v_theta_d{cfg};
vector_unaryOP_bm<array::vector3, double, bench_op::perp> v_perp_d{cfg};
vector_unaryOP_bm<array::vector3, double, bench_op::norm> v_norm_d{cfg};
vector_unaryOP_bm<array::vector3, double, bench_op::eta> v_eta_d{cfg};

std::cout << "Algebra-Plugins 'getter' benchmark (std::array)\n"
<< "-----------------------------------------------\n\n"
<< cfg;

//
// Register all benchmarks
//
::benchmark::RegisterBenchmark((v_phi_s.name() + "_single").c_str(), v_phi_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_phi_d.name() + "_double").c_str(), v_phi_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_theta_s.name() + "_single").c_str(),
v_theta_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_theta_d.name() + "_double").c_str(),
v_theta_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_perp_s.name() + "_single").c_str(),
v_perp_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_perp_d.name() + "_double").c_str(),
v_perp_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_norm_s.name() + "_single").c_str(),
v_norm_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_norm_d.name() + "_double").c_str(),
v_norm_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_eta_s.name() + "_single").c_str(), v_eta_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_eta_d.name() + "_double").c_str(), v_eta_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();

::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();
}
93 changes: 93 additions & 0 deletions benchmarks/array/array_vector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/** Algebra plugins library, part of the ACTS project
*
* (c) 2023 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/

// Project include(s)
#include "algebra/array_cmath.hpp"
#include "benchmark/array/data_generator.hpp"
#include "benchmark/common/benchmark_vector.hpp"

// Benchmark include
#include <benchmark/benchmark.h>

// System include(s)
#include <string>

using namespace algebra;

/// Run vector benchmarks
int main(int argc, char** argv) {

constexpr std::size_t n_samples{160000};
constexpr std::size_t n_warmup{static_cast<std::size_t>(0.1 * n_samples)};

//
// Prepare benchmarks
//
algebra::benchmark_base::configuration cfg{};
cfg.n_samples(n_samples).n_warmup(n_warmup);
cfg.do_sleep(false);

vector_binaryOP_bm<array::vector3, float, bench_op::add> v_add_s{cfg};
vector_binaryOP_bm<array::vector3, float, bench_op::sub> v_sub_s{cfg};
vector_binaryOP_bm<array::vector3, float, bench_op::dot> v_dot_s{cfg};
vector_binaryOP_bm<array::vector3, float, bench_op::cross> v_cross_s{cfg};
vector_unaryOP_bm<array::vector3, float, bench_op::normalize> v_normalize_s{
cfg};

vector_binaryOP_bm<array::vector3, double, bench_op::add> v_add_d{cfg};
vector_binaryOP_bm<array::vector3, double, bench_op::sub> v_sub_d{cfg};
vector_binaryOP_bm<array::vector3, double, bench_op::dot> v_dot_d{cfg};
vector_binaryOP_bm<array::vector3, double, bench_op::cross> v_cross_d{cfg};
vector_unaryOP_bm<array::vector3, double, bench_op::normalize> v_normalize_d{
cfg};

std::cout << "Algebra-Plugins 'vector' benchmark (std::array)\n"
<< "-----------------------------------------------\n\n"
<< cfg;

//
// Register all benchmarks
//
::benchmark::RegisterBenchmark((v_add_s.name() + "_single").c_str(), v_add_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_add_d.name() + "_double").c_str(), v_add_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_sub_s.name() + "_single").c_str(), v_sub_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_sub_d.name() + "_double").c_str(), v_sub_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_dot_s.name() + "_single").c_str(), v_dot_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_dot_d.name() + "_double").c_str(), v_dot_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_cross_s.name() + "_single").c_str(),
v_cross_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_cross_d.name() + "_double").c_str(),
v_cross_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_normalize_s.name() + "_single").c_str(),
v_normalize_s)
->MeasureProcessCPUTime()
->ThreadPerCpu();
::benchmark::RegisterBenchmark((v_normalize_d.name() + "_double").c_str(),
v_normalize_d)
->MeasureProcessCPUTime()
->ThreadPerCpu();

::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();
}
32 changes: 32 additions & 0 deletions benchmarks/array/include/benchmark/array/data_generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/** Algebra plugins library, part of the ACTS project
*
* (c) 2023 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/

#pragma once

// System include(s)
#include <algorithm>
#include <random>
#include <vector>

namespace algebra {

/// Fill an @c std::array based vector with random values
template <typename vector_t>
inline void fill_random(std::vector<vector_t> &collection) {

// Generate a vector of the right type with random values
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<typename vector_t::value_type> dist(0.f, 1.f);

auto rand_obj = [&]() { return vector_t{dist(mt), dist(mt), dist(mt)}; };

collection.resize(collection.capacity());
std::generate(collection.begin(), collection.end(), rand_obj);
}

} // namespace algebra
Loading

0 comments on commit c8fa79b

Please sign in to comment.