Looping tests and co

This commit is contained in:
paul 2019-08-22 01:54:43 +02:00
parent d2e55cf4b2
commit c35ebdf0ad
11 changed files with 276 additions and 350 deletions

View file

@ -17,7 +17,7 @@ if (UNIX)
add_compile_options(-Wextra)
# add_compile_options(-fno-exceptions)
add_compile_options(-ffast-math)
# add_compile_options(-fno-omit-frame-pointer)
add_compile_options(-fno-omit-frame-pointer)
endif()
if (WIN32)
@ -140,7 +140,7 @@ add_executable(sfizz_tests ${TEST_SOURCES} ${COMMON_SOURCES})
if(UNIX)
target_link_libraries(sfizz_tests stdc++fs)
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)
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)
###############################
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)
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)
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)
# target_compile_options(bm_math_loops PRIVATE -fopenmp)
endif()
add_executable(bm_gain benchmarks/BM_gain.cpp sources/SIMDSSE.cpp)
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
View 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();

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -48,6 +48,13 @@ inline unsigned int hash(std::string_view s, unsigned int h = Fnv1aBasis)
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
#if __linux__ || __unix__
// These trap into the signal library rather than your own sourcecode

View file

@ -69,3 +69,9 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
{
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);
}

View file

@ -100,7 +100,36 @@ template<>
void cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept;
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>
void linearRamp(absl::Span<T> output, T start, T end);

View file

@ -37,6 +37,11 @@ bool unaligned(const float* ptr1, const float* ptr2, const float* 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<>
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<>
void sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
{
@ -257,3 +260,81 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
while (out < output.end())
*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++;
}
}

View file

@ -56,13 +56,13 @@ public:
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));
}
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);
}

View file

@ -2,6 +2,8 @@
#include "../sources/SIMDHelpers.h"
#include <array>
#include <algorithm>
#include <absl/types/span.h>
#include <absl/algorithm/container.h>
using namespace Catch::literals;
constexpr int smallBufferSize { 3 };
@ -9,6 +11,22 @@ constexpr int bigBufferSize { 4095 };
constexpr int medBufferSize { 127 };
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")
{
std::vector<float> buffer (5);
@ -338,3 +356,53 @@ TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)")
applyGain<float, true>(gain, buffer, absl::MakeSpan(buffer));
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) );
// }