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)
{
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);
}
}
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD)
(benchmark::State& 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);
}
}
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned)
(benchmark::State& 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);
}
}
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned)
(benchmark::State& 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);
}
}

View file

@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar)
(benchmark::State& 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);
}
}
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD)
(benchmark::State& 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);
}
}
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned)
(benchmark::State& 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);
}
}
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned)
(benchmark::State& 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);
}
}

View file

@ -471,4 +471,87 @@ void copy<float>(const float* input, float* output, unsigned size) noexcept
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));
}
/**
* @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 <class T, bool SIMD = SIMDConfig::mean>
T mean(absl::Span<const T> vector) noexcept
template <class T>
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<T>(vector.size());
return result / static_cast<T>(size);
}
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
@ -558,24 +565,30 @@ float mean<float, true>(absl::Span<const float> vector) noexcept;
* @param vector
* @return T
*/
template <class T, bool SIMD = SIMDConfig::meanSquared>
T meanSquared(absl::Span<const T> vector) noexcept
template <class T>
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<T>(vector.size());
return result / static_cast<T>(size);
}
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 {
template <class T>

View file

@ -16,75 +16,6 @@
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 <>
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")
{
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);
REQUIRE(sfz::mean<float, true>(input) == 5.5f);
sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false);
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)")
{
std::vector<float> input(bigBufferSize);
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")
{
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);
REQUIRE(sfz::meanSquared<float, true>(input) == 38.5f);
sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false);
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)")
{
std::vector<float> input(medBufferSize);
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")