Finished with SIMD for now...

This commit is contained in:
paul 2019-08-22 12:05:28 +02:00
parent 3a4c084918
commit f66a8ce1de
10 changed files with 321 additions and 238 deletions

View file

@ -147,11 +147,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(bm_cum_prod benchmarks/Cum_Prod.cpp)
target_link_libraries(bm_cum_prod benchmark)
add_executable(bm_cum_sum benchmarks/Cum_Sum.cpp)
target_link_libraries(bm_cum_sum benchmark)
add_executable(bm_write benchmarks/BM_writeInterleaved.cpp sources/SIMDSSE.cpp)
target_link_libraries(bm_write benchmark absl::span)
@ -164,12 +159,12 @@ 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)
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)
target_link_libraries(bm_looping benchmark absl::span absl::algorithm)
add_executable(bm_ramp benchmarks/BM_ramp.cpp sources/SIMDSSE.cpp)
target_link_libraries(bm_ramp benchmark absl::span absl::algorithm)

View file

@ -16,7 +16,7 @@ static void Dummy(benchmark::State& state) {
}
}
static void Fill_float(benchmark::State& state) {
static void FillScalar(benchmark::State& state) {
Buffer<float> buffer (state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
@ -26,7 +26,7 @@ static void Fill_float(benchmark::State& state) {
}
}
static void Fill_float_unaligned(benchmark::State& state) {
static void FillScalar_unaligned(benchmark::State& state) {
Buffer<float> buffer (state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
@ -36,7 +36,7 @@ static void Fill_float_unaligned(benchmark::State& state) {
}
}
static void Fill_float_SSE(benchmark::State& state) {
static void FillSIMD(benchmark::State& state) {
Buffer<float> buffer (state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
@ -46,7 +46,7 @@ static void Fill_float_SSE(benchmark::State& state) {
}
}
static void Fill_float_SSE_unaligned(benchmark::State& state) {
static void FillSIMD_unaligned(benchmark::State& state) {
Buffer<float> buffer (state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
@ -56,20 +56,9 @@ static void Fill_float_SSE_unaligned(benchmark::State& state) {
}
}
static void Fill_double(benchmark::State& state) {
Buffer<double> buffer (state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<double> dist { 1, 2 };
for (auto _ : state) {
fill<double>(absl::MakeSpan(buffer), dist(gen));
}
}
BENCHMARK(Dummy)->Range((2<<6), (2<<16));
BENCHMARK(Fill_float)->Range((2<<6), (2<<16));
BENCHMARK(Fill_float_SSE)->Range((2<<6), (2<<16));
BENCHMARK(Fill_float_unaligned)->Range((2<<6), (2<<16));
BENCHMARK(Fill_float_SSE_unaligned)->Range((2<<6), (2<<16));
BENCHMARK(Fill_double)->Range((2<<6), (2<<16));
BENCHMARK(FillScalar)->Range((2<<6), (2<<16));
BENCHMARK(FillSIMD)->Range((2<<6), (2<<16));
BENCHMARK(FillScalar_unaligned)->Range((2<<6), (2<<16));
BENCHMARK(FillSIMD_unaligned)->Range((2<<6), (2<<16));
BENCHMARK_MAIN();

123
benchmarks/BM_ramp.cpp Normal file
View file

@ -0,0 +1,123 @@
#include <benchmark/benchmark.h>
#include <random>
#include "../sources/SIMDHelpers.h"
#include "../sources/Buffer.h"
static void Dummy(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
benchmark::DoNotOptimize(value);
}
}
static void LinearScalar(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
linearRamp<float, false>(absl::MakeSpan(output), 0.0f, value);
}
}
static void LinearSIMD(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
linearRamp<float, true>(absl::MakeSpan(output), 0.0f, value);
}
}
static void LinearScalarUnaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
linearRamp<float, false>(absl::MakeSpan(output).subspan(1), 0.0f, value);
}
}
static void LinearSIMDUnaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
linearRamp<float, true>(absl::MakeSpan(output).subspan(1), 0.0f, value);
}
}
static void MulScalar(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
multiplicativeRamp<float, false>(absl::MakeSpan(output), 1.0f, value);
}
}
static void MulSIMD(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
multiplicativeRamp<float, true>(absl::MakeSpan(output), 1.0f, value);
}
}
static void MulScalarUnaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
multiplicativeRamp<float, false>(absl::MakeSpan(output).subspan(1), 1.0f, value);
}
}
static void MulSIMDUnaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
multiplicativeRamp<float, true>(absl::MakeSpan(output).subspan(1), 1.0f, value);
}
}
// Register the function as a benchmark
BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(LinearScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(LinearSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(LinearScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(LinearSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(MulScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(MulSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(MulScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK(MulSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
BENCHMARK_MAIN();

View file

@ -1,100 +0,0 @@
#include <benchmark/benchmark.h>
#include <random>
#include "../sources/Intrinsics.h"
#include "../sources/Buffer.h"
static void Dummy(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
benchmark::DoNotOptimize(value);
}
}
static void Straight(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
for (auto& out: output)
{
out = value;
value *= value;
}
}
}
static void SIMD(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
auto out = output.begin();
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
auto baseReg = _mm_set_ps1(value);
auto prodReg = _mm_set_ps(value*value*value*value, value*value*value, value*value, value);
while (out < output.data() + alignedEnd)
{
baseReg = _mm_mul_ps(baseReg, prodReg);
_mm_storeu_ps(out, baseReg);
baseReg = _mm_shuffle_ps(baseReg, baseReg, _MM_SHUFFLE(3, 3, 3, 3));
out += 4;
}
while (out < output.end())
{
*out++ = value;
value *= value;
}
}
}
static void SIMD_unaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 1, 2 };
for (auto _ : state)
{
auto value = dist(gen);
auto out = output.begin() + 1;
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
auto baseReg = _mm_set_ps1(value);
auto prodReg = _mm_set_ps(value*value*value*value, value*value*value, value*value, value);
while (out < output.data() + alignedEnd)
{
baseReg = _mm_mul_ps(baseReg, prodReg);
_mm_storeu_ps(out, baseReg);
baseReg = _mm_shuffle_ps(baseReg, baseReg, _MM_SHUFFLE(3, 3, 3, 3));
out += 4;
}
while (out < output.end())
{
*out++ = value;
value *= value;
}
}
}
// Register the function as a benchmark
BENCHMARK(Dummy)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(Straight)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(SIMD)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(SIMD_unaligned)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK_MAIN();

View file

@ -1,100 +0,0 @@
#include <benchmark/benchmark.h>
#include <random>
#include "../sources/Intrinsics.h"
#include "../sources/Buffer.h"
static void Dummy(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, 1 };
for (auto _ : state)
{
auto value = dist(gen);
benchmark::DoNotOptimize(value);
}
}
static void Straight(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, 1 };
for (auto _ : state)
{
auto value = dist(gen);
for (auto& out: output)
{
out = value;
value *= value;
}
}
}
static void SIMD(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, 1 };
for (auto _ : state)
{
auto value = dist(gen);
auto out = output.begin();
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
auto baseReg = _mm_set_ps1(value);
auto prodReg = _mm_set_ps(value+value+value+value, value+value+value, value+value, value);
while (out < output.data() + alignedEnd)
{
baseReg = _mm_add_ps(baseReg, prodReg);
_mm_storeu_ps(out, baseReg);
baseReg = _mm_shuffle_ps(baseReg, baseReg, _MM_SHUFFLE(3, 3, 3, 3));
out += 4;
}
while (out < output.end())
{
*out++ = value;
value *= value;
}
}
}
static void SIMD_unaligned(benchmark::State& state) {
Buffer<float> output(state.range(0));
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, 1 };
for (auto _ : state)
{
auto value = dist(gen);
auto out = output.begin() + 1;
const auto alignedEnd = state.range(0) - (state.range(0) & 3);
auto baseReg = _mm_set_ps1(value);
auto prodReg = _mm_set_ps(value+value+value+value, value+value+value, value+value, value);
while (out < output.data() + alignedEnd)
{
baseReg = _mm_add_ps(baseReg, prodReg);
_mm_storeu_ps(out, baseReg);
baseReg = _mm_shuffle_ps(baseReg, baseReg, _MM_SHUFFLE(3, 3, 3, 3));
out += 4;
}
while (out < output.end())
{
*out++ = value;
value *= value;
}
}
}
// Register the function as a benchmark
BENCHMARK(Dummy)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(Straight)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(SIMD)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK(SIMD_unaligned)->RangeMultiplier(2)->Range((1 << 2), (1 << 8));
BENCHMARK_MAIN();

