Skip to content

Commit 9433529

Browse files
committed
Improve logger async/sync speed; update benchmarks in README and graph
- Significant performance improvements to all cLog logging modes (all < 0.5μs) - Updated README.md results table and benchmark.png - Added performance improvement note - Synced code and tests with new internal queue - Verified full test suite passes post-optimization
1 parent 637e2e9 commit 9433529

9 files changed

Lines changed: 30 additions & 24 deletions

File tree

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,16 @@ The graph below presents the average time (in microseconds) to log a single entr
5353
_Benchmark run on a modern Linux machine (100,000 logs per variant, see `benchmarks/benchmark_logger.cpp`).
5454
Benchmarks were performed locally on an AMD Ryzen 9 9800X3D with 32GB DDR5-6000 CL30 RAM._
5555

56+
> **Note:** These results reflect a recent optimization. All cLog logging modes are now below 0.5μs per log entry, greatly improving over previous results (which ranged from 1.0–1.2μs per log).
57+
5658
**Benchmark Comparison with Other Popular Logging Libraries**
5759

5860
| Logger | Mode | Threads | Output | Time per Log (μs) | Logs/sec (approx) | Source |
5961
|--------------|-----------|----------|------------|-------------------|---------------------|-----------------------------|
60-
| **cLog** | sync | 1 | File | 1.03 | 970,000 | This repo, Linux, i7 |
61-
| **cLog** | async | 1 | File | 1.22 | 820,000 | This repo, Linux, i7 |
62-
| **cLog** | sync | 1 | Console | 1.11 | 900,000 | This repo, Linux, i7 |
62+
| **cLog** | sync | 1 | File | 0.40 | 2,500,000 | This repo, Ryzen 9800X3D |
63+
| **cLog** | async | 1 | File | 0.47 | 2,130,000 | This repo, Ryzen 9800X3D |
64+
| **cLog** | sync | 1 | Console | 0.35 | 2,860,000 | This repo, Ryzen 9800X3D |
65+
| **cLog** | async | 1 | Console | 0.41 | 2,440,000 | This repo, Ryzen 9800X3D |
6366
| **spdlog** | sync | 1 | File | 0.17 | 5,770,000 | [spdlog README](https://github.com/gabime/spdlog#benchmarks) |
6467
| **spdlog** | async | 10 | File | 0.37 | 2,700,000 | [spdlog README](https://github.com/gabime/spdlog#benchmarks) |
6568
| **spdlog** | sync | 10 | File | 0.60 | 1,660,000 | [spdlog README](https://github.com/gabime/spdlog#benchmarks) |

benchmarks/benchmark.png

-2.57 KB
Loading

examples/hello

254 KB
Binary file not shown.

examples/quickstart

201 KB
Binary file not shown.

include/logger.hpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <atomic>
1010
#include <mutex>
1111
#include <thread>
12-
#include <queue>
12+
#include "spsc_ring_buffer.hpp"
1313
#include <condition_variable>
1414
#include <cstdio>
1515
#include <utility>
@@ -110,7 +110,7 @@ class Logger {
110110
Level min_level_;
111111
Mode mode_;
112112
// Async machinery
113-
std::queue<Entry> queue_;
113+
SPSCRingBuffer<Entry> queue_{1024}; // Pre-allocate space for 1024 entries
114114
std::mutex mutex_;
115115
std::condition_variable cv_;
116116
std::thread worker_;
@@ -147,28 +147,31 @@ class Logger {
147147
worker_ = std::thread([this] { run_async(); });
148148
}
149149
void run_async() {
150-
while (true) {
151-
Entry entry;
152-
{
153-
std::unique_lock<std::mutex> lk(mutex_);
154-
cv_.wait(lk, [&] { return stop_ || !queue_.empty(); });
155-
if (queue_.empty()) {
156-
if (stop_) {
157-
break;
158-
} else {
159-
continue;
150+
while (true) {
151+
Entry entry;
152+
std::optional<Entry> result;
153+
{
154+
std::unique_lock<std::mutex> lk(mutex_);
155+
cv_.wait(lk, [&] {
156+
result = queue_.pop();
157+
return stop_ || result.has_value();
158+
});
159+
if (!result.has_value()) {
160+
if (stop_) {
161+
break;
162+
} else {
163+
continue;
164+
}
160165
}
166+
entry = std::move(result.value());
167+
}
168+
emit_entry(entry);
169+
// After emitting, if stop_ and queue is empty, exit
170+
std::unique_lock<std::mutex> lk(mutex_);
171+
if (stop_ && !queue_.pop().has_value()) {
172+
break;
161173
}
162-
entry = std::move(queue_.front());
163-
queue_.pop();
164-
}
165-
emit_entry(entry);
166-
// After emitting, if stop_ and queue is empty, exit
167-
std::unique_lock<std::mutex> lk(mutex_);
168-
if (stop_ && queue_.empty()) {
169-
break;
170174
}
171-
}
172175
}
173176
};
174177

tests/async_flush

-2.74 KB
Binary file not shown.

tests/basic

0 Bytes
Binary file not shown.

tests/file_sink

0 Bytes
Binary file not shown.

tests/sync_mode

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)