// 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 "SIMDHelpers.h" #include "catch2/catch.hpp" #include #include #include #include #include using namespace Catch::literals; constexpr int smallBufferSize { 3 }; constexpr int bigBufferSize { 4095 }; constexpr int medBufferSize { 127 }; constexpr double fillValue { 1.3 }; template inline bool approxEqualMargin(absl::Span lhs, absl::Span rhs, Type eps = 1e-3) { if (lhs.size() != rhs.size()) return false; for (size_t i = 0; i < rhs.size(); ++i) if (rhs[i] != Approx(lhs[i]).margin(eps)) { std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n'; return false; } return true; } template inline bool approxEqual(absl::Span lhs, absl::Span rhs, Type eps = 1e-3) { if (lhs.size() != rhs.size()) return false; for (size_t i = 0; i < rhs.size(); ++i) if (rhs[i] != Approx(lhs[i]).epsilon(eps)) { std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n'; return false; } return true; } TEST_CASE("[Helpers] fill() - Manual buffer") { std::vector buffer(5); std::vector expected { fillValue, fillValue, fillValue, fillValue, fillValue }; fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer") { std::vector buffer(smallBufferSize); std::vector expected(smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer") { std::vector buffer(bigBufferSize); std::vector expected(bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer -- SIMD") { std::vector buffer(smallBufferSize); std::vector expected(smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer -- SIMD") { std::vector buffer(bigBufferSize); std::vector expected(bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer -- doubles") { std::vector buffer(smallBufferSize); std::vector expected(smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer -- doubles") { std::vector buffer(bigBufferSize); std::vector expected(bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] Interleaved read") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read unaligned end") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Small interleaved read unaligned end") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read -- SIMD") { std::array input = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD") { std::array input = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar") { std::array input; std::array leftOutputScalar; std::array rightOutputScalar; std::array leftOutputSIMD; std::array rightOutputSIMD; std::iota(input.begin(), input.end(), 0.0f); readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD)); REQUIRE(leftOutputScalar == leftOutputSIMD); REQUIRE(rightOutputScalar == rightOutputSIMD); } TEST_CASE("[Helpers] Interleaved write") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write unaligned end") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Small interleaved write unaligned end") { std::array leftInput { 0.0f, 1.0f, 2.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar") { std::array leftInput; std::array rightInput; std::array outputScalar; std::array outputSIMD; std::iota(leftInput.begin(), leftInput.end(), 0.0f); std::iota(rightInput.begin(), rightInput.end(), medBufferSize); writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); REQUIRE(outputScalar == outputSIMD); } TEST_CASE("[Helpers] Gain, single") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Gain, single and inplace") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] Gain, spans") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Gain, spans and inplace") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] Gain, single (SIMD)") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Gain, single and inplace (SIMD)") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] Gain, spans (SIMD)") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] SFZ looping index") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); REQUIRE(indices == expectedIndices); REQUIRE(approxEqual(leftCoeffs, expectedLeft)); REQUIRE(approxEqual(rightCoeffs, expectedRight)); } TEST_CASE("[Helpers] SFZ looping index (SIMD)") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); REQUIRE(indices == expectedIndices); REQUIRE(approxEqual(leftCoeffs, expectedLeft)); REQUIRE(approxEqual(rightCoeffs, expectedRight)); } // TEST_CASE("[Helpers] SFZ looping index (SIMD vs Scalar)") // { // std::vector jumps(bigBufferSize); // absl::c_fill(jumps, fillValue); // std::vector indices(bigBufferSize); // std::vector leftCoeffs(bigBufferSize); // std::vector rightCoeffs(bigBufferSize); // std::vector indicesSIMD(bigBufferSize); // std::vector leftCoeffsSIMD(bigBufferSize); // std::vector rightCoeffsSIMD(bigBufferSize); // loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, medBufferSize, 1); // loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, medBufferSize, 1); // for (int i = 0; i < bigBufferSize; ++i) // REQUIRE( ((static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i]).margin(1e-2)) // || (static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i] - static_cast(medBufferSize)).margin(2e-2))) ); // } TEST_CASE("[Helpers] SFZ saturating index") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 5, 5, 5 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f }; saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6); REQUIRE(indices == expectedIndices); REQUIRE(approxEqual(leftCoeffs, expectedLeft)); REQUIRE(approxEqual(rightCoeffs, expectedRight)); } TEST_CASE("[Helpers] SFZ saturating index (SIMD)") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 5, 5, 5 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f }; saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6); REQUIRE(indices == expectedIndices); REQUIRE(approxEqualMargin(leftCoeffs, expectedLeft)); REQUIRE(approxEqualMargin(rightCoeffs, expectedRight)); } TEST_CASE("[Helpers] SFZ saturating index (SIMD vs Scalar)") { std::vector jumps(medBufferSize); absl::c_fill(jumps, fillValue); std::vector indices(medBufferSize); std::vector leftCoeffs(medBufferSize); std::vector rightCoeffs(medBufferSize); std::vector indicesSIMD(medBufferSize); std::vector leftCoeffsSIMD(medBufferSize); std::vector rightCoeffsSIMD(medBufferSize); saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 78); saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, 78); for (int i = 0; i < medBufferSize; ++i) REQUIRE( static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i])); } TEST_CASE("[Helpers] Linear Ramp") { const float start { 0.0f }; const float v { fillValue }; std::array output; std::array expected { v, v + v, v + v + v, v + v + v + v, v + v + v + v + v, v + v + v + v + v + v }; linearRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } TEST_CASE("[Helpers] Linear Ramp (SIMD)") { const float start { 0.0f }; const float v { fillValue }; std::array output; std::array expected { v, v + v, v + v + v, v + v + v + v, v + v + v + v + v, v + v + v + v + v + v }; linearRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)") { const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); linearRamp(absl::MakeSpan(outputScalar), start, fillValue); linearRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)") { const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); linearRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); linearRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Multiplicative Ramp") { const float start { 1.0f }; const float v { fillValue }; std::array output; std::array expected { v, v * v, v * v * v, v * v * v * v, v * v * v * v * v, v * v * v * v * v * v }; multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)") { const float start { 1.0f }; const float v { fillValue }; std::array output; std::array expected { v, v * v, v * v * v, v * v * v * v, v * v * v * v * v, v * v * v * v * v * v }; multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)") { const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); multiplicativeRamp(absl::MakeSpan(outputScalar), start, fillValue); multiplicativeRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)") { const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); multiplicativeRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); multiplicativeRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Add") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0, 3.0, 4.0, 5.0, 6.0 }; add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Add (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0, 3.0, 4.0, 5.0, 6.0 }; add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Add (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0); absl::c_fill(outputScalar, 0.0); absl::c_fill(outputSIMD, 0.0); add(input, absl::MakeSpan(outputScalar)); add(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Subtract") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 0.0, -1.0, -2.0, -3.0, -4.0 }; subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Subtract (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 0.0, -1.0, -2.0, -3.0, -4.0 }; subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Subtract (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0); absl::c_fill(outputScalar, 0.0); absl::c_fill(outputSIMD, 0.0); subtract(input, absl::MakeSpan(outputScalar)); subtract(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] copy") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } TEST_CASE("[Helpers] copy (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } TEST_CASE("[Helpers] copy (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0); absl::c_fill(outputScalar, 0.0); absl::c_fill(outputSIMD, 0.0); add(input, absl::MakeSpan(outputScalar)); add(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } 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(mean(input) == 5.5f); REQUIRE(mean(input) == 5.5f); } TEST_CASE("[Helpers] Mean (SIMD vs scalar)") { std::vector input(bigBufferSize); absl::c_iota(input, 0.0); REQUIRE(mean(input) == Approx(mean(input)).margin(0.001)); } 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(meanSquared(input) == 38.5f); REQUIRE(meanSquared(input) == 38.5f); } TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0); REQUIRE(meanSquared(input) == meanSquared(input)); } TEST_CASE("[Helpers] Cumulative sum ") { std::array input { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array output; std::array expected { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; cumsum(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); linearRamp(absl::MakeSpan(input), 0.0, 0.1); cumsum(input, absl::MakeSpan(outputScalar)); cumsum(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); }