Skip to content
8 changes: 0 additions & 8 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
- { compiler: 'gcc', version: '13', flags: 'enable_xtl_complex' }
- { compiler: 'gcc', version: '14', flags: 'avx' }
- { compiler: 'gcc', version: '13', flags: 'avx512' }
- { compiler: 'gcc', version: '12', flags: 'i386' }
- { compiler: 'gcc', version: '13', flags: 'avx512pf' }
- { compiler: 'gcc', version: '13', flags: 'avx512vbmi' }
- { compiler: 'gcc', version: '14', flags: 'avx512vbmi2' }
Expand All @@ -34,10 +33,6 @@ jobs:
GCC_VERSION=${{ matrix.sys.version }}
sudo apt-get update
sudo apt-get --no-install-suggests --no-install-recommends install g++-$GCC_VERSION
sudo dpkg --add-architecture i386
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get --no-install-suggests --no-install-recommends install gcc-$GCC_VERSION-multilib g++-$GCC_VERSION-multilib linux-libc-dev:i386
CC=gcc-$GCC_VERSION
echo "CC=$CC" >> $GITHUB_ENV
CXX=g++-$GCC_VERSION
Expand Down Expand Up @@ -95,9 +90,6 @@ jobs:
if [[ '${{ matrix.sys.flags }}' == 'avx512vnni' ]]; then
CMAKE_EXTRA_ARGS="$CMAKE_EXTRA_ARGS -DTARGET_ARCH=knm"
fi
if [[ '${{ matrix.sys.flags }}' == 'i386' ]]; then
CXX_FLAGS="$CXX_FLAGS -m32"
fi
if [[ '${{ matrix.sys.flags }}' == 'force_no_instr_set' ]]; then
:
else
Expand Down
11 changes: 7 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ endif()
# Build
# =====

set(XSIMDALGO_HEADERS
${XSIMDALGO_INCLUDE_DIR}/xsimd_algorithm/algorithms.hpp
)

add_library(xsimd-algorithm INTERFACE)

