Move mean and meanSquared to the new format

This commit is contained in:
Paul Ferrand 2020-05-31 10:54:32 +02:00 committed by Jean Pierre Cimalando
parent 8d2ac8ebd5
commit 59f284a82b
6 changed files with 148 additions and 101 deletions

View file

@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::mean<float, false>(input); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false);
auto result = sfz::mean<float>(input);
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::mean<float, true>(input); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true);
auto result = sfz::mean<float>(input);
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::mean<float, false>(absl::MakeSpan(input).subspan(1)); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false);
auto result = sfz::mean<float>(absl::MakeSpan(input).subspan(1));
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::mean<float, true>(absl::MakeSpan(input).subspan(1)); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true);
auto result = sfz::mean<float>(absl::MakeSpan(input).subspan(1));
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }

View file

@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::meanSquared<float, false>(input); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false);
auto result = sfz::meanSquared<float>(input);
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::meanSquared<float, true>(input); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true);
auto result = sfz::meanSquared<float>(input);
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::meanSquared<float, false>(absl::MakeSpan(input).subspan(1)); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false);
auto result = sfz::meanSquared<float>(absl::MakeSpan(input).subspan(1));
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned)
(benchmark::State& state) (benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
auto result = sfz::meanSquared<float, true>(absl::MakeSpan(input).subspan(1)); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true);
auto result = sfz::meanSquared<float>(absl::MakeSpan(input).subspan(1));
benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(result);
} }
} }

View file

@ -471,4 +471,87 @@ void copy<float>(const float* input, float* output, unsigned size) noexcept
std::copy(input, sentinel, output); std::copy(input, sentinel, output);
} }
template <>
float mean<float>(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<float, 4> 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<float>(size);
}
template <>
float meanSquared<float>(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<float, 4> 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<float>(size);
}
} }

View file

@ -525,30 +525,37 @@ void copy(absl::Span<const T> input, absl::Span<T> output) noexcept
copy<T>(input.data(), output.data(), minSpanSize(input, output)); copy<T>(input.data(), output.data(), minSpanSize(input, output));
} }
/** /**
* @brief Computes the mean of a span * @brief Computes the mean of a span
* *
* @tparam T the underlying type * @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param vector * @param vector
* @param size
* @return T * @return T
*/ */
template <class T, bool SIMD = SIMDConfig::mean> template <class T>
T mean(absl::Span<const T> vector) noexcept T mean(const T* vector, unsigned size) noexcept
{ {
T result{ 0.0 }; T result{ 0.0 };
if (vector.size() == 0) if (size == 0)
return result; return result;
auto* value = vector.begin(); const auto sentinel = vector + size;
while (value < vector.end()) while (vector < sentinel)
result += *value++; result += *vector++;
return result / static_cast<T>(vector.size()); return result / static_cast<T>(size);
} }
template <> template <>
float mean<float, true>(absl::Span<const float> vector) noexcept; float mean<float>(const float* vector, unsigned size) noexcept;
template <class T>
T mean(absl::Span<const T> vector) noexcept
{
return mean(vector.data(), vector.size());
}
/** /**
* @brief Computes the mean squared of a span * @brief Computes the mean squared of a span
@ -558,24 +565,30 @@ float mean<float, true>(absl::Span<const float> vector) noexcept;
* @param vector * @param vector
* @return T * @return T
*/ */
template <class T, bool SIMD = SIMDConfig::meanSquared> template <class T>
T meanSquared(absl::Span<const T> vector) noexcept T meanSquared(const T* vector, unsigned size) noexcept
{ {
T result{ 0.0 }; T result{ 0.0 };
if (vector.size() == 0) if (size == 0)
return result; return result;
auto* value = vector.begin(); const auto sentinel = vector + size;
while (value < vector.end()) { while (vector < sentinel) {
result += (*value) * (*value); result += (*vector) * (*vector);
value++; vector++;
} }
return result / static_cast<T>(vector.size()); return result / static_cast<T>(size);
} }
template <> template <>
float meanSquared<float, true>(absl::Span<const float> vector) noexcept; float meanSquared<float>(const float* vector, unsigned size) noexcept;
template <class T>
T meanSquared(absl::Span<const T> vector) noexcept
{
return meanSquared(vector.data(), vector.size());
}
namespace _internals { namespace _internals {
template <class T> template <class T>

View file

@ -16,75 +16,6 @@
constexpr uintptr_t TypeAlignment = 4; constexpr uintptr_t TypeAlignment = 4;
template <>
float sfz::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) && 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<float, 4> sseResult;
_mm_store_ps(sseResult.data(), mmSums);
for (auto sseValue : sseResult)
result += sseValue;
while (value < sentinel)
result += *value++;
return result / static_cast<float>(vector.size());
}
template <>
float sfz::meanSquared<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) && 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<float, 4> sseResult;
_mm_store_ps(sseResult.data(), mmSums);
for (auto sseValue : sseResult)
result += sseValue;
while (value < sentinel) {
result += (*value) * (*value);
value++;
}
return result / static_cast<float>(vector.size());
}
template <> template <>
void sfz::cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept void sfz::cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
{ {

View file

@ -654,29 +654,41 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)")
TEST_CASE("[Helpers] Mean") 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 }; 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(sfz::mean<float, false>(input) == 5.5f); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false);
REQUIRE(sfz::mean<float, true>(input) == 5.5f); REQUIRE(sfz::mean<float>(input) == 5.5f);
sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true);
REQUIRE(sfz::mean<float>(input) == 5.5f);
} }
TEST_CASE("[Helpers] Mean (SIMD vs scalar)") TEST_CASE("[Helpers] Mean (SIMD vs scalar)")
{ {
std::vector<float> input(bigBufferSize); std::vector<float> input(bigBufferSize);
absl::c_iota(input, 0.0f); absl::c_iota(input, 0.0f);
REQUIRE(sfz::mean<float, false>(input) == Approx(sfz::mean<float, true>(input)).margin(0.001)); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false);
auto scalarResult = sfz::mean<float>(input);
sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true);
auto simdResult = sfz::mean<float>(input);
REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) );
} }
TEST_CASE("[Helpers] Mean Squared") TEST_CASE("[Helpers] Mean Squared")
{ {
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 }; 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(sfz::meanSquared<float, false>(input) == 38.5f); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false);
REQUIRE(sfz::meanSquared<float, true>(input) == 38.5f); REQUIRE(sfz::meanSquared<float>(input) == 38.5f);
sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true);
REQUIRE(sfz::meanSquared<float>(input) == 38.5f);
} }
TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)")
{ {
std::vector<float> input(medBufferSize); std::vector<float> input(medBufferSize);
absl::c_iota(input, 0.0f); absl::c_iota(input, 0.0f);
REQUIRE(sfz::meanSquared<float, false>(input) == sfz::meanSquared<float, true>(input)); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false);
auto scalarResult = sfz::meanSquared<float>(input);
sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true);
auto simdResult = sfz::meanSquared<float>(input);
REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) );
} }
TEST_CASE("[Helpers] Cumulative sum") TEST_CASE("[Helpers] Cumulative sum")