From 32aaa6b917eab3e14d9b8edc459627676ed3cbb4 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 30 Jul 2019 01:04:12 +0200 Subject: [PATCH] Added benchmarks and tests for AudioBuffers --- .gitmodules | 3 +++ CMakeLists.txt | 28 +++++++++++++++------ benchmarks/AudioBuffers.cpp | 49 +++++++++++++++++++++++++++++++++++++ benchmarks/Main.cpp | 3 +++ external/benchmark | 1 + sources/AudioBuffer.h | 45 +++++++++++++++++++++++++++++++++- sources/Buffer.h | 4 +-- tests/AudioBuffer.cpp | 19 ++++++++++++++ 8 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 benchmarks/AudioBuffers.cpp create mode 100644 benchmarks/Main.cpp create mode 160000 external/benchmark diff --git a/.gitmodules b/.gitmodules index 95dc9b52..3e32b9a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "external/cxxopts"] path = external/cxxopts url = https://github.com/jarro2783/cxxopts +[submodule "external/benchmark"] + path = external/benchmark + url = https://github.com/google/benchmark diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ae38de6..52b5ae0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,6 @@ project(sfizz VERSION 1.0.0 LANGUAGES CXX) # Set the highest possible standard set(CMAKE_CXX_STANDARD 17) -# Disable Abseil tests -set(BUILD_TESTING OFF) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT ANDROID) add_compile_options(-stdlib=libc++) @@ -15,11 +13,19 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT ANDROID) add_link_options(-stdlib=libc++) # New command on CMake master, not in 3.12 release endif() +# Disable Abseil tests +set(BUILD_TESTING OFF) add_subdirectory(external/abseil-cpp) add_subdirectory(external/spdlog) add_subdirectory(external/Catch2) add_subdirectory(external/cxxopts) +#Disable Benchmark tests and installation +set(BENCHMARK_ENABLE_TESTING OFF) +set(BENCHMARK_ENABLE_INSTALL OFF) +set(BENCHMARK_ENABLE_GTEST_TESTS OFF) +add_subdirectory(external/benchmark) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(COMMON_SOURCES @@ -31,10 +37,6 @@ set(COMMON_SOURCES ) set(TEST_SOURCES - sources/Opcode.cpp - sources/Synth.cpp - sources/Region.cpp - sources/Parser.cpp tests/Regex.cpp tests/Helpers.cpp tests/Region.cpp @@ -46,6 +48,10 @@ set(TEST_SOURCES tests/Main.cpp ) +set(BENCHMARK_SOURCES + benchmarks/Main.cpp + benchmarks/AudioBuffers.cpp +) ############################### add_executable(sfzprint sources/ParserMain.cpp ${COMMON_SOURCES}) @@ -74,4 +80,12 @@ target_link_libraries(sfizz_tests stdc++fs) endif(UNIX) target_link_libraries(sfizz_tests Catch2::Catch2 absl::strings) target_include_directories(sfizz_tests SYSTEM PRIVATE sources) -file(COPY "tests" DESTINATION ${CMAKE_BINARY_DIR}) \ No newline at end of file +file(COPY "tests" DESTINATION ${CMAKE_BINARY_DIR}) + +############################### +add_executable(sfizz_bench ${BENCHMARK_SOURCES} ${COMMON_SOURCES}) +# Per OS properties +if(UNIX) + target_link_libraries(sfizz_bench stdc++fs) +endif(UNIX) +target_link_libraries(sfizz_bench absl::strings benchmark) \ No newline at end of file diff --git a/benchmarks/AudioBuffers.cpp b/benchmarks/AudioBuffers.cpp new file mode 100644 index 00000000..c8bee337 --- /dev/null +++ b/benchmarks/AudioBuffers.cpp @@ -0,0 +1,49 @@ +#include +#include "../sources/AudioBuffer.h" +#include + +static void AB_Joint_Fill_float(benchmark::State& state) { + AudioBuffer buffer (65535); + float fillValue = 0.0f; + for (auto _ : state) { + std::fill(buffer.begin(0), buffer.end(0), fillValue); + std::fill(buffer.begin(1), buffer.end(1), fillValue); + fillValue += 1.0f; + } +} +// Register the function as a benchmark +BENCHMARK(AB_Joint_Fill_float); + +static void AB_Split_Fill_float(benchmark::State& state) { + SplitAudioBuffer buffer (65535); + float fillValue = 0.0f; + for (auto _ : state) { + std::fill(buffer.begin(0), buffer.end(0), fillValue); + std::fill(buffer.begin(1), buffer.end(1), fillValue); + fillValue += 1.0f; + } +} +BENCHMARK(AB_Split_Fill_float); + +static void AB_Joint_Fill_double(benchmark::State& state) { + AudioBuffer buffer (65535); + double fillValue = 0.0; + for (auto _ : state) { + std::fill(buffer.begin(0), buffer.end(0), fillValue); + std::fill(buffer.begin(1), buffer.end(1), fillValue); + fillValue += 1.0; + } +} +// Register the function as a benchmark +BENCHMARK(AB_Joint_Fill_double); + +static void AB_Split_Fill_double(benchmark::State& state) { + SplitAudioBuffer buffer (65535); + double fillValue = 0.0; + for (auto _ : state) { + std::fill(buffer.begin(0), buffer.end(0), fillValue); + std::fill(buffer.begin(1), buffer.end(1), fillValue); + fillValue += 1.0; + } +} +BENCHMARK(AB_Split_Fill_double); \ No newline at end of file diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp new file mode 100644 index 00000000..71fefa04 --- /dev/null +++ b/benchmarks/Main.cpp @@ -0,0 +1,3 @@ +#include + +BENCHMARK_MAIN(); diff --git a/external/benchmark b/external/benchmark new file mode 160000 index 00000000..66482d53 --- /dev/null +++ b/external/benchmark @@ -0,0 +1 @@ +Subproject commit 66482d538d6c6041b29ab6a95cf5b6d561fbd306 diff --git a/sources/AudioBuffer.h b/sources/AudioBuffer.h index be450b7f..df68625d 100644 --- a/sources/AudioBuffer.h +++ b/sources/AudioBuffer.h @@ -44,6 +44,30 @@ public: return nullptr; } + Type* begin(int channelIndex) noexcept + { + ASSERT(channelIndex >= 0); + return buffer.data() + numFrames * channelIndex; + } + + Type* end(int channelIndex) noexcept + { + ASSERT(channelIndex >= 0); + return buffer.data() + numFrames * (channelIndex + 1); + } + + // const Type* cbegin(int channelIndex) noexcept + // { + // ASSERT(channelIndex >= 0); + // return buffer.data() + numFrames * channelIndex; + // } + + // const Type* cend(int channelIndex) noexcept + // { + // ASSERT(channelIndex >= 0); + // return buffer.data() + numFrames * (channelIndex + 1); + // } + Type& operator()(int channelIndex, int sampleIndex) noexcept { return getSample(channelIndex, sampleIndex); @@ -99,13 +123,32 @@ public: Type* getChannel(int channelIndex) noexcept { - ASSERT(channelIndex >= 0); if (channelIndex < NumChannels) return &buffers[channelIndex].data(); else return nullptr; } + Type* begin(int channelIndex) noexcept + { + return buffers[channelIndex].begin(); + } + + Type* end(int channelIndex) noexcept + { + return buffers[channelIndex].end(); + } + + // const Type* cbegin(int channelIndex) noexcept + // { + // return buffers[channelIndex].cbegin(); + // } + + // const Type* cend(int channelIndex) noexcept + // { + // return buffers[channelIndex].cend(); + // } + int getNumFrames() const noexcept { return numFrames; } int getNumChannels() const noexcept { return NumChannels; } bool empty() const noexcept { return numFrames == 0; } diff --git a/sources/Buffer.h b/sources/Buffer.h index b20d0ab0..8c5e85cd 100644 --- a/sources/Buffer.h +++ b/sources/Buffer.h @@ -54,8 +54,8 @@ public: Type* begin() noexcept { return data(); } Type* end() noexcept { return data() + alignedSize; } - const Type* cbegin() const noexcept { return data(); } - const Type* cend() const noexcept { return data() + alignedSize; } + // const Type* cbegin() const noexcept { return data(); } + // const Type* cend() const noexcept { return data() + alignedSize; } private: size_t largerSize { 0 }; size_t alignedSize { 0 }; diff --git a/tests/AudioBuffer.cpp b/tests/AudioBuffer.cpp index 21d0e894..2e7f3c7c 100644 --- a/tests/AudioBuffer.cpp +++ b/tests/AudioBuffer.cpp @@ -91,4 +91,23 @@ TEST_CASE("[AudioBuffer/SplitBuffer] Access 2") for (auto chanIdx = 0; chanIdx < splitDoubleBuffer.getNumChannels(); ++chanIdx) for (auto frameIdx = 0; frameIdx < splitDoubleBuffer.getNumFrames(); ++frameIdx) REQUIRE(splitDoubleBuffer(chanIdx, frameIdx) == static_cast(splitDoubleBuffer.getNumFrames()) * chanIdx + frameIdx); +} + +TEST_CASE("[AudioBuffer/SplitBuffer] Iterators") +{ + const int size { 256 }; + const float fillValue { 2.0f }; + AudioBuffer buffer(size); + for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx) + std::fill(buffer.begin(chanIdx), buffer.end(chanIdx), fillValue); + + for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx) + REQUIRE( std::all_of(buffer.begin(chanIdx), buffer.end(chanIdx), [fillValue](auto value) { return value == fillValue; }) ); + + SplitAudioBuffer splitBuffer(size); + for (auto chanIdx = 0; chanIdx < splitBuffer.getNumChannels(); ++chanIdx) + std::fill(splitBuffer.begin(chanIdx), splitBuffer.end(chanIdx), fillValue); + + for (auto chanIdx = 0; chanIdx < splitBuffer.getNumChannels(); ++chanIdx) + REQUIRE( std::all_of(splitBuffer.begin(chanIdx), splitBuffer.end(chanIdx), [fillValue](auto value) { return value == fillValue; }) ); } \ No newline at end of file