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(-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)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -68,4 +68,10 @@ template<>
|
|||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -256,4 +259,82 @@ 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++;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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 };
|
||||
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) );
|
||||
// }
|
||||
Loading…
Add table
Reference in a new issue