Skip to content

Commit

Permalink
unified thread-local storage handling across platforms using `QUILL_T…
Browse files Browse the repository at this point in the history
…HREAD_LOCAL`
  • Loading branch information
odygrd committed Aug 20, 2024
1 parent 815ed84 commit 8f98f07
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 24 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@
attention. ([#526](https://github.com/odygrd/quill/pull/526))
- Enhanced static assert error message for unsupported codecs, providing clearer guidance for STL and user-defined
types.
- Improved frontend performance by using `__thread` for thread-local storage on Linux and falling back to `thread_local`
for other platforms.
- Improved frontend performance by caching the `ThreadContext` pointer in `Logger` class to avoid repeated function
calls. On Linux, this is now further optimised with `__thread` for thread-local storage, while other platforms still
use `thread_local`.

## v6.1.2

Expand Down Expand Up @@ -888,7 +889,7 @@ within a distinct namespace, there are no conflicts even if you link your own `l
```

- Added support for huge pages on Linux. Enabling this feature allows bounded or unbounded queues to utilize huge pages,
resulting in optimized memory allocation.
resulting in optimised memory allocation.

```c++
quill::Config cfg;
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@

Quill is a fast, feature-rich cross-platform logging library for C++ designed for low-latency and reliable logging.

- Low Latency Logging: Optimized to ensure minimal delay and efficient performance on the hot path.
- Low Latency Logging: Optimised to ensure minimal delay and efficient performance on the hot path.
- Battle-Tested: Proven in demanding production environments.
- Feature-Rich: Packed with advanced features to meet diverse logging needs.
- Extensive Documentation: Easy-to-follow guides and cheat sheets.
Expand Down
2 changes: 1 addition & 1 deletion docs/logging_macros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Logging Macros
Compile-Time Log Level Filtering
--------------------------------

To optimize performance by reducing branches in compiled code, you can enable compile-time filtering of log levels.
To optimise performance by reducing branches in compiled code, you can enable compile-time filtering of log levels.

This is done by defining `QUILL_COMPILE_ACTIVE_LOG_LEVEL` as a compilation flag or before including `LogMacros.h`:

Expand Down
4 changes: 2 additions & 2 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Overview
========

The library adopts asynchronous logging to optimize performance, particularly well-suited for low-latency applications where minimizing hot path latency is crucial, such as trading systems.
The library adopts asynchronous logging to optimise performance, particularly well-suited for low-latency applications where minimizing hot path latency is crucial, such as trading systems.

A dedicated backend thread manages log formatting and I/O operations, ensuring that even occasional log statements incur minimal overhead.

Expand All @@ -25,7 +25,7 @@ Reliable Logging Mechanism
--------------------------

Quill utilizes a thread-local single-producer-single-consumer queue to relay logs to the backend thread, ensuring that log messages are never dropped.
Initially, an unbounded queue with a small size is used to optimize performance.
Initially, an unbounded queue with a small size is used to optimise performance.
However, if the queue reaches its capacity, a new queue will be allocated, which may cause a slight performance penalty for the frontend.

The default unbounded queue can expand up to a size of 2GB. If this limit is reached, the caller thread will block.
Expand Down
16 changes: 3 additions & 13 deletions include/quill/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,11 @@ class LoggerImpl : public detail::LoggerBase
.count())
: user_clock->now();

#if defined(__GNUC__) && defined(__linux__)
// On GCC (or compatible compilers) running on Linux, use __thread for thread-local storage.
// This optimizes performance by caching the ThreadContext pointer to avoid repeatedly
// calling get_local_thread_context(). If the thread_context is not already set, we initialize it.
if (QUILL_UNLIKELY(thread_context == nullptr))
{
// This caches the ThreadContext pointer to avoid repeatedly calling get_local_thread_context()
thread_context = detail::get_local_thread_context<frontend_options_t>();
}
#else
// On other compilers or platforms, use thread_local to store the ThreadContext pointer.
// This ensures portability across different compilers and operating systems.
// We fetch the ThreadContext pointer each time by calling get_local_thread_context().
detail::ThreadContext* const thread_context =
quill::detail::get_local_thread_context<frontend_options_t>();
#endif

// Need to know how much size we need from the queue
size_t total_size = sizeof(current_timestamp) + (sizeof(uintptr_t) * 3) +
Expand Down Expand Up @@ -299,8 +289,8 @@ class LoggerImpl : public detail::LoggerBase
std::atomic<bool>* backend_thread_flushed_ptr = &backend_thread_flushed;

// We do not want to drop the message if a dropping queue is used
while (!this->log_statement<false>(
LogLevel::None, &macro_metadata, reinterpret_cast<uintptr_t>(backend_thread_flushed_ptr)))
while (!this->log_statement<false>(LogLevel::None, &macro_metadata,
reinterpret_cast<uintptr_t>(backend_thread_flushed_ptr)))
{
if (sleep_duration_ns > 0)
{
Expand Down
6 changes: 6 additions & 0 deletions include/quill/core/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
#define QUILL_AS_STR(x) #x
#define QUILL_STRINGIFY(x) QUILL_AS_STR(x)

#if defined(__GNUC__) && defined(__linux__)
#define QUILL_THREAD_LOCAL __thread
#else
#define QUILL_THREAD_LOCAL thread_local
#endif

QUILL_BEGIN_NAMESPACE

namespace detail
Expand Down
5 changes: 1 addition & 4 deletions include/quill/core/LoggerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,7 @@ class LoggerBase
protected:
friend class BackendWorker;

#if defined(__GNUC__) && defined(__linux__)
static inline __thread ThreadContext* thread_context = nullptr;
#endif

static inline QUILL_THREAD_LOCAL ThreadContext* thread_context = nullptr; /* Set and accessed by the frontend */
std::shared_ptr<PatternFormatter> pattern_formatter; /* The backend thread will set this once, we never access it on the frontend */
std::shared_ptr<BacktraceStorage> backtrace_storage; /* The backend thread will construct this, we never access it on the frontend */
std::vector<std::shared_ptr<Sink>> sinks; /* Set by the frontend and accessed by the backend */
Expand Down

0 comments on commit 8f98f07

Please sign in to comment.