From 68aebe613a57c4c902637d77e9a5432d56f787f8 Mon Sep 17 00:00:00 2001 From: HawkinWay <1826784860@qq.com> Date: Sat, 25 Jul 2026 00:42:38 +0800 Subject: [PATCH 1/3] feat: replace seq_cst with acquire release ordering (#3) --- include/spsc/ring_buffer.hpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/include/spsc/ring_buffer.hpp b/include/spsc/ring_buffer.hpp index 77bc924..57b2040 100644 --- a/include/spsc/ring_buffer.hpp +++ b/include/spsc/ring_buffer.hpp @@ -20,24 +20,37 @@ class RingBuffer{ } // producer - bool push(const T& item) { - if (full()) return false; - buffer_[write_idx.load() % capacity_] = item; - write_idx.fetch_add(1); // write_idx++; is okay + bool push(const T& item) { + const size_t current_w = write_idx.load(std::memory_order_relaxed); + const size_t current_r = read_idx.load(std::memory_order_acquire); + if (current_w - current_r == capacity_) return false; + buffer_[current_w % capacity_] = item; + write_idx.store(current_w + 1, std::memory_order_release); return true; } // consumer - bool pop(T& item) { - if (empty()) return false; - item = buffer_[read_idx.load() % capacity_]; - read_idx.fetch_add(1); + bool pop(T& item) { + const size_t current_r = read_idx.load(std::memory_order_relaxed); + const size_t current_w = write_idx.load(std::memory_order_acquire); + if (current_w == current_r) return false; + item = buffer_[current_r % capacity_]; + read_idx.store(current_r + 1, std::memory_order_release); return true; } - bool empty() const { return write_idx.load() == read_idx.load(); } + bool empty() const { + return write_idx.load(std::memory_order_relaxed) == read_idx.load(std::memory_order_relaxed); + } + bool full() const { return size() == capacity_; } - size_t size() const { return write_idx.load() - read_idx.load(); } + + size_t size() const { + // Approximate size in concurrent context. + // Not linearizable. + return write_idx.load(std::memory_order_relaxed) - read_idx.load(std::memory_order_relaxed); + } + size_t capacity() const { return capacity_; } private: From 454bbb5b1d5b35f72e8fa4b3da00d6049ee0b396 Mon Sep 17 00:00:00 2001 From: HawkinWay <1826784860@qq.com> Date: Sat, 25 Jul 2026 01:06:04 +0800 Subject: [PATCH 2/3] docs: update benchmark report with #3 --- docs/benchmark_report.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/benchmark_report.md b/docs/benchmark_report.md index 7baa673..403b6ff 100644 --- a/docs/benchmark_report.md +++ b/docs/benchmark_report.md @@ -45,4 +45,25 @@ Performance drops from: This provides the motivation for exploring acquire/release ordering and cache-line optimization. ---- \ No newline at end of file +--- + +## v0.2 Optimization + +### 📈 SPSC RingBuffer Acquire-Release (Issue #3) + +* **Test Platform**: Apple M4 (10 Cores, macOS) +* **Compiler**: Apple Clang (`-O3` Release) +* **Memory Order**: `std::memory_order_relaxed`, `std::memory_order_release`, `std::memory_order_acquire` +* **Alignment**: Default Non-alignment (Maybe have false sharing) + +| Capacity | Operation Latency(avg) | Throughput(ops/s) | 5-run std. dev. (CV) | +|:---------|:-----------------------|:------------------|:---------------------| +| **64** | ~15.46 ns | **64.65 M/s** | 6.98% | +| **1024** | ~14.94 ns | **66.95 M/s** | 9.37% | +| **4096** | ~16.52 ns | **60.53 M/s** | 11.86% | + +### 👀 Observation + +Switching from `seq_cst` to fine-grained Acquire-Release memory ordering yields only a minor performance gain (from **60.32M ops/s** to **66.95M ops/s**, ~10% improvement). + +This key observation reveals that instruction reordering and full memory barriers are **not the primary bottleneck** at this stage. Instead, the system is severely memory-bound due to **False Sharing**: `write_idx` and `read_idx` reside on the same 64-byte cache line, causing constant cache-line invalidation (cache ping-pong) between CPU cores via the MESI protocol. \ No newline at end of file From e92cf7193e1fb6746ebdc632495e532a7a0841a3 Mon Sep 17 00:00:00 2001 From: HawkinWay <1826784860@qq.com> Date: Sat, 25 Jul 2026 16:12:56 +0800 Subject: [PATCH 3/3] fix(ci): resolve MSVC runtime mismatch with GoogleTest --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bd4838..5446b03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(SPSCRingbuffer VERSION 1.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# MSVC runtime +if(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") +endif () + add_library(spsc_ring_buffer INTERFACE) target_include_directories(spsc_ring_buffer INTERFACE