From 5c2855e1c1fbbf4f338f4d08427507336d5a48f5 Mon Sep 17 00:00:00 2001 From: gabime Date: Thu, 5 Sep 2019 01:25:00 +0300 Subject: [PATCH] wip backtracer --- bench/bench.cpp | 3 - include/spdlog/details/backtracer-inl.h | 74 ++++++++ include/spdlog/details/backtracer.h | 94 +++------- include/spdlog/details/circular_q.h | 169 +++++++++--------- include/spdlog/logger-inl.h | 5 +- include/spdlog/sinks/daily_file_sink.h | 4 +- include/spdlog/sinks/rotating_file_sink-inl.h | 10 +- src/spdlog.cpp | 2 +- tests/test_misc.cpp | 7 +- 9 files changed, 193 insertions(+), 175 deletions(-) create mode 100644 include/spdlog/details/backtracer-inl.h diff --git a/bench/bench.cpp b/bench/bench.cpp index 860d7699..591057bd 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -59,7 +59,6 @@ void bench_threaded_logging(int threads, int iters) daily_mt_tracing->enable_backtrace(32); bench_mt(iters, std::move(daily_mt_tracing), threads); - spdlog::info(""); auto empty_logger = std::make_shared("level-off"); empty_logger->set_level(spdlog::level::off); @@ -68,7 +67,6 @@ void bench_threaded_logging(int threads, int iters) empty_logger_tracing->set_level(spdlog::level::off); empty_logger_tracing->enable_backtrace(32); bench(iters, empty_logger_tracing); - } void bench_single_threaded(int iters) @@ -77,7 +75,6 @@ void bench_single_threaded(int iters) spdlog::info("Single threaded: {:n} messages", iters); spdlog::info("**************************************************************"); - auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); bench(iters, std::move(basic_st)); diff --git a/include/spdlog/details/backtracer-inl.h b/include/spdlog/details/backtracer-inl.h new file mode 100644 index 00000000..910a7192 --- /dev/null +++ b/include/spdlog/details/backtracer-inl.h @@ -0,0 +1,74 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +#include "spdlog/details/backtracer.h" +#endif +namespace spdlog { +namespace details { +SPDLOG_INLINE backtracer::backtracer(const backtracer &other) +{ + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; +} + +SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT +{ + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); +} + +SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) +{ + std::lock_guard lock(mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; + return *this; +} + +SPDLOG_INLINE void backtracer::enable(size_t size) +{ + std::lock_guard lock{mutex_}; + enabled_.store(true, std::memory_order_relaxed); + messages_ = circular_q{size}; +} + +SPDLOG_INLINE void backtracer::disable() +{ + std::lock_guard lock{mutex_}; + enabled_.store(false, std::memory_order_relaxed); +} + +SPDLOG_INLINE bool backtracer::enabled() const +{ + return enabled_.load(std::memory_order_relaxed); +} + +SPDLOG_INLINE backtracer::operator bool() const +{ + return enabled(); +} + +SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) +{ + std::lock_guard lock{mutex_}; + messages_.push_back(log_msg_buffer{msg}); +} + +// pop all items in the q and apply the given fun on each of them. +SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) +{ + std::lock_guard lock{mutex_}; + while (!messages_.empty()) + { + log_msg_buffer popped; + messages_.pop_front(popped); + fun(popped); + } +} +} // namespace details +} // namespace spdlog diff --git a/include/spdlog/details/backtracer.h b/include/spdlog/details/backtracer.h index 2dab7aff..f93c845c 100644 --- a/include/spdlog/details/backtracer.h +++ b/include/spdlog/details/backtracer.h @@ -12,80 +12,34 @@ // Useful for storing debug data in case of error/warning happens. namespace spdlog { - namespace details { - class backtracer - { - mutable std::mutex mutex_; - std::atomic enabled_ {false}; - circular_q messages_; +namespace details { +class backtracer +{ + mutable std::mutex mutex_; + std::atomic enabled_{false}; + circular_q messages_; - public: - backtracer() = default; - backtracer(const backtracer& other) - { - std::lock_guard lock(other.mutex_); - enabled_ = other.enabled(); - messages_ = other.messages_; - } - - backtracer(backtracer&& other) SPDLOG_NOEXCEPT - { - std::lock_guard lock(other.mutex_); - enabled_ = other.enabled(); - messages_ = std::move(other.messages_); - } - - backtracer& operator=(backtracer other) - { - std::lock_guard lock(mutex_); - enabled_ = other.enabled(); - messages_ = other.messages_; - return *this; - } - - void enable(size_t size) - { - std::lock_guard lock{ mutex_ }; - enabled_.store(true, std::memory_order_relaxed); - messages_ = circular_q{ size }; - } +public: + backtracer() = default; + backtracer(const backtracer &other); - void disable() - { - std::lock_guard lock{ mutex_ }; - enabled_.store(false, std::memory_order_relaxed); - } + backtracer(backtracer &&other) SPDLOG_NOEXCEPT; + backtracer &operator=(backtracer other); + void enable(size_t size); + void disable(); + bool enabled() const; + explicit operator bool() const; + void push_back(const log_msg &msg); + // pop all items in the q and apply the given fun on each of them. + void foreach_pop(std::function fun); - bool enabled() const - { - return enabled_.load(std::memory_order_relaxed); - } +}; - explicit operator bool() const - { - return enabled(); - } +} // namespace details +} // namespace spdlog - void push_back(const log_msg &msg) - { - std::lock_guard lock{ mutex_ }; - messages_.push_back(log_msg_buffer{ msg }); - } - - // pop all items in the q and apply the given fun on each of them. - void foreach_pop(std::function fun) - { - std::lock_guard lock{ mutex_ }; - while (!messages_.empty()) - { - log_msg_buffer popped; - messages_.pop_front(popped); - fun(popped); - } - } - }; - - } // namespace details -} // namespace spdlog \ No newline at end of file +#ifdef SPDLOG_HEADER_ONLY +#include "backtracer-inl.h" +#endif \ No newline at end of file diff --git a/include/spdlog/details/circular_q.h b/include/spdlog/details/circular_q.h index d2eeb021..5bcd8697 100644 --- a/include/spdlog/details/circular_q.h +++ b/include/spdlog/details/circular_q.h @@ -7,100 +7,95 @@ #include namespace spdlog { - namespace details { - template - class circular_q +namespace details { +template +class circular_q +{ + size_t max_items_ = 0; + typename std::vector::size_type head_ = 0; + typename std::vector::size_type tail_ = 0; + size_t overrun_counter_ = 0; + std::vector v_; + +public: + using item_type = T; + + // empty cir + circular_q() = default; + + explicit circular_q(size_t max_items) + : max_items_(max_items + 1) // one item is reserved as marker for full q + , v_(max_items_) + {} + + circular_q(const circular_q &) = default; + circular_q &operator=(const circular_q &) = default; + + // move cannot be default, + // since we need to reset head_, tail_, etc to zero in the moved object + circular_q(circular_q &&other) SPDLOG_NOEXCEPT + { + copy_moveable(std::move(other)); + } + + circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT + { + copy_moveable(std::move(other)); + return *this; + } + + // push back, overrun (oldest) item if no room left + void push_back(T &&item) + { + if (max_items_ > 0) { - size_t max_items_ = 0; - typename std::vector::size_type head_ = 0; - typename std::vector::size_type tail_ = 0; - size_t overrun_counter_ = 0; - std::vector v_; + v_[tail_] = std::move(item); + tail_ = (tail_ + 1) % max_items_; - public: - using item_type = T; - - // empty cir - circular_q() = default; - - explicit circular_q(size_t max_items) - : max_items_(max_items + 1) // one item is reserved as marker for full q - , v_(max_items_) - {} - - - - circular_q(const circular_q&) = default; - circular_q& operator=(const circular_q&) = default; - - // move cannot be default, - // since we need to reset head_, tail_, etc to zero in the moved object - circular_q(circular_q&& other) SPDLOG_NOEXCEPT + if (tail_ == head_) // overrun last item if full { - copy_moveable(std::move(other)); + head_ = (head_ + 1) % max_items_; + ++overrun_counter_; } + } + } - circular_q& operator=(circular_q&& other) SPDLOG_NOEXCEPT - { - copy_moveable(std::move(other)); - return *this; - } + // Pop item from front. + // If there are no elements in the container, the behavior is undefined. + void pop_front(T &popped_item) + { + if (max_items_ > 0) + { + popped_item = std::move(v_[head_]); + head_ = (head_ + 1) % max_items_; + } + } + bool empty() + { + return tail_ == head_; + } - // push back, overrun (oldest) item if no room left - void push_back(T &&item) - { - if(max_items_ > 0) - { - v_[tail_] = std::move(item); - tail_ = (tail_ + 1) % max_items_; + bool full() + { + // head is ahead of the tail by 1 + return ((tail_ + 1) % max_items_) == head_; + } - if (tail_ == head_) // overrun last item if full - { - head_ = (head_ + 1) % max_items_; - ++overrun_counter_; - } - } - } + size_t overrun_counter() const + { + return overrun_counter_; + } - // Pop item from front. - // If there are no elements in the container, the behavior is undefined. - void pop_front(T &popped_item) - { - if(max_items_ > 0) - { - popped_item = std::move(v_[head_]); - head_ = (head_ + 1) % max_items_; - } - } - - bool empty() - { - return tail_ == head_; - } - - bool full() - { - // head is ahead of the tail by 1 - return ((tail_ + 1) % max_items_) == head_; - } - - size_t overrun_counter() const - { - return overrun_counter_; - } - - private: - void copy_moveable(circular_q&& other) SPDLOG_NOEXCEPT - { - max_items_ = other.max_items_; - head_ = other.head_; - tail_ = other.tail_; - overrun_counter_ = other.overrun_counter_, - v_ = std::move(other.v_); - other.max_items_ = 0; // disable other - } - - }; - } // namespace details +private: + void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT + { + max_items_ = other.max_items_; + head_ = other.head_; + tail_ = other.tail_; + overrun_counter_ = other.overrun_counter_, v_ = std::move(other.v_); + other.max_items_ = 0; // disable other + } +}; +} // namespace details } // namespace spdlog diff --git a/include/spdlog/logger-inl.h b/include/spdlog/logger-inl.h index 357e8325..458d47aa 100644 --- a/include/spdlog/logger-inl.h +++ b/include/spdlog/logger-inl.h @@ -23,8 +23,7 @@ SPDLOG_INLINE logger::logger(const logger &other) , flush_level_(other.flush_level_.load(std::memory_order_relaxed)) , custom_err_handler_(other.custom_err_handler_) , tracer_(other.tracer_) -{ -} +{} SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)), sinks_(std::move(other.sinks_)), @@ -57,7 +56,7 @@ SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT other.flush_level_.store(tmp); custom_err_handler_.swap(other.custom_err_handler_); - std::swap(tracer_, other.tracer_); + std::swap(tracer_, other.tracer_); } SPDLOG_INLINE void swap(logger &a, logger &b) diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index fbcfeaee..6f80af40 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -30,8 +30,8 @@ struct daily_filename_calculator { filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), - basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); + return fmt::format( + SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); } }; diff --git a/include/spdlog/sinks/rotating_file_sink-inl.h b/include/spdlog/sinks/rotating_file_sink-inl.h index 2e459cbf..15443c5a 100644 --- a/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/include/spdlog/sinks/rotating_file_sink-inl.h @@ -43,12 +43,12 @@ SPDLOG_INLINE rotating_file_sink::rotating_file_sink( template SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename_t &filename, std::size_t index) { - if(index == 0u) - { - return filename; - } + if (index == 0u) + { + return filename; + } - filename_t basename, ext; + filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); return fmt::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); } diff --git a/src/spdlog.cpp b/src/spdlog.cpp index d30665aa..fd591bbb 100644 --- a/src/spdlog.cpp +++ b/src/spdlog.cpp @@ -12,7 +12,7 @@ #include "spdlog/spdlog-inl.h" #include "spdlog/common-inl.h" - +#include "spdlog/details/backtracer-inl.h" #include "spdlog/logger-inl.h" template spdlog::logger::logger(std::string name, sinks_init_list::iterator begin, sinks_init_list::iterator end); diff --git a/tests/test_misc.cpp b/tests/test_misc.cpp index 54878192..576005a4 100644 --- a/tests/test_misc.cpp +++ b/tests/test_misc.cpp @@ -2,7 +2,6 @@ #include "test_sink.h" #include "spdlog/fmt/bin_to_hex.h" - template std::string log_info(const T &what, spdlog::level::level_enum logger_level = spdlog::level::info) { @@ -109,7 +108,7 @@ TEST_CASE("clone-logger", "[clone]") logger->info("Some message 1"); cloned->info("Some message 2"); - REQUIRE(test_sink->lines().size()==2); + REQUIRE(test_sink->lines().size() == 2); REQUIRE(test_sink->lines()[0] == "Some message 1"); REQUIRE(test_sink->lines()[1] == "Some message 2"); @@ -121,7 +120,7 @@ TEST_CASE("clone async", "[clone]") using namespace spdlog; spdlog::init_thread_pool(4, 1); - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); auto logger = std::make_shared("orig", test_sink, spdlog::thread_pool()); logger->set_pattern("%v"); auto cloned = logger->clone("clone"); @@ -136,7 +135,7 @@ TEST_CASE("clone async", "[clone]") spdlog::details::os::sleep_for_millis(10); - REQUIRE(test_sink->lines().size()==2); + REQUIRE(test_sink->lines().size() == 2); REQUIRE(test_sink->lines()[0] == "Some message 1"); REQUIRE(test_sink->lines()[1] == "Some message 2");