diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index a838f951..2f1300cf 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -51,10 +51,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_compile_options(-mfloat-abi=hard) endif() endif() - check_cxx_compiler_flag(-faligned-new SFIZZ_HAVE_FALIGNED_NEW) - if(SFIZZ_HAVE_FALIGNED_NEW) - add_compile_options($<$:-faligned-new>) - endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CMAKE_CXX_STANDARD 17) add_compile_options(/Zc:__cplusplus) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1538b4cc..bc1ad2cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ set(SFIZZ_HEADERS sfizz/utility/Debug.h sfizz/utility/LeakDetector.h sfizz/utility/Macros.h + sfizz/utility/MemoryHelpers.h sfizz/utility/NumericId.h sfizz/utility/StringViewHelpers.h sfizz/utility/SwapAndPop.h @@ -285,8 +286,8 @@ add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal - PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde sfizz::hiir - PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde sfizz::hiir sfizz::jsl + PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") target_link_libraries(sfizz_internal PUBLIC st_audiofile) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 9689c554..ae39b144 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -117,7 +117,9 @@ void streamFromFile(sfz::AudioReader& reader, uint32_t numFrames, sfz::Oversampl } sfz::FilePool::FilePool(sfz::Logger& logger) - : logger(logger), threadPool(globalThreadPool()) + : logger(logger), + filesToLoad(alignedNew()), + threadPool(globalThreadPool()) { loadingJobs.reserve(config::maxVoices); lastUsedFiles.reserve(config::maxVoices); @@ -350,8 +352,8 @@ sfz::FileDataHolder sfz::FilePool::getFilePromise(const std::shared_ptr& return {}; } QueuedFileData queuedData { fileId, &preloaded->second, std::chrono::high_resolution_clock::now() }; - if (!filesToLoad.try_push(queuedData)) { - DBG("[sfizz] Could not enqueue the file to load for " << fileId << " (queue capacity " << filesToLoad.capacity() << ")"); + if (!filesToLoad->try_push(queuedData)) { + DBG("[sfizz] Could not enqueue the file to load for " << fileId << " (queue capacity " << filesToLoad->capacity() << ")"); return {}; } @@ -498,7 +500,7 @@ void sfz::FilePool::dispatchingJob() noexcept while (dispatchBarrier.wait(), dispatchFlag) { std::lock_guard guard { loadingJobsMutex }; - if (filesToLoad.try_pop(queuedData)) { + if (filesToLoad->try_pop(queuedData)) { if (queuedData.id.expired()) { // file ID was nulled, it means the region was deleted, ignore } diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 7f61e2c8..976438fd 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -35,6 +35,7 @@ #include "Logger.h" #include "SpinMutex.h" #include "utility/LeakDetector.h" +#include "utility/MemoryHelpers.h" #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include class ThreadPool; namespace sfz { @@ -348,7 +350,10 @@ private: FileData* data { nullptr }; TimePoint queuedTime {}; }; - atomic_queue::AtomicQueue2 filesToLoad; + + using FileQueue = atomic_queue::AtomicQueue2; + aligned_unique_ptr filesToLoad; + void dispatchingJob() noexcept; void garbageJob() noexcept; void loadingJob(QueuedFileData data) noexcept; diff --git a/src/sfizz/Logger.cpp b/src/sfizz/Logger.cpp index 780ad81e..b0a767db 100644 --- a/src/sfizz/Logger.cpp +++ b/src/sfizz/Logger.cpp @@ -43,6 +43,8 @@ void printStatistics(std::vector& data) } sfz::Logger::Logger() + : callbackTimeQueue(alignedNew()), + fileTimeQueue(alignedNew()) { keepRunning.test_and_set(); clearFlag.test_and_set(); @@ -106,7 +108,7 @@ void sfz::Logger::logCallbackTime(const CallbackBreakdown& breakdown, int numVoi callbackTime.breakdown = breakdown; callbackTime.numVoices = numVoices; callbackTime.numSamples = numSamples; - callbackTimeQueue.try_push(callbackTime); + callbackTimeQueue->try_push(callbackTime); } void sfz::Logger::logFileTime(std::chrono::duration waitDuration, std::chrono::duration loadDuration, uint32_t fileSize, absl::string_view filename) @@ -119,7 +121,7 @@ void sfz::Logger::logFileTime(std::chrono::duration waitDuration, std::c fileTime.loadDuration = loadDuration; fileTime.fileSize = fileSize; fileTime.filename = filename; - fileTimeQueue.try_push(fileTime); + fileTimeQueue->try_push(fileTime); } void sfz::Logger::setPrefix(absl::string_view prefix) @@ -136,11 +138,11 @@ void sfz::Logger::moveEvents() noexcept { while(keepRunning.test_and_set()) { CallbackTime callbackTime; - while (callbackTimeQueue.try_pop(callbackTime)) + while (callbackTimeQueue->try_pop(callbackTime)) callbackTimes.push_back(callbackTime); FileTime fileTime; - while (fileTimeQueue.try_pop(fileTime)) + while (fileTimeQueue->try_pop(fileTime)) fileTimes.push_back(fileTime); if (!clearFlag.test_and_set()) { diff --git a/src/sfizz/Logger.h b/src/sfizz/Logger.h index c851dbbe..3aee168a 100644 --- a/src/sfizz/Logger.h +++ b/src/sfizz/Logger.h @@ -7,6 +7,7 @@ #pragma once #include "Config.h" #include "utility/LeakDetector.h" +#include "utility/MemoryHelpers.h" #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include namespace sfz { @@ -131,8 +133,11 @@ private: bool loggingEnabled { config::loggingEnabled }; std::string prefix { "" }; - atomic_queue::AtomicQueue2 callbackTimeQueue; - atomic_queue::AtomicQueue2 fileTimeQueue; + using CallbackTimeQueue = atomic_queue::AtomicQueue2; + using FileTimeQueue = atomic_queue::AtomicQueue2; + + aligned_unique_ptr callbackTimeQueue; + aligned_unique_ptr fileTimeQueue; std::vector callbackTimes; std::vector fileTimes; diff --git a/src/sfizz/utility/MemoryHelpers.h b/src/sfizz/utility/MemoryHelpers.h new file mode 100644 index 00000000..c2ba4511 --- /dev/null +++ b/src/sfizz/utility/MemoryHelpers.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include + +namespace sfz { + +/** + * @brief Allocate and initialize an object of type T, using sufficient + * alignment for the type. + * This provides compatibility with systems which do not support aligned-new. + */ +template +T* alignedNew(Args&& ...args) +{ + using allocator = jsl::aligned_allocator; + struct deleter { + void operator()(T* x) const noexcept { allocator().deallocate(x, sizeof(T)); } + }; + std::unique_ptr ptr { allocator().allocate(sizeof(T)) }; + allocator().construct(ptr.get(), std::forward(args)...); + return ptr.release(); +} + +/** + * @brief Deinitialize and deallocate the aligned object of type T. It must have + * been previously instantiated by alignedNew. + */ +template +void alignedDelete(T* ptr) +{ + using allocator = jsl::aligned_allocator; + if (ptr) { + ptr->~T(); + allocator().deallocate(ptr, sizeof(T)); + } +} + +/** + * @brief Deletes an object using alignedDelete. + */ +template +struct aligned_deleter { + void operator()(T* x) const noexcept { alignedDelete(x); } +}; + +/** + * @brief Unique pointer which uses alignedDelete as the cleanup function. + */ +template +using aligned_unique_ptr = std::unique_ptr>; + +} // namespace sfz