View file

@ -25,9 +25,12 @@ namespace SIMDConfig
constexpr unsigned int defaultAlignment { 16 };
constexpr bool writeInterleaved { true };
constexpr bool readInterleaved { true };
constexpr bool fill { false };
constexpr bool fill { true };
constexpr bool gain { false };
constexpr bool mathfuns { false };
constexpr bool loopingSFZIndex { true };
constexpr bool linearRamp { false };
constexpr bool multiplicativeRamp { true };
#if USE_SIMD
constexpr bool useSIMD { true };
#else

View file

@ -64,5 +64,17 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
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);
loopingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart);
}
template<>
void linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
{
linearRamp<float, false>(output, start, step);
}
template<>
void multiplicativeRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
{
multiplicativeRamp<float, false>(output, start, step);
}

View file

@ -144,12 +144,6 @@ void loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::
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);
template<class T, bool SIMD=SIMDConfig::useSIMD>
void exponentialRamp(absl::Span<T> output, T start, T end);
template<class T>
inline void snippetGain(T gain, const T*& input, T*& output)
{
@ -202,4 +196,41 @@ template<>
void applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept;
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;
template<class T>
inline void snippetRampLinear(T*& output, T& value, T step)
{
value += step;
*output++ = value;
}
template<class T, bool SIMD=SIMDConfig::gain>
void linearRamp(absl::Span<T> output, T start, T step) noexcept
{
auto* out = output.begin();
while(out < output.end())
snippetRampLinear<T>(out, start, step);
}
template<class T>
inline void snippetRampMultiplicative(T*& output, T& value, T step)
{
value *= step;
*output++ = value;
}
template<class T, bool SIMD=SIMDConfig::gain>
void multiplicativeRamp(absl::Span<T> output, T start, T step) noexcept
{
auto* out = output.begin();
while(out < output.end())
snippetRampMultiplicative<T>(out, start, step);
}
template<>
void linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept;
template<>
void multiplicativeRamp<float, true>(absl::Span<float> output, float start, float step) noexcept;

View file

@ -303,4 +303,54 @@ void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<floa
floatIndex = _mm_cvtss_f32(mmFloatIndex);
while (jump < sentinel)
snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
}
template<>
void linearRamp<float, true>(absl::Span<float> output, float value, float step) noexcept
{
auto* out = output.begin();
const auto* lastAligned = prevAligned(output.end());
while(unaligned(out) && out < lastAligned)
snippetRampLinear<float>(out, value, step);
auto mmValue = _mm_set1_ps(value);
auto mmStep = _mm_set_ps(step+step+step+step, step+step+step, step+step, step);
while (out < lastAligned)
{
mmValue = _mm_add_ps(mmValue, mmStep);
_mm_store_ps(out, mmValue);
mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3));
out += TypeAlignment;
}
value = _mm_cvtss_f32(mmValue);
while(out < output.end())
snippetRampLinear<float>(out, value, step);
}
template<>
void multiplicativeRamp<float, true>(absl::Span<float> output, float value, float step) noexcept
{
auto* out = output.begin();
const auto* lastAligned = prevAligned(output.end());
while(unaligned(out) && out < lastAligned)
snippetRampMultiplicative<float>(out, value, step);
auto mmValue = _mm_set1_ps(value);
auto mmStep = _mm_set_ps(step*step*step*step, step*step*step, step*step, step);
while (out < lastAligned)
{
mmValue = _mm_mul_ps(mmValue, mmStep);
_mm_store_ps(out, mmValue);
mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3));
out += TypeAlignment;
}
value = _mm_cvtss_f32(mmValue);
while(out < output.end())
snippetRampMultiplicative<float>(out, value, step);
}

