Added a SIMD helper for the "floating index to sample index + interpolation coefficients"

This commit is contained in:
paulfd 2019-09-15 20:17:52 +02:00
parent 9324d137bc
commit ced4178643
6 changed files with 200 additions and 8 deletions

View file

@ -0,0 +1,93 @@
// Copyright (c) 2019, Paul Ferrand
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <benchmark/benchmark.h>
#include <vector>
#include <random>
#include <numeric>
#include <absl/algorithm/container.h>
#include "../sfizz/SIMDHelpers.h"
// In this one we have an array of jumps
constexpr float maxJump { 4 };
class InterpolationCast : 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, maxJump };
jumps = std::vector<int>(state.range(0));
leftCoeffs = std::vector<float>(state.range(0));
rightCoeffs = std::vector<float>(state.range(0));
floatJumps = std::vector<float>(state.range(0));
absl::c_generate(floatJumps, [&]() { return dist(gen); });
}
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
}
std::vector<int> jumps;
std::vector<float> leftCoeffs;
std::vector<float> rightCoeffs;
std::vector<float> floatJumps;
};
BENCHMARK_DEFINE_F(InterpolationCast, Scalar)(benchmark::State& state) {
for (auto _ : state)
{
sfzInterpolationCast<float, false>(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs));
}
}
BENCHMARK_DEFINE_F(InterpolationCast, SIMD)(benchmark::State& state) {
for (auto _ : state)
{
sfzInterpolationCast<float, true>(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs));
}
}
BENCHMARK_DEFINE_F(InterpolationCast, Scalar_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfzInterpolationCast<float, false>(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1));
}
}
BENCHMARK_DEFINE_F(InterpolationCast, SIMD_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfzInterpolationCast<float, true>(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1));
}
}
// Register the function as a benchmark
BENCHMARK_REGISTER_F(InterpolationCast, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(InterpolationCast, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(InterpolationCast, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(InterpolationCast, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_MAIN();

View file

@ -78,6 +78,9 @@ target_link_libraries(bm_meanSquared benchmark absl::span absl::algorithm)
add_executable(bm_cumsum BM_cumsum.cpp ${SFIZZ_SIMD_SOURCES})
target_link_libraries(bm_cumsum benchmark absl::span absl::algorithm)
add_executable(bm_interpolationCast BM_interpolationCast.cpp ${SFIZZ_SIMD_SOURCES})
target_link_libraries(bm_interpolationCast benchmark absl::span absl::algorithm)
add_custom_target(sfizz_benchmarks)
add_dependencies(sfizz_benchmarks
bm_opf_high_vs_low
@ -87,6 +90,7 @@ add_dependencies(sfizz_benchmarks
bm_meanSquared
bm_fill
bm_cumsum
bm_interpolationCast
bm_mathfuns
bm_gain
bm_looping

View file

@ -62,6 +62,7 @@ namespace SIMDConfig {
constexpr bool copy { false };
constexpr bool pan { true };
constexpr bool cumsum { true };
constexpr bool sfzInterpolationCast { true };
constexpr bool mean { false };
constexpr bool meanSquared { false };
}

View file

@ -155,3 +155,9 @@ void cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output
{
cumsum<float, false>(input, output);
}
template<>
void sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs) noexcept
{
sfzInterpolationCast<float, false>(floatJumps, jumps, leftCoeffs, rightCoeffs);
}

View file

@ -494,3 +494,35 @@ void cumsum(absl::Span<const float> input, absl::Span<float> output) noexcept
template <>
void cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept;
template<class T>
void snippetSFZInterpolationCast(const T*& floatJump, int*& jump, T*& leftCoeff, T*& rightCoeff)
{
*jump = static_cast<int>(*floatJump);
*rightCoeff = *floatJump - static_cast<float>(*jump);
*leftCoeff = static_cast<T>(1.0) - *rightCoeff;
leftCoeff++;
jump++;
rightCoeff++;
floatJump++;
}
template<class T, bool SIMD = SIMDConfig::sfzInterpolationCast>
void sfzInterpolationCast(absl::Span<const T> floatJumps, absl::Span<int> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs) noexcept
{
ASSERT(jumps.size() >= floatJumps.size());
ASSERT(jumps.size() == leftCoeffs.size());
ASSERT(jumps.size() == rightCoeffs.size());
auto floatJump = floatJumps.data();
auto jump = jumps.data();
auto leftCoeff = leftCoeffs.data();
auto rightCoeff = rightCoeffs.data();
const auto sentinel = floatJump + min(floatJumps.size(), jumps.size(), leftCoeffs.size(), rightCoeffs.size());
while (floatJump < sentinel)
snippetSFZInterpolationCast(floatJump, jump, leftCoeff, rightCoeff);
}
template<>
void sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs) noexcept;

View file

@ -522,6 +522,26 @@ void add<float, true>(absl::Span<const float> input, absl::Span<float> output) n
snippetAdd<float>(in, out);
}
template <>
void add<float, true>(float value, absl::Span<float> output) noexcept
{
auto* out = output.begin();
auto* sentinel = output.end();
const auto* lastAligned = prevAligned(sentinel);
while (unaligned(out) && out < lastAligned)
snippetAdd<float>(value, out);
auto mmValue = _mm_set_ps1(value);
while (out < lastAligned) {
_mm_store_ps(out, _mm_add_ps(mmValue, _mm_load_ps(out)));
out += TypeAlignment;
}
while (out < sentinel)
snippetAdd<float>(value, out);
}
template <>
void subtract<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
{
@ -582,8 +602,8 @@ void pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> lef
const auto mmOne = _mm_set_ps1(1.0f);
const auto mmPiFour = _mm_set_ps1(piFour<float>);
__m128 mmCos;
__m128 mmSin;
__m128 mmCos;
__m128 mmSin;
while (pan < lastAligned) {
auto mmPan = _mm_load_ps(pan);
mmPan = _mm_add_ps(mmOne, mmPan);
@ -615,9 +635,9 @@ float mean<float, true>(absl::Span<const float> vector) noexcept
while (unaligned(value) && value < lastAligned)
result += *value++;
auto mmSums = _mm_setzero_ps();
while(value < lastAligned) {
while (value < lastAligned) {
mmSums = _mm_add_ps(mmSums, _mm_load_ps(value));
value += TypeAlignment;
}
@ -625,7 +645,7 @@ float mean<float, true>(absl::Span<const float> vector) noexcept
std::array<float, 4> sseResult;
_mm_store_ps(sseResult.data(), mmSums);
for (auto sseValue: sseResult)
for (auto sseValue : sseResult)
result += sseValue;
while (value < sentinel)
@ -649,9 +669,9 @@ float meanSquared<float, true>(absl::Span<const float> vector) noexcept
result += (*value) * (*value);
value++;
}
auto mmSums = _mm_setzero_ps();
while(value < lastAligned) {
while (value < lastAligned) {
const auto mmValues = _mm_load_ps(value);
mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues));
value += TypeAlignment;
@ -660,7 +680,7 @@ float meanSquared<float, true>(absl::Span<const float> vector) noexcept
std::array<float, 4> sseResult;
_mm_store_ps(sseResult.data(), mmSums);
for (auto sseValue: sseResult)
for (auto sseValue : sseResult)
result += sseValue;
while (value < sentinel) {
@ -702,3 +722,39 @@ void cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output
while (in < sentinel)
snippetCumsum(in, out);
}
template <>
void sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs) noexcept
{
ASSERT(jumps.size() >= floatJumps.size());
ASSERT(jumps.size() == leftCoeffs.size());
ASSERT(jumps.size() == rightCoeffs.size());
auto floatJump = floatJumps.data();
auto jump = jumps.data();
auto leftCoeff = leftCoeffs.data();
auto rightCoeff = rightCoeffs.data();
const auto sentinel = floatJump + min(floatJumps.size(), jumps.size(), leftCoeffs.size(), rightCoeffs.size());
const auto lastAligned = prevAligned(sentinel);
while (unaligned(floatJump, reinterpret_cast<float*>(jump), leftCoeff, rightCoeff) && floatJump < lastAligned)
snippetSFZInterpolationCast(floatJump, jump, leftCoeff, rightCoeff);
while (floatJump < lastAligned) {
auto mmFloatJumps = _mm_load_ps(floatJump);
auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatJumps, _mm_set_ps1(0.4999999552965164184570312f)));
_mm_store_si128(reinterpret_cast<__m128i*>(jump), mmIndices);
auto mmRight = _mm_sub_ps(mmFloatJumps, _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);
floatJump += TypeAlignment;
jump += TypeAlignment;
leftCoeff += TypeAlignment;
rightCoeff += TypeAlignment;
}
while(floatJump < sentinel)
snippetSFZInterpolationCast(floatJump, jump, leftCoeff, rightCoeff);
}