blob: 6671c5722b52cf4b44bcc08628bc4ec11e28a9e4 [file] [log] [blame]
/*
* 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::unique_lock<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::unique_lock<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;
}