diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a0df0d..07e7589c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- [v3.4.1](#v341) - [v3.4.0](#v340) - [v3.3.1](#v331) - [v3.3.0](#v330) @@ -51,6 +52,10 @@ - [v1.1.0](#v110) - [v1.0.0](#v100) +## v3.4.1 + +- Reduce backend worker unnecessary allocation. ([#368](https://github.com/odygrd/quill/issues/368)) + ## v3.4.0 - Resolved `bad_variant_access` error occurring when using Quill as a pre-compiled library with a distinct queue diff --git a/quill/include/quill/Quill.h b/quill/include/quill/Quill.h index cc872e41..0f57f5c6 100644 --- a/quill/include/quill/Quill.h +++ b/quill/include/quill/Quill.h @@ -34,7 +34,7 @@ namespace quill /** Version Info **/ constexpr uint32_t VersionMajor{3}; constexpr uint32_t VersionMinor{4}; -constexpr uint32_t VersionPatch{0}; +constexpr uint32_t VersionPatch{1}; constexpr uint32_t Version{VersionMajor * 10000 + VersionMinor * 100 + VersionPatch}; /** forward declarations **/ diff --git a/quill/include/quill/detail/HandlerCollection.h b/quill/include/quill/detail/HandlerCollection.h index e7eb5f36..ffe01d3f 100644 --- a/quill/include/quill/detail/HandlerCollection.h +++ b/quill/include/quill/detail/HandlerCollection.h @@ -132,9 +132,9 @@ class HandlerCollection * The list contains each handler only once regardless the amount of Logger instances using it * This is not used for logging by the backend but only in special cases when * e.g. it needs to iterate through all handlers for e.g. to flush - * @return a vector containing all the active handlers + * @param active_handlers_collection active handlers collection */ - QUILL_NODISCARD std::vector> active_handlers() const; + void active_handlers(std::vector>& active_handlers_collection) const; /** * Called by the backend worker thread only to remove any handlers that are not longer in use diff --git a/quill/include/quill/detail/backend/BackendWorker.h b/quill/include/quill/detail/backend/BackendWorker.h index 985ab119..d6182fc7 100644 --- a/quill/include/quill/detail/backend/BackendWorker.h +++ b/quill/include/quill/detail/backend/BackendWorker.h @@ -155,7 +155,7 @@ class BackendWorker /** * Force flush all active Handlers */ - QUILL_ATTRIBUTE_HOT inline void _force_flush(std::vector> const& active_handlers); + QUILL_ATTRIBUTE_HOT inline void _force_flush(); /** * Check for dropped messages - only when bounded queue is used @@ -206,6 +206,7 @@ class BackendWorker std::vector> _args; /** Format args tmp storage as member to avoid reallocation */ std::vector> _printf_args; /** Format args tmp storage as member to avoid reallocation */ + std::vector> _active_handlers_cache; BacktraceStorage _backtrace_log_message_storage; /** Stores a vector of backtrace messages per logger name */ std::unordered_map>> _slog_templates; /** Avoid re-formating the same structured template each time */ @@ -755,7 +756,8 @@ void BackendWorker::_process_transit_event(TransitEvent& transit_event) } else if (macro_metadata.event() == MacroMetadata::Event::Flush) { - _force_flush(_handler_collection.active_handlers()); + _handler_collection.active_handlers(_active_handlers_cache); + _force_flush(); // this is a flush event, so we need to notify the caller to continue now transit_event.flush_flag->store(true); @@ -876,12 +878,12 @@ bool BackendWorker::_process_and_write_single_message(const ThreadContextCollect } /***/ -void BackendWorker::_force_flush(std::vector> const& active_handlers) +void BackendWorker::_force_flush() { if (_has_unflushed_messages) { // If we have buffered any messages then flush all active handlers - for (auto const& handler : active_handlers) + for (auto const& handler : _active_handlers_cache) { std::shared_ptr h = handler.lock(); if (h) @@ -1048,11 +1050,11 @@ void BackendWorker::_main_loop() { // None of the thread local queues had any events to process, this means we have processed // all messages in all queues We force flush all remaining messages - std::vector> const active_handlers = _handler_collection.active_handlers(); - _force_flush(active_handlers); + _handler_collection.active_handlers(_active_handlers_cache); + _force_flush(); // invoke the Handler's periodic loop - for (auto const& handler : active_handlers) + for (auto const& handler : _active_handlers_cache) { std::shared_ptr h = handler.lock(); if (h) @@ -1174,7 +1176,8 @@ void BackendWorker::_exit() { // we are done, all queues are now empty _check_message_failures(cached_thread_contexts, _notification_handler); - _force_flush(_handler_collection.active_handlers()); + _handler_collection.active_handlers(_active_handlers_cache); + _force_flush(); break; } } diff --git a/quill/src/detail/HandlerCollection.cpp b/quill/src/detail/HandlerCollection.cpp index 9d13f5d3..0614102b 100644 --- a/quill/src/detail/HandlerCollection.cpp +++ b/quill/src/detail/HandlerCollection.cpp @@ -69,16 +69,12 @@ void HandlerCollection::subscribe_handler(std::shared_ptr const& handle } /***/ -std::vector> HandlerCollection::active_handlers() const +void HandlerCollection::active_handlers(std::vector>& active_handlers_collection) const { - std::vector> subscribed_handlers_collection; - // Protect shared access, we just use a lock here since this function is not used when logging // messages but only in special cases e.g. flushing std::lock_guard const lock{_mutex}; - subscribed_handlers_collection = _active_handlers_collection; - - return subscribed_handlers_collection; + active_handlers_collection = _active_handlers_collection; } /***/