From 59f284a82bcdf6c0f71a957bad159c053b917060 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 10:54:32 +0200 Subject: [PATCH] Move mean and meanSquared to the new format --- benchmarks/BM_mean.cpp | 12 +++-- benchmarks/BM_meanSquared.cpp | 12 +++-- src/sfizz/SIMDHelpers.cpp | 83 +++++++++++++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 49 +++++++++++++-------- src/sfizz/SIMDSSE.cpp | 69 ----------------------------- tests/SIMDHelpersT.cpp | 24 +++++++--- 6 files changed, 148 insertions(+), 101 deletions(-) diff --git a/benchmarks/BM_mean.cpp b/benchmarks/BM_mean.cpp index 5ea0cc93..88d50624 100644 --- a/benchmarks/BM_mean.cpp +++ b/benchmarks/BM_mean.cpp @@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } } @@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } } @@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } @@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } diff --git a/benchmarks/BM_meanSquared.cpp b/benchmarks/BM_meanSquared.cpp index 41468cc0..ec8c1f5c 100644 --- a/benchmarks/BM_meanSquared.cpp +++ b/benchmarks/BM_meanSquared.cpp @@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } } @@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } } @@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } @@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index d1c61bdc..24c9a882 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -471,4 +471,87 @@ void copy(const float* input, float* output, unsigned size) noexcept std::copy(input, sentinel, output); } +template <> +float mean(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + + if (getSIMDOpStatus(SIMDOps::mean)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned) + result += *vector++; + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + mmSums = _mm_add_ps(mmSums, _mm_load_ps(vector)); + incrementAll<4>(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; + + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (vector < sentinel) + result += *vector++; + + return result / static_cast(size); +} + +template <> +float meanSquared(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + + if (getSIMDOpStatus(SIMDOps::meanSquared)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned){ + result += (*vector) * (*vector); + vector++; + } + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + const auto mmValues = _mm_load_ps(vector); + mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); + incrementAll<4>(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; + + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (vector < sentinel){ + result += (*vector) * (*vector); + vector++; + } + + return result / static_cast(size); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 12accd63..69d3bb42 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -525,30 +525,37 @@ void copy(absl::Span input, absl::Span output) noexcept copy(input.data(), output.data(), minSpanSize(input, output)); } + /** * @brief Computes the mean of a span * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param vector + * @param size * @return T */ -template -T mean(absl::Span vector) noexcept +template +T mean(const T* vector, unsigned size) noexcept { T result{ 0.0 }; - if (vector.size() == 0) + if (size == 0) return result; - auto* value = vector.begin(); - while (value < vector.end()) - result += *value++; + const auto sentinel = vector + size; + while (vector < sentinel) + result += *vector++; - return result / static_cast(vector.size()); + return result / static_cast(size); } template <> -float mean(absl::Span vector) noexcept; +float mean(const float* vector, unsigned size) noexcept; + +template +T mean(absl::Span vector) noexcept +{ + return mean(vector.data(), vector.size()); +} /** * @brief Computes the mean squared of a span @@ -558,24 +565,30 @@ float mean(absl::Span vector) noexcept; * @param vector * @return T */ -template -T meanSquared(absl::Span vector) noexcept +template +T meanSquared(const T* vector, unsigned size) noexcept { T result{ 0.0 }; - if (vector.size() == 0) + if (size == 0) return result; - auto* value = vector.begin(); - while (value < vector.end()) { - result += (*value) * (*value); - value++; + const auto sentinel = vector + size; + while (vector < sentinel) { + result += (*vector) * (*vector); + vector++; } - return result / static_cast(vector.size()); + return result / static_cast(size); } template <> -float meanSquared(absl::Span vector) noexcept; +float meanSquared(const float* vector, unsigned size) noexcept; + +template +T meanSquared(absl::Span vector) noexcept +{ + return meanSquared(vector.data(), vector.size()); +} namespace _internals { template diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 9cf5ec04..ca29d7ba 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,75 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -float sfz::mean(absl::Span vector) noexcept -{ - float result { 0.0 }; - if (vector.size() == 0) - return result; - - auto* value = vector.begin(); - auto* sentinel = vector.end(); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(value) && value < lastAligned) - result += *value++; - - auto mmSums = _mm_setzero_ps(); - while (value < lastAligned) { - mmSums = _mm_add_ps(mmSums, _mm_load_ps(value)); - value += TypeAlignment; - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - while (value < sentinel) - result += *value++; - - return result / static_cast(vector.size()); -} - -template <> -float sfz::meanSquared(absl::Span vector) noexcept -{ - float result { 0.0 }; - if (vector.size() == 0) - return result; - - auto* value = vector.begin(); - auto* sentinel = vector.end(); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(value) && value < lastAligned) { - result += (*value) * (*value); - value++; - } - - auto mmSums = _mm_setzero_ps(); - while (value < lastAligned) { - const auto mmValues = _mm_load_ps(value); - mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); - value += TypeAlignment; - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - while (value < sentinel) { - result += (*value) * (*value); - value++; - } - - return result / static_cast(vector.size()); -} - template <> void sfz::cumsum(absl::Span input, absl::Span output) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index fd545249..0eefbd34 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -654,29 +654,41 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") TEST_CASE("[Helpers] Mean") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - REQUIRE(sfz::mean(input) == 5.5f); - REQUIRE(sfz::mean(input) == 5.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + REQUIRE(sfz::mean(input) == 5.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + REQUIRE(sfz::mean(input) == 5.5f); } TEST_CASE("[Helpers] Mean (SIMD vs scalar)") { std::vector input(bigBufferSize); absl::c_iota(input, 0.0f); - REQUIRE(sfz::mean(input) == Approx(sfz::mean(input)).margin(0.001)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto scalarResult = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto simdResult = sfz::mean(input); + REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Mean Squared") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - REQUIRE(sfz::meanSquared(input) == 38.5f); - REQUIRE(sfz::meanSquared(input) == 38.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + REQUIRE(sfz::meanSquared(input) == 38.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + REQUIRE(sfz::meanSquared(input) == 38.5f); } TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0f); - REQUIRE(sfz::meanSquared(input) == sfz::meanSquared(input)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto scalarResult = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto simdResult = sfz::meanSquared(input); + REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Cumulative sum")