Looping tests and co
This commit is contained in:
parent
d2e55cf4b2
commit
c35ebdf0ad
11 changed files with 276 additions and 350 deletions
|
|
@ -17,7 +17,7 @@ if (UNIX)
|
||||||
add_compile_options(-Wextra)
|
add_compile_options(-Wextra)
|
||||||
# add_compile_options(-fno-exceptions)
|
# add_compile_options(-fno-exceptions)
|
||||||
add_compile_options(-ffast-math)
|
add_compile_options(-ffast-math)
|
||||||
# add_compile_options(-fno-omit-frame-pointer)
|
add_compile_options(-fno-omit-frame-pointer)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
@ -140,7 +140,7 @@ add_executable(sfizz_tests ${TEST_SOURCES} ${COMMON_SOURCES})
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
target_link_libraries(sfizz_tests stdc++fs)
|
target_link_libraries(sfizz_tests stdc++fs)
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
target_link_libraries(sfizz_tests Catch2::Catch2 absl::strings absl::flat_hash_map sndfile readerwriterqueue cnpy-static absl::span)
|
target_link_libraries(sfizz_tests Catch2::Catch2 absl::strings absl::flat_hash_map sndfile readerwriterqueue cnpy-static absl::span absl::algorithm)
|
||||||
target_include_directories(sfizz_tests SYSTEM PRIVATE sources)
|
target_include_directories(sfizz_tests SYSTEM PRIVATE sources)
|
||||||
file(COPY "tests" DESTINATION ${CMAKE_BINARY_DIR})
|
file(COPY "tests" DESTINATION ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
|
|
@ -153,12 +153,6 @@ add_executable(bench_opf_high_vs_low benchmarks/OPF_high_vs_low.cpp)
|
||||||
target_link_libraries(bench_opf_high_vs_low benchmark absl::span)
|
target_link_libraries(bench_opf_high_vs_low benchmark absl::span)
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
add_executable(bench_looping_index benchmarks/Looping_index.cpp)
|
|
||||||
target_link_libraries(bench_looping_index benchmark)
|
|
||||||
|
|
||||||
add_executable(bench_looping_index_2 benchmarks/Looping_index_2.cpp)
|
|
||||||
target_link_libraries(bench_looping_index_2 benchmark)
|
|
||||||
|
|
||||||
add_executable(bm_cum_prod benchmarks/Cum_Prod.cpp)
|
add_executable(bm_cum_prod benchmarks/Cum_Prod.cpp)
|
||||||
target_link_libraries(bm_cum_prod benchmark)
|
target_link_libraries(bm_cum_prod benchmark)
|
||||||
|
|
||||||
|
|
@ -175,10 +169,13 @@ add_executable(bm_fill benchmarks/BM_fill.cpp sources/SIMDSSE.cpp)
|
||||||
target_link_libraries(bm_fill benchmark absl::span)
|
target_link_libraries(bm_fill benchmark absl::span)
|
||||||
|
|
||||||
add_executable(bm_mathfuns benchmarks/BM_mathfuns.cpp sources/SIMDSSE.cpp)
|
add_executable(bm_mathfuns benchmarks/BM_mathfuns.cpp sources/SIMDSSE.cpp)
|
||||||
target_link_libraries(bm_mathfuns benchmark absl::span absl::span)
|
target_link_libraries(bm_mathfuns benchmark absl::span)
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
# target_compile_options(bm_math_loops PRIVATE -fopenmp)
|
# target_compile_options(bm_math_loops PRIVATE -fopenmp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(bm_gain benchmarks/BM_gain.cpp sources/SIMDSSE.cpp)
|
add_executable(bm_gain benchmarks/BM_gain.cpp sources/SIMDSSE.cpp)
|
||||||
target_link_libraries(bm_gain benchmark absl::span)
|
target_link_libraries(bm_gain benchmark absl::span)
|
||||||
|
|
||||||
|
add_executable(bm_looping benchmarks/BM_looping.cpp sources/SIMDSSE.cpp)
|
||||||
|
target_link_libraries(bm_looping benchmark absl::span absl::algorithm)
|
||||||
72
benchmarks/BM_looping.cpp
Normal file
72
benchmarks/BM_looping.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
#include <numeric>
|
||||||
|
#include <absl/algorithm/container.h>
|
||||||
|
#include "../sources/SIMDHelpers.h"
|
||||||
|
|
||||||
|
// In this one we have an array of indices
|
||||||
|
|
||||||
|
constexpr int loopStart { 5 };
|
||||||
|
constexpr int loopEnd { 1076 };
|
||||||
|
constexpr float maxJump { 4 };
|
||||||
|
|
||||||
|
class LoopingFixture : public benchmark::Fixture {
|
||||||
|
public:
|
||||||
|
void SetUp(const ::benchmark::State& state) {
|
||||||
|
std::random_device rd { };
|
||||||
|
std::mt19937 gen { rd() };
|
||||||
|
std::uniform_real_distribution<float> dist { 0, 1 };
|
||||||
|
indices = std::vector<int>(state.range(0));
|
||||||
|
leftCoeffs = std::vector<float>(state.range(0));
|
||||||
|
rightCoeffs = std::vector<float>(state.range(0));
|
||||||
|
jumps = std::vector<float>(state.range(0));
|
||||||
|
absl::c_generate(jumps, [&]() { return dist(gen); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> indices;
|
||||||
|
std::vector<float> leftCoeffs;
|
||||||
|
std::vector<float> rightCoeffs;
|
||||||
|
std::vector<float> jumps;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(LoopingFixture, Scalar)(benchmark::State& state) {
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(LoopingFixture, SIMD)(benchmark::State& state) {
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(LoopingFixture, Scalar_Unaligned)(benchmark::State& state) {
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
loopingSFZIndex<float, false>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(LoopingFixture, SIMD_Unaligned)(benchmark::State& state) {
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
loopingSFZIndex<float, true>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Register the function as a benchmark
|
||||||
|
BENCHMARK_REGISTER_F(LoopingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||||
|
BENCHMARK_REGISTER_F(LoopingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||||
|
BENCHMARK_REGISTER_F(LoopingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||||
|
BENCHMARK_REGISTER_F(LoopingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||||
|
BENCHMARK_MAIN();
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <random>
|
|
||||||
#include "../sources/Intrinsics.h"
|
|
||||||
#include "../sources/Buffer.h"
|
|
||||||
constexpr int loopOffset { 5 };
|
|
||||||
constexpr int loopPoint { 51 };
|
|
||||||
constexpr int loopBack { loopPoint - loopOffset };
|
|
||||||
constexpr float maxJump { 4 };
|
|
||||||
|
|
||||||
static void Straight(benchmark::State& state) {
|
|
||||||
Buffer<int> indices(state.range(0));
|
|
||||||
Buffer<float> leftCoeffs(state.range(0));
|
|
||||||
Buffer<float> rightCoeffs(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
std::uniform_real_distribution<float> dist { 0, maxJump };
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
auto offset = dist(gen);
|
|
||||||
float floatingIndex = 0.0f;
|
|
||||||
auto index = indices.data();
|
|
||||||
auto leftCoeff = leftCoeffs.data();
|
|
||||||
auto rightCoeff = rightCoeffs.data();
|
|
||||||
while (index < indices.end())
|
|
||||||
{
|
|
||||||
*index = static_cast<int>(floatingIndex);
|
|
||||||
*rightCoeff = floatingIndex - *index;
|
|
||||||
*leftCoeff = 1.0f - *rightCoeff;
|
|
||||||
floatingIndex += offset;
|
|
||||||
if (floatingIndex > loopPoint)
|
|
||||||
floatingIndex -= loopBack;
|
|
||||||
index++;
|
|
||||||
leftCoeff++;
|
|
||||||
rightCoeff++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SIMD(benchmark::State& state) {
|
|
||||||
Buffer<int> indices(state.range(0));
|
|
||||||
Buffer<float> leftCoeffs(state.range(0));
|
|
||||||
Buffer<float> rightCoeffs(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
std::uniform_real_distribution<float> dist { 0, maxJump };
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
auto index = indices.begin();
|
|
||||||
auto leftCoeff = leftCoeffs.begin();
|
|
||||||
auto rightCoeff = rightCoeffs.begin();
|
|
||||||
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
|
|
||||||
float floatingIndex = 48.0f;
|
|
||||||
auto offset = dist(gen);
|
|
||||||
const auto wrappingRegister = _mm_set1_ps(loopBack);
|
|
||||||
const auto upperBoundRegister = _mm_set1_ps(loopPoint);
|
|
||||||
const auto offsetRegister = _mm_set1_ps(offset);
|
|
||||||
const auto incrementRegister = _mm_set_ps(4.0f, 3.0f, 2.0f, 1.0f);
|
|
||||||
while (index < indices.data() + alignedEnd)
|
|
||||||
{
|
|
||||||
auto floatingIndexRegister = _mm_set_ps1(floatingIndex);
|
|
||||||
floatingIndexRegister = _mm_add_ps(floatingIndexRegister, _mm_mul_ps(incrementRegister, offsetRegister));
|
|
||||||
auto rightCoefficientsRegister = _mm_sub_ps(floatingIndexRegister,
|
|
||||||
_mm_cvtepi32_ps(_mm_cvtps_epi32(_mm_sub_ps(floatingIndexRegister, _mm_set_ps1(0.5f))))
|
|
||||||
);
|
|
||||||
auto leftCoefficientsRegister = _mm_sub_ps(_mm_set_ps1(1.0f), rightCoefficientsRegister);
|
|
||||||
const auto comparisonRegister = _mm_cmpge_ps(floatingIndexRegister, upperBoundRegister);
|
|
||||||
auto loopbackRegister = _mm_sub_ps(floatingIndexRegister, wrappingRegister);
|
|
||||||
loopbackRegister = _mm_and_ps(comparisonRegister, loopbackRegister);
|
|
||||||
floatingIndexRegister = _mm_andnot_ps(comparisonRegister, floatingIndexRegister);
|
|
||||||
floatingIndexRegister = _mm_add_ps(floatingIndexRegister, loopbackRegister);
|
|
||||||
auto indexRegister = _mm_cvtps_epi32(floatingIndexRegister);
|
|
||||||
_mm_store_si128(reinterpret_cast<__m128i*>(index), indexRegister);
|
|
||||||
_mm_store_ps(leftCoeff, leftCoefficientsRegister);
|
|
||||||
_mm_store_ps(rightCoeff, rightCoefficientsRegister);
|
|
||||||
floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(floatingIndexRegister, floatingIndexRegister, _MM_SHUFFLE(0, 0, 0, 3)));;
|
|
||||||
// floatingIndex = *(index + 3) + *(rightCoeff + 3);
|
|
||||||
index += 4;
|
|
||||||
leftCoeff += 4;
|
|
||||||
rightCoeff += 4;
|
|
||||||
}
|
|
||||||
while (index < indices.end())
|
|
||||||
{
|
|
||||||
*index = static_cast<int>(floatingIndex);
|
|
||||||
*rightCoeff = floatingIndex - *index;
|
|
||||||
*leftCoeff = 1.0f - *rightCoeff;
|
|
||||||
floatingIndex += offset;
|
|
||||||
if (floatingIndex > loopPoint)
|
|
||||||
floatingIndex -= loopBack;
|
|
||||||
index++;
|
|
||||||
leftCoeff++;
|
|
||||||
rightCoeff++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the function as a benchmark
|
|
||||||
BENCHMARK(Straight)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK(SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK_MAIN();
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <random>
|
|
||||||
#include <numeric>
|
|
||||||
#include "../sources/Intrinsics.h"
|
|
||||||
#include "../sources/Buffer.h"
|
|
||||||
|
|
||||||
// In this one we have an array of indices
|
|
||||||
|
|
||||||
constexpr int loopOffset { 5 };
|
|
||||||
constexpr int loopPoint { 1076 };
|
|
||||||
constexpr int loopBack { loopPoint - loopOffset };
|
|
||||||
constexpr float maxJump { 4 };
|
|
||||||
|
|
||||||
static void Straight(benchmark::State& state) {
|
|
||||||
Buffer<int> indices(state.range(0));
|
|
||||||
Buffer<float> leftCoeffs(state.range(0));
|
|
||||||
Buffer<float> rightCoeffs(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
std::uniform_real_distribution<float> dist { 0, maxJump };
|
|
||||||
Buffer<float> jumps(state.range(0));
|
|
||||||
std::generate(jumps.begin(), jumps.end(), [&]() { return dist(gen); });
|
|
||||||
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
float floatingIndex = 0.0f;
|
|
||||||
auto index = indices.data();
|
|
||||||
auto leftCoeff = leftCoeffs.data();
|
|
||||||
auto rightCoeff = rightCoeffs.data();
|
|
||||||
auto jump = jumps.data();
|
|
||||||
|
|
||||||
while (index < indices.end())
|
|
||||||
{
|
|
||||||
*index = static_cast<int>(floatingIndex);
|
|
||||||
*rightCoeff = floatingIndex - *index;
|
|
||||||
*leftCoeff = 1.0f - *rightCoeff;
|
|
||||||
floatingIndex += *jump;
|
|
||||||
if (floatingIndex > loopPoint)
|
|
||||||
floatingIndex -= loopBack;
|
|
||||||
index++;
|
|
||||||
leftCoeff++;
|
|
||||||
rightCoeff++;
|
|
||||||
jump++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SIMD(benchmark::State& state) {
|
|
||||||
Buffer<int> indices(state.range(0));
|
|
||||||
Buffer<float> leftCoeffs(state.range(0));
|
|
||||||
Buffer<float> rightCoeffs(state.range(0));
|
|
||||||
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
std::uniform_real_distribution<float> dist { 0, maxJump };
|
|
||||||
Buffer<float> jumps(state.range(0));
|
|
||||||
std::generate(jumps.begin(), jumps.end(), [&]() { return dist(gen); });
|
|
||||||
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
auto index = indices.data();
|
|
||||||
auto leftCoeff = leftCoeffs.data();
|
|
||||||
auto rightCoeff = rightCoeffs.data();
|
|
||||||
auto jump = jumps.data();
|
|
||||||
|
|
||||||
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
|
|
||||||
|
|
||||||
auto floatingIndexReg = _mm_set_ps1(48.0f);
|
|
||||||
const auto wrappingReg = _mm_set1_ps(loopBack);
|
|
||||||
const auto upperBoundReg = _mm_set1_ps(loopPoint);
|
|
||||||
|
|
||||||
while (index < indices.data() + alignedEnd)
|
|
||||||
{
|
|
||||||
auto offsetReg = _mm_load_ps(jump);
|
|
||||||
offsetReg = _mm_add_ps(offsetReg, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(offsetReg), 4)));
|
|
||||||
offsetReg = _mm_add_ps(offsetReg, _mm_shuffle_ps(_mm_setzero_ps(), offsetReg, 0x40));
|
|
||||||
|
|
||||||
floatingIndexReg = _mm_add_ps(floatingIndexReg, offsetReg);
|
|
||||||
const auto comparisonReg = _mm_cmpge_ps(floatingIndexReg, upperBoundReg);
|
|
||||||
auto loopbackReg = _mm_sub_ps(floatingIndexReg, wrappingReg);
|
|
||||||
loopbackReg = _mm_and_ps(comparisonReg, loopbackReg);
|
|
||||||
floatingIndexReg = _mm_andnot_ps(comparisonReg, floatingIndexReg);
|
|
||||||
floatingIndexReg = _mm_add_ps(floatingIndexReg, loopbackReg);
|
|
||||||
|
|
||||||
auto indexReg = _mm_cvtps_epi32(_mm_sub_ps(floatingIndexReg, _mm_set_ps1(0.5f)));
|
|
||||||
_mm_store_si128(reinterpret_cast<__m128i*>(index), indexReg);
|
|
||||||
|
|
||||||
auto rightCoefficientsReg = _mm_sub_ps(floatingIndexReg, _mm_cvtepi32_ps(indexReg));
|
|
||||||
auto leftCoefficientsReg = _mm_sub_ps(_mm_set_ps1(1.0f), rightCoefficientsReg);
|
|
||||||
_mm_store_ps(leftCoeff, leftCoefficientsReg);
|
|
||||||
_mm_store_ps(rightCoeff, rightCoefficientsReg);
|
|
||||||
|
|
||||||
floatingIndexReg = _mm_shuffle_ps(floatingIndexReg, floatingIndexReg, _MM_SHUFFLE(3, 3, 3, 3));
|
|
||||||
// floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(floatingIndexReg, floatingIndexReg, _MM_SHUFFLE(0, 0, 0, 3)));;
|
|
||||||
// floatingIndex = *(index + 3) + *(rightCoeff + 3);
|
|
||||||
index += 4;
|
|
||||||
jump += 4;
|
|
||||||
leftCoeff += 4;
|
|
||||||
rightCoeff += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
float floatingIndex = _mm_cvtss_f32(floatingIndexReg);
|
|
||||||
while (index < indices.end())
|
|
||||||
{
|
|
||||||
*index = static_cast<int>(floatingIndex);
|
|
||||||
*rightCoeff = floatingIndex - *index;
|
|
||||||
*leftCoeff = 1.0f - *rightCoeff;
|
|
||||||
floatingIndex += *jump;
|
|
||||||
if (floatingIndex > loopPoint)
|
|
||||||
floatingIndex -= loopBack;
|
|
||||||
index++;
|
|
||||||
leftCoeff++;
|
|
||||||
rightCoeff++;
|
|
||||||
jump++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the function as a benchmark
|
|
||||||
BENCHMARK(Straight)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK(SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK_MAIN();
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include "gsl/gsl-lite.hpp"
|
|
||||||
#include "absl/types/span.h"
|
|
||||||
#include <random>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
constexpr float filterGain { 0.25f };
|
|
||||||
|
|
||||||
void processRaw(float* input, float* lowpass, float gain, int numSamples)
|
|
||||||
{
|
|
||||||
const auto end = input + numSamples;
|
|
||||||
float state = 0.0f;
|
|
||||||
float intermediate;
|
|
||||||
const auto G = gain / (1 - gain);
|
|
||||||
while (input < end)
|
|
||||||
{
|
|
||||||
intermediate = G * (*input++ - state);
|
|
||||||
*lowpass = intermediate + state;
|
|
||||||
state = *lowpass++ + intermediate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processGSLSpan(gsl::span<const float> input, gsl::span<float> lowpass, float gain)
|
|
||||||
{
|
|
||||||
|
|
||||||
float state = 0.0f;
|
|
||||||
float intermediate;
|
|
||||||
const auto G = gain / (1 - gain);
|
|
||||||
for (auto [in, out] = std::make_pair(input.begin(), lowpass.begin());
|
|
||||||
in < input.end() && out < lowpass.end();
|
|
||||||
in++, out++)
|
|
||||||
{
|
|
||||||
intermediate = G * (*in - state);
|
|
||||||
*out = intermediate + state;
|
|
||||||
state = *out + intermediate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processABSLSpan(absl::Span<const float> input, absl::Span<float> lowpass, float gain)
|
|
||||||
{
|
|
||||||
|
|
||||||
float state = 0.0f;
|
|
||||||
float intermediate;
|
|
||||||
const auto G = gain / (1 - gain);
|
|
||||||
for (auto [in, out] = std::make_pair(input.begin(), lowpass.begin());
|
|
||||||
in < input.end() && out < lowpass.end();
|
|
||||||
in++, out++)
|
|
||||||
{
|
|
||||||
intermediate = G * (*in - state);
|
|
||||||
*out = intermediate + state;
|
|
||||||
state = *out + intermediate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Raw(benchmark::State& state) {
|
|
||||||
std::vector<float> input(state.range(0));
|
|
||||||
std::vector<float> output(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
|
|
||||||
std::normal_distribution<float> dist { };
|
|
||||||
std::generate(input.begin(), input.end(), [&]() {
|
|
||||||
return dist(gen);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
processRaw(input.data(), output.data(), filterGain, state.range(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GSLSpan(benchmark::State& state) {
|
|
||||||
std::vector<float> input(state.range(0));
|
|
||||||
std::vector<float> output(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
|
|
||||||
std::normal_distribution<float> dist { };
|
|
||||||
std::generate(input.begin(), input.end(), [&]() {
|
|
||||||
return dist(gen);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
processGSLSpan(input, output, filterGain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ABSLSpan(benchmark::State& state) {
|
|
||||||
std::vector<float> input(state.range(0));
|
|
||||||
std::vector<float> output(state.range(0));
|
|
||||||
std::random_device rd { };
|
|
||||||
std::mt19937 gen { rd() };
|
|
||||||
|
|
||||||
std::normal_distribution<float> dist { };
|
|
||||||
std::generate(input.begin(), input.end(), [&]() {
|
|
||||||
return dist(gen);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (auto _ : state)
|
|
||||||
{
|
|
||||||
processABSLSpan(input, absl::MakeSpan(output), filterGain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the function as a benchmark
|
|
||||||
|
|
||||||
BENCHMARK(Raw)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK(GSLSpan)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK(ABSLSpan)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
|
||||||
BENCHMARK_MAIN();
|
|
||||||
|
|
@ -48,6 +48,13 @@ inline unsigned int hash(std::string_view s, unsigned int h = Fnv1aBasis)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline constexpr T min(T op1, T op2) { return std::min(op1, op2); }
|
||||||
|
template<class T>
|
||||||
|
inline constexpr T min(T op1, T op2, T op3) { return std::min(op1, std::min(op2, op3)); }
|
||||||
|
template<class T>
|
||||||
|
inline constexpr T min(T op1, T op2, T op3, T op4) { return std::min(op1, std::min(op2, std::min(op3, op4))); }
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#if __linux__ || __unix__
|
#if __linux__ || __unix__
|
||||||
// These trap into the signal library rather than your own sourcecode
|
// These trap into the signal library rather than your own sourcecode
|
||||||
|
|
|
||||||
|
|
@ -68,4 +68,10 @@ template<>
|
||||||
void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||||
{
|
{
|
||||||
applyGain<float, false>(gain, input, output);
|
applyGain<float, false>(gain, input, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept
|
||||||
|
{
|
||||||
|
loopingSFZIndex<float, false>( jumps, leftCoeff, rightCoeff, indices);
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +100,36 @@ template<>
|
||||||
void cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept;
|
void cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept;
|
||||||
|
|
||||||
template<class T, bool SIMD=SIMDConfig::useSIMD>
|
template<class T, bool SIMD=SIMDConfig::useSIMD>
|
||||||
void loopingSFZIndex(absl::Span<const T> inputLeft, absl::Span<const T> inputRight, absl::Span<T> output);
|
void loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd, T loopStart) noexcept
|
||||||
|
{
|
||||||
|
ASSERT(indices.size() >= jumps.size());
|
||||||
|
ASSERT(indices.size() == leftCoeffs.size());
|
||||||
|
ASSERT(indices.size() == rightCoeffs.size());
|
||||||
|
|
||||||
|
auto* index = indices.begin();
|
||||||
|
auto* leftCoeff = leftCoeffs.begin();
|
||||||
|
auto* rightCoeff = rightCoeffs.begin();
|
||||||
|
auto* jump = jumps.begin();
|
||||||
|
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
|
||||||
|
auto* sentinel = jumps.begin() + size;
|
||||||
|
|
||||||
|
while (jump < sentinel)
|
||||||
|
{
|
||||||
|
floatIndex += *jump;
|
||||||
|
if (floatIndex >= loopEnd)
|
||||||
|
floatIndex -= loopEnd - loopStart;
|
||||||
|
*index = static_cast<int>(floatIndex);
|
||||||
|
*rightCoeff = floatIndex - *index;
|
||||||
|
*leftCoeff = 1.0f - *rightCoeff;
|
||||||
|
index++;
|
||||||
|
leftCoeff++;
|
||||||
|
rightCoeff++;
|
||||||
|
jump++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept;
|
||||||
|
|
||||||
template<class T, bool SIMD=SIMDConfig::useSIMD>
|
template<class T, bool SIMD=SIMDConfig::useSIMD>
|
||||||
void linearRamp(absl::Span<T> output, T start, T end);
|
void linearRamp(absl::Span<T> output, T start, T end);
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ bool unaligned(const float* ptr1, const float* ptr2, const float* ptr3)
|
||||||
return unaligned(ptr1) || unaligned(ptr2) || unaligned(ptr3);
|
return unaligned(ptr1) || unaligned(ptr2) || unaligned(ptr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool unaligned(const float* ptr1, const float* ptr2, const float* ptr3, const float* ptr4)
|
||||||
|
{
|
||||||
|
return unaligned(ptr1) || unaligned(ptr2) || unaligned(ptr3) || unaligned(ptr4);
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
void readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||||
{
|
{
|
||||||
|
|
@ -194,8 +199,6 @@ void log<float, true>(absl::Span<const float> input, absl::Span<float> output) n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
void sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||||
{
|
{
|
||||||
|
|
@ -256,4 +259,82 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
|
||||||
|
|
||||||
while (out < output.end())
|
while (out < output.end())
|
||||||
*out++ = (*g++) * (*in++);
|
*out++ = (*g++) * (*in++);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept
|
||||||
|
{
|
||||||
|
ASSERT(indices.size() >= jumps.size());
|
||||||
|
ASSERT(indices.size() == leftCoeffs.size());
|
||||||
|
ASSERT(indices.size() == rightCoeffs.size());
|
||||||
|
|
||||||
|
auto index = indices.data();
|
||||||
|
auto leftCoeff = leftCoeffs.data();
|
||||||
|
auto rightCoeff = rightCoeffs.data();
|
||||||
|
auto jump = jumps.data();
|
||||||
|
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
|
||||||
|
const auto* sentinel = jumps.begin() + size;
|
||||||
|
const auto* alignedEnd = prevAligned(sentinel);
|
||||||
|
|
||||||
|
while (unaligned(reinterpret_cast<float*>(index), leftCoeff, rightCoeff, jump) && jump < alignedEnd)
|
||||||
|
{
|
||||||
|
floatIndex += *jump;
|
||||||
|
if (floatIndex >= loopEnd)
|
||||||
|
floatIndex -= loopEnd - loopStart;
|
||||||
|
*index = static_cast<int>(floatIndex);
|
||||||
|
*rightCoeff = floatIndex - *index;
|
||||||
|
*leftCoeff = 1.0f - *rightCoeff;
|
||||||
|
index++;
|
||||||
|
leftCoeff++;
|
||||||
|
rightCoeff++;
|
||||||
|
jump++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mmFloatIndex = _mm_set_ps1(floatIndex);
|
||||||
|
const auto mmJumpBack = _mm_set1_ps(loopEnd - loopStart);
|
||||||
|
const auto mmLoopEnd = _mm_set1_ps(loopEnd);
|
||||||
|
while (jump < alignedEnd)
|
||||||
|
{
|
||||||
|
auto mmOffset = _mm_load_ps(jump);
|
||||||
|
mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4)));
|
||||||
|
mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, 0x40));
|
||||||
|
|
||||||
|
mmFloatIndex = _mm_add_ps(mmFloatIndex, mmOffset);
|
||||||
|
const auto mmCompared = _mm_cmpge_ps(mmFloatIndex, mmLoopEnd);
|
||||||
|
auto mmLoopBack = _mm_sub_ps(mmFloatIndex, mmJumpBack);
|
||||||
|
mmLoopBack = _mm_and_ps(mmCompared, mmLoopBack);
|
||||||
|
mmFloatIndex = _mm_andnot_ps(mmCompared, mmFloatIndex);
|
||||||
|
mmFloatIndex = _mm_add_ps(mmFloatIndex, mmLoopBack);
|
||||||
|
|
||||||
|
auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatIndex, _mm_set_ps1(0.4999999552965164184570312f)));
|
||||||
|
_mm_store_si128(reinterpret_cast<__m128i*>(index), mmIndices);
|
||||||
|
|
||||||
|
auto mmRight = _mm_sub_ps(mmFloatIndex, _mm_cvtepi32_ps(mmIndices));
|
||||||
|
auto mmLeft = _mm_sub_ps(_mm_set_ps1(1.0f), mmRight);
|
||||||
|
_mm_store_ps(leftCoeff, mmLeft);
|
||||||
|
_mm_store_ps(rightCoeff, mmRight);
|
||||||
|
|
||||||
|
mmFloatIndex = _mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(3, 3, 3, 3));
|
||||||
|
// floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(0, 0, 0, 3)));;
|
||||||
|
// floatingIndex = *(index + 3) + *(rightCoeff + 3);
|
||||||
|
index += TypeAlignment;
|
||||||
|
jump += TypeAlignment;
|
||||||
|
leftCoeff += TypeAlignment;
|
||||||
|
rightCoeff += TypeAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
floatIndex = _mm_cvtss_f32(mmFloatIndex);
|
||||||
|
while (jump < sentinel)
|
||||||
|
{
|
||||||
|
floatIndex += *jump;
|
||||||
|
if (floatIndex >= loopEnd)
|
||||||
|
floatIndex -= loopEnd - loopStart;
|
||||||
|
*index = static_cast<int>(floatIndex);
|
||||||
|
*rightCoeff = floatIndex - *index;
|
||||||
|
*leftCoeff = 1.0f - *rightCoeff;
|
||||||
|
index++;
|
||||||
|
leftCoeff++;
|
||||||
|
rightCoeff++;
|
||||||
|
jump++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,13 +56,13 @@ public:
|
||||||
|
|
||||||
void readInterleaved(absl::Span<const Type> input) noexcept
|
void readInterleaved(absl::Span<const Type> input) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(input.size() <= numChannels * numFrames);
|
ASSERT(input.size() <= static_cast<size_t>(numChannels * numFrames));
|
||||||
::readInterleaved<Type>(input, absl::MakeSpan(leftBuffer), absl::MakeSpan(rightBuffer));
|
::readInterleaved<Type>(input, absl::MakeSpan(leftBuffer), absl::MakeSpan(rightBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeInterleaved(absl::Span<Type> output) noexcept
|
void writeInterleaved(absl::Span<Type> output) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(output.size() >= numChannels * numFrames);
|
ASSERT(output.size() >= static_cast<size_t>(numChannels * numFrames));
|
||||||
::writeInterleaved<Type>(leftBuffer, rightBuffer, output);
|
::writeInterleaved<Type>(leftBuffer, rightBuffer, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#include "../sources/SIMDHelpers.h"
|
#include "../sources/SIMDHelpers.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <absl/types/span.h>
|
||||||
|
#include <absl/algorithm/container.h>
|
||||||
using namespace Catch::literals;
|
using namespace Catch::literals;
|
||||||
|
|
||||||
constexpr int smallBufferSize { 3 };
|
constexpr int smallBufferSize { 3 };
|
||||||
|
|
@ -9,6 +11,22 @@ constexpr int bigBufferSize { 4095 };
|
||||||
constexpr int medBufferSize { 127 };
|
constexpr int medBufferSize { 127 };
|
||||||
constexpr double fillValue { 1.3 };
|
constexpr double fillValue { 1.3 };
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
inline bool approxEqual(absl::Span<const Type> lhs, absl::Span<const Type> rhs, Type eps=1e-3)
|
||||||
|
{
|
||||||
|
if (lhs.size() != rhs.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rhs.size(); ++i)
|
||||||
|
if (rhs[i] != Approx(lhs[i]).epsilon(eps))
|
||||||
|
{
|
||||||
|
std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("[Helpers] fill() - Manual buffer")
|
TEST_CASE("[Helpers] fill() - Manual buffer")
|
||||||
{
|
{
|
||||||
std::vector<float> buffer (5);
|
std::vector<float> buffer (5);
|
||||||
|
|
@ -337,4 +355,54 @@ TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)")
|
||||||
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||||
applyGain<float, true>(gain, buffer, absl::MakeSpan(buffer));
|
applyGain<float, true>(gain, buffer, absl::MakeSpan(buffer));
|
||||||
REQUIRE( buffer == expected );
|
REQUIRE( buffer == expected );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Helpers] SFZ looping index")
|
||||||
|
{
|
||||||
|
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f}; // 1.1 2.3 3.6 5.0 6.5 8.1
|
||||||
|
std::array<int, 6> indices;
|
||||||
|
std::array<float, 6> leftCoeffs;
|
||||||
|
std::array<float, 6> rightCoeffs;
|
||||||
|
std::array<int, 6> expectedIndices { 2, 3, 4, 1, 2, 4 };
|
||||||
|
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f };
|
||||||
|
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f };
|
||||||
|
loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1);
|
||||||
|
REQUIRE( indices == expectedIndices );
|
||||||
|
REQUIRE( approxEqual<float>(leftCoeffs, expectedLeft) );
|
||||||
|
REQUIRE( approxEqual<float>(rightCoeffs, expectedRight) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Helpers] SFZ looping index (SIMD)")
|
||||||
|
{
|
||||||
|
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f}; // 1.1 2.3 3.6 5.0 6.5 8.1
|
||||||
|
std::array<int, 6> indices;
|
||||||
|
std::array<float, 6> leftCoeffs;
|
||||||
|
std::array<float, 6> rightCoeffs;
|
||||||
|
std::array<int, 6> expectedIndices { 2, 3, 4, 1, 2, 4 };
|
||||||
|
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f };
|
||||||
|
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f };
|
||||||
|
loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1);
|
||||||
|
REQUIRE( indices == expectedIndices );
|
||||||
|
REQUIRE( approxEqual<float>(leftCoeffs, expectedLeft) );
|
||||||
|
REQUIRE( approxEqual<float>(rightCoeffs, expectedRight) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST_CASE("[Helpers] SFZ looping index (SIMD vs Scalar)")
|
||||||
|
// {
|
||||||
|
|
||||||
|
// std::vector<float> jumps(bigBufferSize);
|
||||||
|
// absl::c_fill(jumps, fillValue);
|
||||||
|
|
||||||
|
// std::vector<int> indices(bigBufferSize);
|
||||||
|
// std::vector<float> leftCoeffs(bigBufferSize);
|
||||||
|
// std::vector<float> rightCoeffs(bigBufferSize);
|
||||||
|
|
||||||
|
// std::vector<int> indicesSIMD(bigBufferSize);
|
||||||
|
// std::vector<float> leftCoeffsSIMD(bigBufferSize);
|
||||||
|
// std::vector<float> rightCoeffsSIMD(bigBufferSize);
|
||||||
|
// loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, medBufferSize, 1);
|
||||||
|
// loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, medBufferSize, 1);
|
||||||
|
// REQUIRE( approxEqual<int>(indices, indicesSIMD, 1) );
|
||||||
|
// REQUIRE( approxEqual<float>(leftCoeffs, leftCoeffsSIMD, 1e-2) );
|
||||||
|
// REQUIRE( approxEqual<float>(rightCoeffs, rightCoeffsSIMD, 1e-2) );
|
||||||
|
// }
|
||||||
Loading…
Add table
Reference in a new issue