View file

@ -406,4 +406,84 @@ TEST_CASE("[Helpers] SFZ looping index (SIMD)")
// REQUIRE( approxEqual<int>(indices, indicesSIMD, 1) );
// REQUIRE( approxEqual<float>(leftCoeffs, leftCoeffsSIMD, 1e-2) );
// REQUIRE( approxEqual<float>(rightCoeffs, rightCoeffsSIMD, 1e-2) );
// }
// }
TEST_CASE("[Helpers] Linear Ramp")
{
const float start { 0.0f };
const float v { fillValue };
std::array<float, 6> output;
std::array<float, 6> expected {v, v + v, v + v + v, v + v + v + v, v + v + v + v + v, v + v + v + v + v + v} ;
linearRamp<float, false>(absl::MakeSpan(output), start, v);
REQUIRE( output == expected );
}
TEST_CASE("[Helpers] Linear Ramp (SIMD)")
{
const float start { 0.0f };
const float v { fillValue };
std::array<float, 6> output;
std::array<float, 6> expected {v, v + v, v + v + v, v + v + v + v, v + v + v + v + v, v + v + v + v + v + v} ;
linearRamp<float, true>(absl::MakeSpan(output), start, v);
REQUIRE( output == expected );
}
TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)")
{
const float start { 0.0f };
std::vector<float> outputScalar(bigBufferSize);
std::vector<float> outputSIMD(bigBufferSize);
linearRamp<float, false>(absl::MakeSpan(outputScalar), start, fillValue);
linearRamp<float, true>(absl::MakeSpan(outputSIMD), start, fillValue);
REQUIRE( approxEqual<float>(outputScalar, outputSIMD) );
}
TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)")
{
const float start { 0.0f };
std::vector<float> outputScalar(bigBufferSize);
std::vector<float> outputSIMD(bigBufferSize);
linearRamp<float, false>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
linearRamp<float, true>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
REQUIRE( approxEqual<float>(outputScalar, outputSIMD) );
}
TEST_CASE("[Helpers] Multiplicative Ramp")
{
const float start { 1.0f };
const float v { fillValue };
std::array<float, 6> output;
std::array<float, 6> expected {v, v * v, v * v * v, v * v * v * v, v * v * v * v * v, v * v * v * v * v * v} ;
multiplicativeRamp<float, false>(absl::MakeSpan(output), start, v);
REQUIRE( output == expected );
}
TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)")
{
const float start { 1.0f };
const float v { fillValue };
std::array<float, 6> output;
std::array<float, 6> expected {v, v * v, v * v * v, v * v * v * v, v * v * v * v * v, v * v * v * v * v * v} ;
multiplicativeRamp<float, true>(absl::MakeSpan(output), start, v);
REQUIRE( output == expected );
}
TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)")
{
const float start { 1.0f };
std::vector<float> outputScalar(bigBufferSize);
std::vector<float> outputSIMD(bigBufferSize);
multiplicativeRamp<float, false>(absl::MakeSpan(outputScalar), start, fillValue);
multiplicativeRamp<float, true>(absl::MakeSpan(outputSIMD), start, fillValue);
REQUIRE( approxEqual<float>(outputScalar, outputSIMD) );
}
TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)")
{
const float start { 1.0f };
std::vector<float> outputScalar(bigBufferSize);
std::vector<float> outputSIMD(bigBufferSize);
multiplicativeRamp<float, false>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
multiplicativeRamp<float, true>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
REQUIRE( approxEqual<float>(outputScalar, outputSIMD) );
}