diff --git a/src/sfizz/Buffer.h b/src/sfizz/Buffer.h index c790be3f..60b87d3c 100644 --- a/src/sfizz/Buffer.h +++ b/src/sfizz/Buffer.h @@ -29,20 +29,65 @@ #include #include #include - +#ifdef DEBUG +#include +#endif namespace sfz { + /** - * @brief A heap buffer structure that tries to align its beginning and adds a small offset - * at the end for alignment too. + * @brief A buffer counting class that tries to track the memory usage. + */ +class BufferCounter +{ +public: + BufferCounter() = default; + ~BufferCounter() + { +#ifdef DEBUG + std::cout << "Remaining buffers on destruction: " << numBuffers << '\n'; + std::cout << "Total size: " << bytes << '\n'; +#endif + } + + void newBuffer(int size) + { + numBuffers++; + bytes.fetch_add(size); + } + + void bufferResized(int oldSize, int newSize) + { + bytes.fetch_add(newSize); + bytes.fetch_sub(oldSize); + } + + void bufferDeleted(int size) + { + numBuffers--; + bytes.fetch_sub(size); + } + + int getNumBuffers() { return numBuffers; } + int getTotalBytes() { return bytes; } +private: + std::atomic numBuffers { 0 }; + std::atomic bytes { 0 }; +}; + +/** + * @brief A heap buffer structure that tries to align its beginning and + * adds a small offset at the end for alignment too. * - * Apparently on Linux this effort is mostly useless, and in the end most of the SIMD operations - * are coded with alignment checks and sentinels so this class could probably be much simpler. - * It does however wrap realloc which in some cases should be a bit more efficient than - * allocating a whole new block. + * Apparently on Linux this effort is mostly useless, and in the end + * most of the SIMD operations are coded with alignment checks and + * sentinels so this class could probably be much simpler. It does + * however wrap realloc which in some cases should be a bit more + * efficient than allocating a whole new block. * - * @tparam Type The buffer type - * @tparam Alignment the required alignment in bytes (defaults to SIMDConfig::defaultAlignment) + * @tparam Type The buffer type + * @tparam Alignment the required alignment in bytes (defaults to + * SIMDConfig::defaultAlignment) */ template class Buffer { @@ -64,7 +109,7 @@ public: */ Buffer() { - + counter().newBuffer(0); } /** @@ -74,6 +119,7 @@ public: */ Buffer(size_t size) { + counter().newBuffer(0); resize(size); } @@ -98,6 +144,7 @@ public: return false; } + counter().bufferResized(largerSize * sizeof(value_type), tempSize * sizeof(value_type)); largerSize = tempSize; alignedSize = newSize; paddedData = static_cast(newData); @@ -118,6 +165,7 @@ public: */ void clear() { + counter().bufferResized(largerSize * sizeof(value_type), 0); largerSize = 0; alignedSize = 0; std::free(paddedData); @@ -127,6 +175,7 @@ public: } ~Buffer() { + counter().bufferDeleted(largerSize * sizeof(value_type)); std::free(paddedData); } @@ -194,6 +243,18 @@ public: constexpr pointer alignedEnd() noexcept { return _alignedEnd; } + /** + * @brief Return the buffer counter object. + * + * TODO: In C++ 17 all of this can be static inline. + * + * @return The buffer counter on which you can call various methods. + */ + static BufferCounter& counter() + { + static BufferCounter counter; + return counter; + } private: static constexpr auto AlignmentMask { Alignment - 1 }; static constexpr auto TypeAlignment { Alignment / sizeof(value_type) };