From cc935ab34e5e3a72461bcb55f7c058eb02eb15a3 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 14 Oct 2020 22:52:43 +0200 Subject: [PATCH] Add basic FPU unit test --- libs/ardour/test/fpu_test.cc | 183 +++++++++++++++++++++++++++++++++++ libs/ardour/test/fpu_test.h | 53 ++++++++++ libs/ardour/wscript | 2 + 3 files changed, 238 insertions(+) create mode 100644 libs/ardour/test/fpu_test.cc create mode 100644 libs/ardour/test/fpu_test.h diff --git a/libs/ardour/test/fpu_test.cc b/libs/ardour/test/fpu_test.cc new file mode 100644 index 0000000000..bf50ff3db6 --- /dev/null +++ b/libs/ardour/test/fpu_test.cc @@ -0,0 +1,183 @@ +#include +#include "pbd/compose.h" +#include "pbd/fpu.h" +#include "pbd/malign.h" +#include "libs/ardour/ardour/mix.h" +#include "fpu_test.h" + +#if defined(__APPLE__) +#include +#endif + +CPPUNIT_TEST_SUITE_REGISTRATION(FPUTest); + +void +FPUTest::setUp () +{ + _size = 1024; + cache_aligned_malloc ((void**) &_test1, sizeof (float) * _size); + cache_aligned_malloc ((void**) &_test2, sizeof (float) * _size); + cache_aligned_malloc ((void**) &_comp1, sizeof (float) * _size); + cache_aligned_malloc ((void**) &_comp2, sizeof (float) * _size); + + for (size_t i = 0; i < _size; ++i) { + _test1[i] = _comp1[i] = 3.0 / (i + 1.0); + _test2[i] = _comp2[i] = 2.5 / (i + 1.0); + } + +} + +void +FPUTest::tearDown () +{ + cache_aligned_free (_comp1); + cache_aligned_free (_comp2); + cache_aligned_free (_test1); + cache_aligned_free (_test2); +} + +void +FPUTest::run () +{ + CPPUNIT_ASSERT_MESSAGE ("Aligned Malloc", (((intptr_t)_test1) % 32) == 0); + CPPUNIT_ASSERT_MESSAGE ("Aligned Malloc", (((intptr_t)_test2) % 32) == 0); + + apply_gain_to_buffer (_test1, _size, 1.33); + default_apply_gain_to_buffer (_comp1, _size, 1.33); + compare ("Apply Gain", _size); + + for (size_t off = 0; off < 32; ++off) { + for (size_t cnt = 1; cnt < 32; ++cnt) { + /* apply gain */ +#if 0 // This segfaults currently with AVX + apply_gain_to_buffer (&_test1[off], cnt, 0.99); + default_apply_gain_to_buffer (&_comp1[off], cnt, 0.99); + compare (string_compose ("Apply Gain not aligned off: %1 cnt: %2", off, cnt), cnt); +#endif + + /* compute peak */ + float pk_test = 0; + float pk_comp = 0; + pk_test = compute_peak (&_test1[off], cnt, pk_test); + pk_comp = default_compute_peak (&_comp1[off], cnt, pk_comp); + + CPPUNIT_ASSERT_MESSAGE (string_compose ("Compute peak not aligned off: %1 cnt: %2", off, cnt), fabsf (pk_test - pk_comp) < 1e-6); + + /* mix buffers w/gain */ + mix_buffers_with_gain (&_test1[off], &_test2[off], cnt, 0.45); + default_mix_buffers_with_gain (&_comp1[off], &_comp2[off], cnt, 0.45); + compare (string_compose ("Mix Buffers w/gain not aligned off: %1 cnt: %2", off, cnt), cnt); + + /* mix buffers w/o gain */ + mix_buffers_no_gain (&_test1[off], &_test2[off], cnt); + default_mix_buffers_no_gain (&_comp1[off], &_comp2[off], cnt); + compare (string_compose ("Mix Buffers no gain not aligned off: %1 cnt: %2", off, cnt), cnt); + + /* copy vector */ + copy_vector (&_test1[off], &_test2[off], cnt); + default_copy_vector (&_comp1[off], &_comp2[off], cnt); + compare (string_compose ("Copy Vector not aligned off: %1 cnt: %2", off, cnt), cnt); + + /* find_peaks */ + float pk_test_max; + float pk_comp_max; + find_peaks (&_test1[off], cnt, &pk_test, &pk_test_max); + default_find_peaks (&_comp1[off], cnt, &pk_comp, &pk_comp_max); + CPPUNIT_ASSERT_MESSAGE (string_compose ("Find peaks not aligned off: %1 cnt: %2", off, cnt), fabsf (pk_test - pk_comp) < 2e-6 && fabsf (pk_test_max - pk_comp_max) < 2e-6); + } + } +} + +void +FPUTest::compare (std::string msg, size_t cnt) +{ + size_t err = 0; + for (size_t i = 0; i < cnt; ++i) { + if (_test1[i] != _comp1[i]) { + ++err; + } + } + CPPUNIT_ASSERT_MESSAGE (msg, err == 0); +} + +#if defined(ARCH_X86) && defined(BUILD_SSE_OPTIMIZATIONS) +void +FPUTest::avxTest () +{ + PBD::FPU* fpu = PBD::FPU::instance (); + if (!fpu->has_avx ()) { + printf ("AVX is not available at run-time\n"); + return; + } + + compute_peak = x86_sse_avx_compute_peak; + find_peaks = x86_sse_avx_find_peaks; + apply_gain_to_buffer = x86_sse_avx_apply_gain_to_buffer; + mix_buffers_with_gain = x86_sse_avx_mix_buffers_with_gain; + mix_buffers_no_gain = x86_sse_avx_mix_buffers_no_gain; + copy_vector = x86_sse_avx_copy_vector; + + //run (); +} + +void +FPUTest::sseTest () +{ + PBD::FPU* fpu = PBD::FPU::instance (); + if (!fpu->has_avx ()) { + printf ("SSE is not available at run-time\n"); + return; + } + + compute_peak = x86_sse_compute_peak; + find_peaks = x86_sse_find_peaks; + apply_gain_to_buffer = x86_sse_apply_gain_to_buffer; + mix_buffers_with_gain = x86_sse_mix_buffers_with_gain; + mix_buffers_no_gain = x86_sse_mix_buffers_no_gain; + copy_vector = default_copy_vector; + + run (); +} + +#elif defined ARM_NEON_SUPPORT + +void +FPUTest::neonTest () +{ + PBD::FPU* fpu = PBD::FPU::instance (); + if (!fpu->has_neon ()) { + printf ("NEON is not available at run-time\n"); + return; + } + run (); +} + +#elif defined(__APPLE__) && defined(BUILD_VECLIB_OPTIMIZATIONS) + +void +FPUTest::veclibTest () +{ + CPPUNIT_ASSERT_MESSAGE ("Aligned Malloc", (((intptr_t)_test1) % 32) == 0); + if (floor (kCFCoreFoundationVersionNumber) <= kCFCoreFoundationVersionNumber10_4) { + printf ("veclib is not available at run-time\n"); + return; + } + + compute_peak = veclib_compute_peak; + find_peaks = veclib_find_peaks; + apply_gain_to_buffer = veclib_apply_gain_to_buffer; + mix_buffers_with_gain = veclib_mix_buffers_with_gain; + mix_buffers_no_gain = veclib_mix_buffers_no_gain; + copy_vector = default_copy_vector; + + run (); +} + +#else + +void +FPUTest::noTest () +{ + printf ("HW acceleration is disabled at compile-time\n"); +} +#endif diff --git a/libs/ardour/test/fpu_test.h b/libs/ardour/test/fpu_test.h new file mode 100644 index 0000000000..8e05a20780 --- /dev/null +++ b/libs/ardour/test/fpu_test.h @@ -0,0 +1,53 @@ +#include +#include + +#include "ardour/runtime_functions.h" + +class FPUTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (FPUTest); +#if defined(ARCH_X86) && defined(BUILD_SSE_OPTIMIZATIONS) + CPPUNIT_TEST (sseTest); + CPPUNIT_TEST (avxTest); +#elif defined ARM_NEON_SUPPORT + CPPUNIT_TEST (neonTest); +#elif defined(__APPLE__) && defined(BUILD_VECLIB_OPTIMIZATIONS) + CPPUNIT_TEST (veclibTest); +#else + CPPUNIT_TEST (noTest); +#endif + CPPUNIT_TEST_SUITE_END (); + +public: + void setUp (); + void tearDown (); + +#if defined(ARCH_X86) && defined(BUILD_SSE_OPTIMIZATIONS) + void avxTest (); + void sseTest (); +#elif defined ARM_NEON_SUPPORT + void neonTest (); +#elif defined(__APPLE__) && defined(BUILD_VECLIB_OPTIMIZATIONS) + void veclibTest (); +#else + void noTest (); +#endif + +private: + void run (); + void compare (std::string, size_t); + + ARDOUR::compute_peak_t compute_peak; + ARDOUR::find_peaks_t find_peaks; + ARDOUR::apply_gain_to_buffer_t apply_gain_to_buffer; + ARDOUR::mix_buffers_with_gain_t mix_buffers_with_gain; + ARDOUR::mix_buffers_no_gain_t mix_buffers_no_gain; + ARDOUR::copy_vector_t copy_vector; + + size_t _size; + + float* _test1; + float* _test2; + float* _comp1; + float* _comp2; +}; diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 367c2b7f95..04b7d7ac0c 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -557,6 +557,7 @@ def build(bld): create_ardour_test_program(bld, obj.includes, 'audio_engine_test', 'test_audio_engine', ['test/audio_engine_test.cc']) create_ardour_test_program(bld, obj.includes, 'automation_list_property_test', 'test_automation_list_property', ['test/automation_list_property_test.cc']) create_ardour_test_program(bld, obj.includes, 'bbt', 'test_bbt', ['test/bbt_test.cc']) + create_ardour_test_program(bld, obj.includes, 'fpu', 'test_fpu', ['test/fpu_test.cc']) create_ardour_test_program(bld, obj.includes, 'tempo', 'test_tempo', ['test/tempo_test.cc']) create_ardour_test_program(bld, obj.includes, 'lua_script', 'test_lua_script', ['test/lua_script_test.cc']) create_ardour_test_program(bld, obj.includes, 'midi_clock', 'test_midi_clock', ['test/midi_clock_test.cc']) @@ -578,6 +579,7 @@ def build(bld): test/automation_list_property_test.cc test/bbt_test.cc test/dsp_load_calculator_test.cc + test/fpu_test.cc test/tempo_test.cc test/lua_script_test.cc test/midi_clock_test.cc