Added a mean (reduce) SIMD/scalar helper
This commit is contained in:
parent
ebd2b1906a
commit
c4f681c371
7 changed files with 165 additions and 1 deletions
90
benchmarks/BM_mean.cpp
Normal file
90
benchmarks/BM_mean.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// 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 "../sfizz/SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
class MeanArray : 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 };
|
||||
input = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]])
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<float> input;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(MeanArray, Scalar)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = mean<float, false>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MeanArray, SIMD)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = mean<float, true>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = mean<float, false>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = mean<float, true>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(MeanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -69,11 +69,15 @@ target_link_libraries(bm_copy benchmark absl::span absl::algorithm)
|
|||
add_executable(bm_pan BM_pan.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_pan benchmark absl::span absl::algorithm)
|
||||
|
||||
add_executable(bm_mean BM_mean.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_mean benchmark absl::span absl::algorithm)
|
||||
|
||||
add_custom_target(sfizz_benchmarks)
|
||||
add_dependencies(sfizz_benchmarks
|
||||
bm_opf_high_vs_low
|
||||
bm_write
|
||||
bm_read
|
||||
bm_mean
|
||||
bm_fill
|
||||
bm_mathfuns
|
||||
bm_gain
|
||||
|
|
|
|||
|
|
@ -59,4 +59,5 @@ namespace SIMDConfig {
|
|||
constexpr bool multiplyAdd { false };
|
||||
constexpr bool copy { false };
|
||||
constexpr bool pan { true };
|
||||
constexpr bool mean { true };
|
||||
}
|
||||
|
|
@ -130,4 +130,10 @@ template <>
|
|||
void pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
pan<float, false>(panEnvelope, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
template <>
|
||||
float mean<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
return mean<float, false>(vector);
|
||||
}
|
||||
|
|
@ -412,4 +412,21 @@ void pan(absl::Span<const T> panEnvelope, absl::Span<T> leftBuffer, absl::Span<T
|
|||
}
|
||||
|
||||
template <>
|
||||
void pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept;
|
||||
void pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept;
|
||||
|
||||
template <class T, bool SIMD = SIMDConfig::mean>
|
||||
T mean(absl::Span<const T> vector) noexcept
|
||||
{
|
||||
T result { 0.0 };
|
||||
if (vector.size() == 0)
|
||||
return result;
|
||||
|
||||
auto* value = vector.begin();
|
||||
while (value < vector.end())
|
||||
result += *value++;
|
||||
|
||||
return result / static_cast<T>(vector.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
float mean<float, true>(absl::Span<const float> vector) noexcept;
|
||||
|
|
@ -600,4 +600,36 @@ void pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> lef
|
|||
|
||||
while (pan < sentinel)
|
||||
snippetPan(pan, left, right);
|
||||
}
|
||||
|
||||
template <>
|
||||
float mean<float, true>(absl::Span<const float> 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))
|
||||
result += *value++;
|
||||
|
||||
auto mmValues = _mm_setzero_ps();
|
||||
while(value < lastAligned) {
|
||||
mmValues = _mm_add_ps(mmValues, _mm_load_ps(value));
|
||||
value += TypeAlignment;
|
||||
}
|
||||
|
||||
std::array<float, 4> sseResult;
|
||||
_mm_store_ps(sseResult.data(), mmValues);
|
||||
|
||||
for (auto sseValue: sseResult)
|
||||
result += sseValue;
|
||||
|
||||
while (value < sentinel)
|
||||
result += *value++;
|
||||
|
||||
return result / static_cast<float>(vector.size());
|
||||
}
|
||||
|
|
@ -684,3 +684,17 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)")
|
|||
add<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean")
|
||||
{
|
||||
std::array<float, 10> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f };
|
||||
REQUIRE(mean<float, false>(input) == 5.5f);
|
||||
REQUIRE(mean<float, true>(input) == 5.5f);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean (SIMD vs scalar)")
|
||||
{
|
||||
std::vector<float> input(bigBufferSize);
|
||||
absl::c_iota(input, 0.0);
|
||||
REQUIRE(mean<float, false>(input) == mean<float, true>(input));
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue