Use fmt::string_view when logging a C string to avoid unnecessary copy
This commit is contained in:
		
							parent
							
								
									4b66e94ecf
								
							
						
					
					
						commit
						cb71fea0f6
					
				| @ -29,6 +29,7 @@ using namespace utils; | |||||||
| void bench(int howmany, std::shared_ptr<spdlog::logger> log); | void bench(int howmany, std::shared_ptr<spdlog::logger> log); | ||||||
| void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); | void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); | ||||||
| void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log); | void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log); | ||||||
|  | void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log); | ||||||
| 
 | 
 | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
| @ -81,6 +82,21 @@ int main(int argc, char *argv[]) | |||||||
| 
 | 
 | ||||||
|         bench_default_api(howmany, spdlog::create<null_sink_st>("null_st")); |         bench_default_api(howmany, spdlog::create<null_sink_st>("null_st")); | ||||||
| 
 | 
 | ||||||
|  |         spdlog::info("**************************************************************"); | ||||||
|  |         spdlog::info("C-string. Single thread, {:n} iterations", howmany); | ||||||
|  |         spdlog::info("**************************************************************"); | ||||||
|  | 
 | ||||||
|  |         basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_cs.log", true); | ||||||
|  |         bench_c_string(howmany, std::move(basic_st)); | ||||||
|  | 
 | ||||||
|  |         rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_cs.log", file_size, rotating_files); | ||||||
|  |         bench_c_string(howmany, std::move(rotating_st)); | ||||||
|  | 
 | ||||||
|  |         daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_cs.log"); | ||||||
|  |         bench_c_string(howmany, std::move(daily_st)); | ||||||
|  | 
 | ||||||
|  |         bench_c_string(howmany, spdlog::create<null_sink_st>("null_st")); | ||||||
|  | 
 | ||||||
|         spdlog::info("**************************************************************"); |         spdlog::info("**************************************************************"); | ||||||
|         spdlog::info("{:n} threads sharing same logger, {:n} iterations", threads, howmany); |         spdlog::info("{:n} threads sharing same logger, {:n} iterations", threads, howmany); | ||||||
|         spdlog::info("**************************************************************"); |         spdlog::info("**************************************************************"); | ||||||
| @ -173,3 +189,26 @@ void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log) | |||||||
|     spdlog::set_default_logger(std::move(orig_default)); |     spdlog::set_default_logger(std::move(orig_default)); | ||||||
|     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); |     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) | ||||||
|  | { | ||||||
|  |     const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " \ | ||||||
|  |         "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " \ | ||||||
|  |         "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " \ | ||||||
|  |         "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " \ | ||||||
|  |         "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; | ||||||
|  |     using std::chrono::high_resolution_clock; | ||||||
|  |     auto orig_default = spdlog::default_logger(); | ||||||
|  |     spdlog::set_default_logger(log); | ||||||
|  |     auto start = high_resolution_clock::now(); | ||||||
|  |     for (auto i = 0; i < howmany; ++i) | ||||||
|  |     { | ||||||
|  |         spdlog::log(level::info, msg); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto delta = high_resolution_clock::now() - start; | ||||||
|  |     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||||
|  |     spdlog::drop(log->name()); | ||||||
|  |     spdlog::set_default_logger(std::move(orig_default)); | ||||||
|  |     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
|  | } | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "chrono" | #include "chrono" | ||||||
|  | #include "spdlog/details/log_msg.h" | ||||||
| #include "spdlog/fmt/fmt.h" | #include "spdlog/fmt/fmt.h" | ||||||
| 
 | 
 | ||||||
| // Some fmt helpers to efficiently format and pad ints and strings
 | // Some fmt helpers to efficiently format and pad ints and strings
 | ||||||
| @ -40,6 +41,17 @@ inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | |||||||
|     dest.append(i.data(), i.data() + i.size()); |     dest.append(i.data(), i.data() + i.size()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template<size_t Buffer_Size> | ||||||
|  | inline void append_msg(const details::log_msg &msg, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | ||||||
|  | { | ||||||
|  |     auto *c_buf = msg.c_string.data(); | ||||||
|  |     if (c_buf != nullptr) { | ||||||
|  |         dest.append(c_buf, c_buf + msg.c_string.size()); | ||||||
|  |     } else { | ||||||
|  |         append_buf(msg.raw, dest); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| template<size_t Buffer_Size> | template<size_t Buffer_Size> | ||||||
| inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | ||||||
| { | { | ||||||
|  | |||||||
| @ -39,6 +39,9 @@ struct log_msg | |||||||
|     log_clock::time_point time; |     log_clock::time_point time; | ||||||
|     size_t thread_id; |     size_t thread_id; | ||||||
|     fmt::memory_buffer raw; |     fmt::memory_buffer raw; | ||||||
|  |     // if c_string.data() is not nullptr, c_string should be used as the message
 | ||||||
|  |     // instead of raw above 
 | ||||||
|  |     fmt::string_view c_string; | ||||||
|     size_t msg_id; |     size_t msg_id; | ||||||
| 
 | 
 | ||||||
|     // info about wrapping the formatted text with color (updated by pattern_formatter).
 |     // info about wrapping the formatted text with color (updated by pattern_formatter).
 | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ inline spdlog::logger::logger(std::string logger_name, It begin, It end) | |||||||
|     , flush_level_(level::off) |     , flush_level_(level::off) | ||||||
|     , last_err_time_(0) |     , last_err_time_(0) | ||||||
|     , msg_counter_(1) // message counter will start from 1. 0-message id will be
 |     , msg_counter_(1) // message counter will start from 1. 0-message id will be
 | ||||||
|                       // reserved for controll messages
 |                       // reserved for control messages
 | ||||||
| { | { | ||||||
|     err_handler_ = [this](const std::string &msg) { this->default_err_handler_(msg); }; |     err_handler_ = [this](const std::string &msg) { this->default_err_handler_(msg); }; | ||||||
| } | } | ||||||
| @ -70,8 +70,12 @@ inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Ar | |||||||
|     SPDLOG_CATCH_AND_HANDLE |     SPDLOG_CATCH_AND_HANDLE | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const char *msg) | inline void spdlog::logger::log(level::level_enum lvl, const char *msg) | ||||||
|  | { | ||||||
|  |     logn(lvl, msg, std::char_traits<char>::length(msg)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void spdlog::logger::logn(level::level_enum lvl, const char *msg, size_t msg_len) | ||||||
| { | { | ||||||
|     if (!should_log(lvl)) |     if (!should_log(lvl)) | ||||||
|     { |     { | ||||||
| @ -80,7 +84,7 @@ inline void spdlog::logger::log(level::level_enum lvl, const char *msg) | |||||||
|     try |     try | ||||||
|     { |     { | ||||||
|         details::log_msg log_msg(&name_, lvl); |         details::log_msg log_msg(&name_, lvl); | ||||||
|         details::fmt_helper::append_c_str(msg, log_msg.raw); |         log_msg.c_string = fmt::string_view(msg, msg_len); | ||||||
|         sink_it_(log_msg); |         sink_it_(log_msg); | ||||||
|     } |     } | ||||||
|     SPDLOG_CATCH_AND_HANDLE |     SPDLOG_CATCH_AND_HANDLE | ||||||
|  | |||||||
| @ -401,7 +401,7 @@ class v_formatter final : public flag_formatter | |||||||
| { | { | ||||||
|     void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override |     void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override | ||||||
|     { |     { | ||||||
|         fmt_helper::append_buf(msg.raw, dest); |         fmt_helper::append_msg(msg, dest); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -524,7 +524,7 @@ class full_formatter final : public flag_formatter | |||||||
|         msg.color_range_end = dest.size(); |         msg.color_range_end = dest.size(); | ||||||
|         dest.push_back(']'); |         dest.push_back(']'); | ||||||
|         dest.push_back(' '); |         dest.push_back(' '); | ||||||
|         fmt_helper::append_buf(msg.raw, dest); |         fmt_helper::append_msg(msg, dest); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "spdlog/details/fmt_helper.h" | ||||||
| #include "spdlog/details/log_msg.h" | #include "spdlog/details/log_msg.h" | ||||||
| #include "spdlog/details/mpmc_blocking_q.h" | #include "spdlog/details/mpmc_blocking_q.h" | ||||||
| #include "spdlog/details/os.h" | #include "spdlog/details/os.h" | ||||||
| @ -77,7 +78,7 @@ struct async_msg | |||||||
|         , msg_id(m.msg_id) |         , msg_id(m.msg_id) | ||||||
|         , worker_ptr(std::move(worker)) |         , worker_ptr(std::move(worker)) | ||||||
|     { |     { | ||||||
|         fmt_helper::append_buf(m.raw, raw); |         fmt_helper::append_msg(m, raw); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async_msg(async_logger_ptr &&worker, async_msg_type the_type) |     async_msg(async_logger_ptr &&worker, async_msg_type the_type) | ||||||
|  | |||||||
| @ -46,9 +46,10 @@ public: | |||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void log(level::level_enum lvl, const char *fmt, const Args &... args); |     void log(level::level_enum lvl, const char *fmt, const Args &... args); | ||||||
| 
 | 
 | ||||||
|     template<typename... Args> |  | ||||||
|     void log(level::level_enum lvl, const char *msg); |     void log(level::level_enum lvl, const char *msg); | ||||||
| 
 | 
 | ||||||
|  |     void logn(level::level_enum lvl, const char *msg, size_t msg_len); | ||||||
|  | 
 | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void trace(const char *fmt, const Args &... args); |     void trace(const char *fmt, const Args &... args); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ protected: | |||||||
|         fmt::memory_buffer formatted; |         fmt::memory_buffer formatted; | ||||||
|         if (use_raw_msg_) |         if (use_raw_msg_) | ||||||
|         { |         { | ||||||
|             details::fmt_helper::append_buf(msg.raw, formatted); |             details::fmt_helper::append_msg(msg, formatted); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|  | |||||||
| @ -53,7 +53,12 @@ public: | |||||||
| protected: | protected: | ||||||
|     void sink_it_(const details::log_msg &msg) override |     void sink_it_(const details::log_msg &msg) override | ||||||
|     { |     { | ||||||
|         ::syslog(syslog_prio_from_level(msg), "%s", fmt::to_string(msg.raw).c_str()); |         if (msg.c_string.data() != nullptr) | ||||||
|  |         { | ||||||
|  |             ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast<int>(msg.c_string.size()), msg.c_string.data()); | ||||||
|  |         } else { | ||||||
|  |             ::syslog(syslog_prio_from_level(msg), "%s", fmt::to_string(msg.raw).c_str()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void flush_() override {} |     void flush_() override {} | ||||||
|  | |||||||
| @ -231,3 +231,22 @@ TEST_CASE("default logger API", "[default logger]") | |||||||
|     spdlog::drop_all(); |     spdlog::drop_all(); | ||||||
|     spdlog::set_pattern("%v"); |     spdlog::set_pattern("%v"); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | TEST_CASE("C string", "[c_string]") | ||||||
|  | { | ||||||
|  |     std::ostringstream oss; | ||||||
|  |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss); | ||||||
|  | 
 | ||||||
|  |     spdlog::logger oss_logger("oss", oss_sink); | ||||||
|  |     oss_logger.set_level(spdlog::level::debug); | ||||||
|  |     oss_logger.set_pattern("*** %v"); | ||||||
|  | 
 | ||||||
|  |     const char *test_string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit massa nunc"; | ||||||
|  | 
 | ||||||
|  |     oss_logger.log(spdlog::level::debug, test_string); | ||||||
|  |     REQUIRE(oss.str() == "*** " + std::string(test_string) + std::string(spdlog::details::os::default_eol)); | ||||||
|  | 
 | ||||||
|  |     oss.str(""); | ||||||
|  |     oss_logger.logn(spdlog::level::debug, test_string, 11); | ||||||
|  |     REQUIRE(oss.str() == "*** " + std::string(test_string, 11) + std::string(spdlog::details::os::default_eol)); | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user