Move mean and meanSquared to the new format
This commit is contained in:
parent
8d2ac8ebd5
commit
59f284a82b
6 changed files with 148 additions and 101 deletions
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue