| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| * (the "License"); you may not use this file except in compliance with | |
| * the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <log4cxx/logger.h> | |
| #include <log4cxx/xml/domconfigurator.h> | |
| #include <log4cxx/patternlayout.h> | |
| #include <log4cxx/consoleappender.h> | |
| #include <log4cxx/helpers/transcoder.h> | |
| #include <string> | |
| #include <thread> | |
| #if LOG4CXX_USING_STD_FORMAT | |
| #include <format> | |
| #else | |
| #include <fmt/core.h> | |
| #include <fmt/chrono.h> | |
| #include <fmt/ostream.h> | |
| #endif | |
| #include "log4cxxbenchmarker.h" | |
| using log4cxx::LogString; | |
| static log4cxx::LoggerPtr console = log4cxx::Logger::getLogger( "console" ); | |
| static std::vector<uint64_t> results; | |
| static std::mutex results_mutex; | |
| static void benchmark_function( const std::string& name, void (*fn)(int), int howmany ) | |
| { | |
| using std::chrono::duration; | |
| using std::chrono::duration_cast; | |
| using std::chrono::high_resolution_clock; | |
| auto start = high_resolution_clock::now(); | |
| fn(howmany); | |
| auto delta = high_resolution_clock::now() - start; | |
| auto delta_d = duration_cast<duration<double>>(delta).count(); | |
| std::lock_guard<std::mutex> lk(results_mutex); | |
| results.push_back( uint64_t(howmany / delta_d) ); | |
| LOG4CXX_INFO_FMT( console, "Log4cxx {} Elapsed: {:.4} secs {:L}/sec", | |
| name, | |
| delta_d, | |
| results.back()); | |
| } | |
| static void benchmark_conversion_pattern( const std::string& name, | |
| const std::string& conversion_pattern, | |
| void(*fn)(const LogString&, int), | |
| int howmany) | |
| { | |
| using std::chrono::duration; | |
| using std::chrono::duration_cast; | |
| using std::chrono::high_resolution_clock; | |
| auto start = high_resolution_clock::now(); | |
| LOG4CXX_DECODE_CHAR(conversion_patternLS, conversion_pattern); | |
| fn(conversion_patternLS, howmany); | |
| auto delta = high_resolution_clock::now() - start; | |
| auto delta_d = duration_cast<duration<double>>(delta).count(); | |
| std::lock_guard<std::mutex> lk(results_mutex); | |
| results.push_back( uint64_t(howmany / delta_d) ); | |
| LOG4CXX_INFO_FMT( console, "Log4cxx {} pattern: {} Elapsed: {:.4} secs {:L}/sec", | |
| name, | |
| conversion_pattern, | |
| delta_d, | |
| results.back()); | |
| } | |
| static void bench_log4cxx_single_threaded(int iters) | |
| { | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| LOG4CXX_INFO_FMT(console, "Benchmarking Single threaded: {} messages", iters ); | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| benchmark_conversion_pattern( "NoFormat", "%m%n", &log4cxxbenchmarker::logWithConversionPattern, iters ); | |
| benchmark_conversion_pattern( "DateOnly", "[%d] %m%n", &log4cxxbenchmarker::logWithConversionPattern, iters ); | |
| benchmark_conversion_pattern( "DateClassLevel", "[%d] [%c] [%p] %m%n", &log4cxxbenchmarker::logWithConversionPattern, iters ); | |
| benchmark_function( "Logging with FMT", &log4cxxbenchmarker::logWithFMT, iters ); | |
| benchmark_function( "Logging static string", &log4cxxbenchmarker::logStaticString, iters ); | |
| benchmark_function( "Logging static string with FMT", &log4cxxbenchmarker::logStaticStringFMT, iters ); | |
| benchmark_function( "Logging disabled debug", &log4cxxbenchmarker::logDisabledDebug, iters ); | |
| benchmark_function( "Logging disabled trace", &log4cxxbenchmarker::logDisabledTrace, iters ); | |
| benchmark_function( "Logging enabled debug", &log4cxxbenchmarker::logEnabledDebug, iters ); | |
| benchmark_function( "Logging enabled trace", &log4cxxbenchmarker::logEnabledTrace, iters ); | |
| } | |
| static void bench_log4cxx_multi_threaded(size_t threads, int iters) | |
| { | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| LOG4CXX_INFO_FMT(console, "Benchmarking multithreaded threaded: {} messages/thread, {} threads", iters, threads ); | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| std::vector<std::thread> runningThreads; | |
| auto logger = log4cxxbenchmarker::logSetupMultithreaded(); | |
| for ( size_t x = 0; x < threads; x++ ) | |
| { | |
| runningThreads.push_back( std::thread( [iters]() | |
| { | |
| benchmark_function( "Logging with FMT MT", &log4cxxbenchmarker::logWithFMTMultithreaded, iters ); | |
| }) ); | |
| } | |
| for ( std::thread& th : runningThreads ) | |
| { | |
| th.join(); | |
| } | |
| } | |
| static void bench_log4cxx_multi_threaded_disabled(size_t threads, int iters) | |
| { | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| LOG4CXX_INFO_FMT(console, "Benchmarking multithreaded disabled: {} messages/thread, {} threads", iters, threads ); | |
| LOG4CXX_INFO(console, LOG4CXX_STR("**************************************************************")); | |
| std::vector<std::thread> runningThreads; | |
| auto logger = log4cxxbenchmarker::logSetupMultithreaded(); | |
| for ( size_t x = 0; x < threads; x++ ) | |
| { | |
| runningThreads.push_back( std::thread( [iters]() | |
| { | |
| benchmark_function( "Logging disabled MT", &log4cxxbenchmarker::logDisabledMultithreaded, iters ); | |
| }) ); | |
| } | |
| for ( std::thread& th : runningThreads ) | |
| { | |
| th.join(); | |
| } | |
| } | |
| int main(int argc, char* argv[]) | |
| { | |
| int iters = 1000000; | |
| size_t threads = 4; | |
| size_t max_threads = 32; | |
| std::setlocale( LC_ALL, "" ); /* Set locale for C functions */ | |
| std::locale::global(std::locale("")); /* set locale for C++ functions */ | |
| console->setAdditivity( false ); | |
| log4cxx::PatternLayoutPtr pattern( new log4cxx::PatternLayout() ); | |
| pattern->setConversionPattern( LOG4CXX_STR("%m%n") ); | |
| log4cxx::ConsoleAppenderPtr consoleWriter( new log4cxx::ConsoleAppender ); | |
| consoleWriter->setLayout( pattern ); | |
| consoleWriter->setTarget( LOG4CXX_STR("System.out") ); | |
| log4cxx::helpers::Pool p; | |
| consoleWriter->activateOptions(p); | |
| console->addAppender( consoleWriter ); | |
| if (argc > 1) | |
| { | |
| iters = std::stoi(argv[1]); | |
| } | |
| if (argc > 2) | |
| { | |
| threads = std::stoul(argv[2]); | |
| } | |
| if (threads > max_threads) | |
| { | |
| LOG4CXX_ERROR_FMT(console, "Too many threads specified(max: {})", max_threads); | |
| return 1; | |
| } | |
| LOG4CXX_INFO_FMT(console, "Benchmarking library only(no writing out):", 0); | |
| bench_log4cxx_single_threaded(iters); | |
| bench_log4cxx_multi_threaded(threads, iters); | |
| bench_log4cxx_multi_threaded_disabled(threads, iters); | |
| LOG4CXX_INFO_FMT(console, "Results for use in spreadsheet:", 0); | |
| for ( uint64_t result : results ) | |
| { | |
| LOG4CXX_INFO_FMT(console, "{}", result ); | |
| } | |
| return 0; | |
| } |