blob: e6508481185d7403a7f089bf3d89867850c75f5d [file] [log] [blame]
#include <log4cxx/logger.h>
#include <log4cxx/patternlayout.h>
#include <log4cxx/appenderskeleton.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/asyncappender.h>
#include <fmt/format.h>
#include <benchmark/benchmark.h>
#include <thread>
#include <cstdlib>
#include <iomanip>
using namespace log4cxx;
class NullWriterAppender : public AppenderSkeleton
{
public:
DECLARE_LOG4CXX_OBJECT(NullWriterAppender)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(NullWriterAppender)
LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
END_LOG4CXX_CAST_MAP()
NullWriterAppender() {}
void close() override {}
bool requiresLayout() const override
{
return true;
}
void append(const spi::LoggingEventPtr& event, helpers::Pool& p) override
{
// This gets called whenever there is a valid event for our appender.
}
void activateOptions(helpers::Pool& /* pool */) override
{
// Given all of our options, do something useful(e.g. open a file)
}
void setOption(const LogString& option, const LogString& value) override
{
}
};
IMPLEMENT_LOG4CXX_OBJECT(NullWriterAppender)
#if defined(LOG4CXX_VERSION_MINOR) && (0 < LOG4CXX_VERSION_MAJOR || 11 < LOG4CXX_VERSION_MINOR)
LOG4CXX_PTR_DEF(NullWriterAppender);
#else
#define LOG4CXX_HAS_FMT 0
template class log4cxx::helpers::ObjectPtrT<NullWriterAppender>;
typedef log4cxx::helpers::ObjectPtrT<NullWriterAppender> NullWriterAppenderPtr;
#endif
class benchmarker : public ::benchmark::Fixture
{
public:
LoggerPtr m_logger;
void SetupLogger()
{
m_logger = Logger::getLogger(LOG4CXX_STR("bench_logger"));
m_logger->removeAllAppenders();
m_logger->setAdditivity(false);
m_logger->setLevel(Level::getInfo());
PatternLayoutPtr pattern(new PatternLayout);
pattern->setConversionPattern(LOG4CXX_STR("%m%n"));
NullWriterAppenderPtr nullWriter(new NullWriterAppender);
nullWriter->setName(LOG4CXX_STR("NullWriterAppender"));
nullWriter->setLayout(pattern);
m_logger->addAppender(nullWriter);
}
void SetUp(const ::benchmark::State& state)
{
std::setlocale( LC_ALL, "" ); /* Set locale for C functions */
std::locale::global(std::locale("")); /* set locale for C++ functions */
SetupLogger();
}
void TearDown(const ::benchmark::State& state)
{
}
static int threadCount()
{
auto threadCount = helpers::StringHelper::toInt
(helpers::OptionConverter::getSystemProperty
(LOG4CXX_STR("LOG4CXX_BENCHMARK_THREAD_COUNT"), LOG4CXX_STR("0")));
if (threadCount <= 0)
threadCount = std::thread::hardware_concurrency() - 2;
return threadCount;
}
static double warmUpSeconds()
{
auto milliseconds = helpers::StringHelper::toInt
(helpers::OptionConverter::getSystemProperty
(LOG4CXX_STR("LOG4CXX_BENCHMARK_WARM_UP_MILLISECONDS"), LOG4CXX_STR("0")));
if (milliseconds <= 0)
milliseconds = 100;
return milliseconds / 1000;
}
};
BENCHMARK_DEFINE_F(benchmarker, logDisabledTrace)(benchmark::State& state)
{
m_logger->setLevel(Level::getDebug());
for (auto _ : state)
{
LOG4CXX_TRACE( m_logger, LOG4CXX_STR("This is a static string to see what happens"));
}
}
BENCHMARK_REGISTER_F(benchmarker, logDisabledTrace)->Name("Testing disabled logging request")->MinWarmUpTime(benchmarker::warmUpSeconds());
BENCHMARK_REGISTER_F(benchmarker, logDisabledTrace)->Name("Testing disabled logging request")->Threads(benchmarker::threadCount());
BENCHMARK_DEFINE_F(benchmarker, logStaticString)(benchmark::State& state)
{
m_logger->setLevel(Level::getInfo());
for (auto _ : state)
{
LOG4CXX_INFO( m_logger, LOG4CXX_STR("This is a static string to see what happens"));
}
}
BENCHMARK_REGISTER_F(benchmarker, logStaticString)->Name("Logging static string");
#if LOG4CXX_HAS_FMT
BENCHMARK_DEFINE_F(benchmarker, logStaticStringFMT)(benchmark::State& state)
{
for (auto _ : state)
{
LOG4CXX_INFO_FMT(m_logger, "This is a static string to see what happens");
}
}
BENCHMARK_REGISTER_F(benchmarker, logStaticStringFMT)->Name("Logging static string with FMT");
BENCHMARK_DEFINE_F(benchmarker, logIntValueFMT)(benchmark::State& state)
{
int x = 0;
for (auto _ : state)
{
LOG4CXX_INFO_FMT( m_logger, "Hello: msg number {}", ++x);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntValueFMT)->Name("Logging int value with FMT");
BENCHMARK_REGISTER_F(benchmarker, logIntValueFMT)->Name("Logging int value with FMT")->Threads(benchmarker::threadCount());
BENCHMARK_DEFINE_F(benchmarker, logIntPlusFloatValueFMT)(benchmark::State& state)
{
int x = 0;
for (auto _ : state)
{
auto f = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
LOG4CXX_INFO_FMT( m_logger, "Hello: msg number {} pseudo-random float {:.3f}", ++x, f);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntPlusFloatValueFMT)->Name("Logging int+float with FMT");
BENCHMARK_REGISTER_F(benchmarker, logIntPlusFloatValueFMT)->Name("Logging int+float with FMT")->Threads(benchmarker::threadCount());
#endif
BENCHMARK_DEFINE_F(benchmarker, logIntValueStream)(benchmark::State& state)
{
int x = 0;
for (auto _ : state)
{
LOG4CXX_INFO( m_logger, "Hello: msg number " << ++x);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntValueStream)->Name("Logging int value with std::ostream");
BENCHMARK_REGISTER_F(benchmarker, logIntValueStream)->Name("Logging int value with std::ostream")->Threads(benchmarker::threadCount());
BENCHMARK_DEFINE_F(benchmarker, logIntPlusFloatStream)(benchmark::State& state)
{
int x = 0;
for (auto _ : state)
{
auto f = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
LOG4CXX_INFO( m_logger, "Hello: msg number " << ++x
<< " pseudo-random float " << std::setprecision(3) << std::fixed << f);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntPlusFloatStream)->Name("Logging int+float with std::ostream");
BENCHMARK_REGISTER_F(benchmarker, logIntPlusFloatStream)->Name("Logging int+float with std::ostream")->Threads(benchmarker::threadCount());
template <class ...Args>
void logWithConversionPattern(benchmark::State& state, Args&&... args)
{
auto args_tuple = std::make_tuple(std::move(args)...);
LogString conversionPattern = std::get<0>(args_tuple);
PatternLayoutPtr pattern(new PatternLayout);
pattern->setConversionPattern( conversionPattern );
auto logger = Logger::getLogger( LOG4CXX_STR("bench_logger") );
logger->getAppender(LOG4CXX_STR("NullWriterAppender"))->setLayout(pattern);
int x = 0;
for (auto _ : state)
{
LOG4CXX_INFO( logger, LOG4CXX_STR("Hello m_logger: msg number ") << ++x);
}
}
BENCHMARK_CAPTURE(logWithConversionPattern, NoFormat, LOG4CXX_STR("%m%n"))->Name("NoFormat pattern: %m%n");
BENCHMARK_CAPTURE(logWithConversionPattern, DateOnly, LOG4CXX_STR("[%d] %m%n"))->Name("DateOnly pattern: [%d] %m%n");
BENCHMARK_CAPTURE(logWithConversionPattern, DateClassLevel, LOG4CXX_STR("[%d] [%c] [%p] %m%n"))->Name("DateClassLevel pattern: [%d] [%c] [%p] %m%n");
static void SetAsyncAppender(const benchmark::State& state)
{
LoggerPtr logger = Logger::getLogger( LOG4CXX_STR("bench_logger") );
logger->removeAllAppenders();
logger->setAdditivity( false );
logger->setLevel( Level::getInfo() );
PatternLayoutPtr pattern(new PatternLayout);
pattern->setConversionPattern(LOG4CXX_STR("%m%n"));
NullWriterAppenderPtr nullWriter(new NullWriterAppender);
nullWriter->setLayout( pattern );
AsyncAppenderPtr asyncAppender = AsyncAppenderPtr(new AsyncAppender());
asyncAppender->addAppender(nullWriter);
asyncAppender->setBufferSize(5);
helpers::Pool p;
asyncAppender->activateOptions(p);
logger->addAppender(asyncAppender);
}
BENCHMARK_REGISTER_F(benchmarker, logIntValueStream)->Name("Logging int value with std::ostream to AsyncAppender")->Setup(SetAsyncAppender);
BENCHMARK_REGISTER_F(benchmarker, logIntValueStream)->Name("Logging int value with std::ostream to AsyncAppender")->Threads(benchmarker::threadCount());
BENCHMARK_MAIN();