target_include_directories(xsimd-algorithm INTERFACE
Expand All @@ -37,12 +33,19 @@ target_compile_features(xsimd-algorithm INTERFACE cxx_std_20)
target_link_libraries(xsimd-algorithm INTERFACE xsimd)

OPTION(BUILD_TESTS "xsimd-algorithm test suite" OFF)
OPTION(BUILD_BENCHMARK "xsimd-algorithm benchmark suite" OFF)

add_subdirectory(test-utils)

if(BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()

if(BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif()

# Installation
# ============

Expand Down
26 changes: 26 additions & 0 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
############################################################################
# Copyright (c) xsimd-algorithm contributors #
# #
# Distributed under the terms of the BSD 3-Clause License. #
# #
# The full license is in the file LICENSE, distributed with this software. #
############################################################################

cmake_minimum_required(VERSION 3.8)

project(xsimd-algorithm-benchmark)

if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
find_package(xsimd-algorithm REQUIRED CONFIG)
endif ()

find_package(benchmark REQUIRED)

set(XSIMD_ALGORITHM_BENCHMARKS
main.cpp
bench_math.cpp
)

add_executable(benchmark_xsimd_algorithm ${XSIMD_ALGORITHM_BENCHMARKS})
target_link_libraries(benchmark_xsimd_algorithm
PRIVATE xsimd-algorithm xsimd::test-utils benchmark::benchmark)
114 changes: 114 additions & 0 deletions benchmark/bench_math.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/****************************************************************************
* Copyright (c) xsimd-algorithm contributors *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#include <cstddef>
#include <format>
#include <string_view>

#include <benchmark/benchmark.h>

#include "bench_utils.hpp"
#include "xsimd_test_utils/map_unary_data.hpp"
#include "xsimd_test_utils/utils.hpp"

using xsimd::builder::alignment;

namespace
{
template <typename Op, typename Alloc, typename Apply>
void bench_unary(benchmark::State& state, Apply apply)
{
using input_t = typename Op::input_t;

auto const size = static_cast<std::size_t>(state.range(0));
auto [input, output] = Op::template make_input_output<Alloc>(size);

for (auto _ : state)
{
apply(xsimd::test::as_span(input), xsimd::test::as_span(output));
benchmark::DoNotOptimize(output.data());
benchmark::ClobberMemory();
}

state.SetItemsProcessed(static_cast<std::int64_t>(state.iterations() * size));
state.SetBytesProcessed(
static_cast<std::int64_t>(state.iterations() * size * 2 * sizeof(input_t)));
}

template <typename Op, typename Alloc, typename Arch, alignment aligned = alignment {}>
void bench_map_unary(benchmark::State& state)
{
bench_unary<Op, Alloc>(
state,
[](auto in, auto out)
{ Op::template range_apply_map_unary<aligned, Arch>(in, out); });
}

template <typename Op, typename Alloc, typename Arch>
void bench_transform(benchmark::State& state)
{
bench_unary<Op, Alloc>(
state,
[](auto in, auto out)
{ Op::template range_apply_transform<Arch>(in, out); });
}

template <typename Op, typename Alloc>
void bench_scalar(benchmark::State& state)
{
bench_unary<Op, Alloc>(state, [](auto in, auto out)
{ Op::range_apply_scalar(in, out); });
}

template <typename Op, typename Arch, typename Bench>
void register_bench(std::string_view variant, Bench bench_fn)
{
using input_t = typename Op::input_t;

auto* bench = benchmark::RegisterBenchmark(
std::format("{}/{}/{}/{}", Arch::name(), Op::name, xsimd::bench::type_name<input_t>(), variant),
bench_fn);
for (auto const size : xsimd::bench::bench_sizes<input_t>())
{
bench->Arg(size);
}
}

template <typename Op>
void register_benches()
{
using input_t = typename Op::input_t;
using arch = xsimd::default_arch;
using aligned_alloc = typename xsimd::test::aligned_vector<input_t, arch>::allocator_type;
using unaligned_alloc = typename xsimd::test::unaligned_vector<input_t, arch>::allocator_type;

// To avoid an explosion of benchmarks, we probagly want to only benchmark aligned for
// math ops, and benchmark map_unary/transform setups (alignment...) separately on a
// few ops.
register_bench<Op, arch>("scalar/aligned", bench_scalar<Op, aligned_alloc>);
register_bench<Op, arch>("simd-map/aligned", bench_map_unary<Op, aligned_alloc, arch, alignment { .start_aligned = true }>);
register_bench<Op, arch>("simd-map/unaligned", bench_map_unary<Op, unaligned_alloc, arch>);
if constexpr (std::is_same_v<typename Op::input_t, typename Op::output_t>)
{
register_bench<Op, arch>("simd-transform/aligned", bench_transform<Op, aligned_alloc, arch>);
register_bench<Op, arch>("simd-transform/unaligned", bench_transform<Op, unaligned_alloc, arch>);
}
}

bool const registered = []
{
register_benches<xsimd::test::sqrt_op<float>>();
register_benches<xsimd::test::sqrt_op<double>>();
register_benches<xsimd::test::abs_op<float>>();
register_benches<xsimd::test::abs_op<double>>();
register_benches<xsimd::test::exp_op<float>>();
register_benches<xsimd::test::exp_op<double>>();
register_benches<xsimd::test::widen_op<std::int32_t>>();
return true;
}();
}
91 changes: 91 additions & 0 deletions benchmark/bench_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/****************************************************************************
* Copyright (c) xsimd-algorithm contributors *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XSIMD_ALGORITHM_BENCHMARK_BENCH_UTILS_HPP
#define XSIMD_ALGORITHM_BENCHMARK_BENCH_UTILS_HPP

#include <cstdint>
#include <type_traits>
#include <vector>

#include <xsimd/xsimd.hpp>

namespace xsimd::bench
{
template <typename T>
std::vector<std::int64_t> bench_sizes()
{
constexpr auto batch_size = static_cast<std::int64_t>(xsimd::batch<T>::size);

auto sizes = std::vector<std::int64_t> {};
for (std::int64_t size : { 64, 1024, 65536, 1 << 21 })
{
auto const whole = size - (size % batch_size);
sizes.push_back(whole);
sizes.push_back(whole + batch_size / 2 + 1);
}
return sizes;
}

template <typename T>
constexpr auto type_name()
{
// Avoid failing compiler check such as std::is_same<std::uint64_t, long long> due
// to it not being an alias.
constexpr bool is_int = std::is_integral_v<T> && !std::is_same_v<T, bool>;
constexpr bool is_sint = is_int && std::is_signed_v<T>;
constexpr bool is_uint = is_int && std::is_unsigned_v<T>;

if constexpr (std::is_same_v<T, bool>)
{
return "bool";
}
else if constexpr (is_sint && sizeof(T) == 1)
{
return "i8";
}
else if constexpr (is_uint && sizeof(T) == 1)
{
return "u8";
}
else if constexpr (is_sint && sizeof(T) == 2)
{
return "i16";
}
else if constexpr (is_uint && sizeof(T) == 2)
{
return "u16";
}
else if constexpr (is_sint && sizeof(T) == 4)
{
return "i32";
}
else if constexpr (is_uint && sizeof(T) == 4)
{
return "u32";
}
else if constexpr (is_sint && sizeof(T) == 8)
{
return "i64";
}
else if constexpr (is_uint && sizeof(T) == 8)
{
return "u64";
}
else if constexpr (std::is_same_v<T, float>)
{
return "f32";
}
else if constexpr (std::is_same_v<T, double>)
{
return "f64";
}
}
}

#endif
11 changes: 11 additions & 0 deletions benchmark/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/****************************************************************************
* Copyright (c) xsimd-algorithm contributors *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#include <benchmark/benchmark.h>

BENCHMARK_MAIN();
3 changes: 2 additions & 1 deletion environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ dependencies:
- cmake
- xsimd=14.3.0
- doctest
- ninja
- benchmark
- ninja
Loading
Loading