This is an automated email from the ASF dual-hosted git repository.
swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/master by this push:
new 45a73bdb Google benchmark option (#131)
45a73bdb is described below
commit 45a73bdbaa3fe1d051c74aabe9bb19eb7a04ea96
Author: Stephen Webb <[email protected]>
AuthorDate: Mon Sep 19 13:11:16 2022 +1000
Google benchmark option (#131)
* Provide a cmake option (-D BUILD_BENCHMARK_CHECKS) to use the Google
benchmark library for throughput checks
---
src/test/cpp/CMakeLists.txt | 1 +
src/test/cpp/benchmark/CMakeLists.txt | 64 +++++++++
src/test/cpp/benchmark/benchmark.cpp | 239 ++++++++++++++++++++++++++++++++++
3 files changed, 304 insertions(+)
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index 356f598a..ddeae55b 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -81,6 +81,7 @@ add_subdirectory(spi)
add_subdirectory(varia)
add_subdirectory(xml)
add_subdirectory(throughput)
+add_subdirectory(benchmark)
# Note: we need to include the APR DLLs on our path so that the tests will run.
# The way that CMake sets the environment is that it actually generates a
secondary file,
diff --git a/src/test/cpp/benchmark/CMakeLists.txt
b/src/test/cpp/benchmark/CMakeLists.txt
new file mode 100644
index 00000000..9acae364
--- /dev/null
+++ b/src/test/cpp/benchmark/CMakeLists.txt
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+option(BUILD_BENCHMARK_CHECKS "Build google benchmark checks" OFF)
+
+if( NOT BUILD_BENCHMARK_CHECKS )
+ return()
+endif()
+find_package(benchmark REQUIRED)
+find_package(fmt QUIET)
+if(fmt_FOUND)
+ set(LOG4CXX_HAS_FMT 1)
+else()
+ set(LOG4CXX_HAS_FMT 0)
+endif()
+add_executable(benchmark benchmark.cpp)
+
+# Note: we need to include the APR DLLs on our path so that the tests will run.
+# The way that CMake sets the environment is that it actually generates a
secondary file,
+# CTestTestfile.cmake, which sets the final properties of the test.
+# However, this results in a secondary quirk to the running of the tests:
CMake uses
+# a semicolon to deliminate entries in a list! Since the Windows PATH is
semicolon-delimited
+# as well, CMake uses only the first entry in the list when setting the path.
+# So, we need to do a triple escape on the PATH that we want to set in order
for CMake to
+# properly interpret the PATH
+if( WIN32 )
+ get_filename_component(APR_DLL_DIR "${APR_DLL}" DIRECTORY)
+ get_filename_component(APR_UTIL_DLL_DIR "${APR_UTIL_DLL}" DIRECTORY)
+ get_filename_component(EXPAT_LIB_DIR "${EXPAT_LIBRARY}" DIRECTORY)
+
+
+ set(EXPAT_DLL_DIR "${EXPAT_LIB_DIR}/../bin")
+ set(LOG4CXX_DLL_DIR "$<SHELL_PATH:$<TARGET_FILE_DIR:log4cxx>>;")
+ set(PATH_FOR_TESTS
${CMAKE_PROGRAM_PATH};${APR_DLL_DIR};${APR_UTIL_DLL_DIR};${LOG4CXX_DLL_DIR};${EXPAT_DLL_DIR}\;)
+ list(REMOVE_DUPLICATES PATH_FOR_TESTS)
+ set(NORMAL_PATH $ENV{PATH})
+ set(ESCAPED_PATH "")
+ foreach( ENTRY ${PATH_FOR_TESTS}${NORMAL_PATH} )
+ set(ESCAPED_PATH "${ESCAPED_PATH}${ENTRY}\\\;")
+ endforeach()
+ set_target_properties(benchmark PROPERTIES
+ VS_DEBUGGER_ENVIRONMENT
"LOG4CXX_BENCHMARK_THREAD_COUNT=4\nPATH=${ESCAPED_PATH}"
+ )
+else()
+add_custom_target(run-benchmarks COMMAND benchmark DEPENDS benchmark)
+endif( WIN32 )
+
+target_compile_definitions(benchmark PRIVATE
"LOG4CXX_HAS_FMT=${LOG4CXX_HAS_FMT}" ${LOG4CXX_COMPILE_DEFINITIONS}
${APR_COMPILE_DEFINITIONS} ${APR_UTIL_COMPILE_DEFINITIONS} )
+target_include_directories(benchmark PRIVATE ${CMAKE_CURRENT_LIST_DIR}
$<TARGET_PROPERTY:log4cxx,INCLUDE_DIRECTORIES>)
+target_link_libraries(benchmark PRIVATE log4cxx ${APR_LIBRARIES}
${APR_SYSTEM_LIBS} Threads::Threads fmt::fmt benchmark::benchmark
benchmark::benchmark_main)
diff --git a/src/test/cpp/benchmark/benchmark.cpp
b/src/test/cpp/benchmark/benchmark.cpp
new file mode 100644
index 00000000..8a3f84e5
--- /dev/null
+++ b/src/test/cpp/benchmark/benchmark.cpp
@@ -0,0 +1,239 @@
+#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>
+
+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() {}
+
+ virtual void close() {}
+
+ virtual bool requiresLayout() const
+ {
+ return true;
+ }
+
+ virtual void append(const spi::LoggingEventPtr& event, helpers::Pool& p)
+ {
+ // This gets called whenever there is a valid event for our
appender.
+ }
+
+ virtual void activateOptions(helpers::Pool& /* pool */)
+ {
+ // Given all of our options, do something useful(e.g. open a
file)
+ }
+
+ virtual void setOption(const LogString& option, const LogString& value)
+ {
+ }
+};
+
+IMPLEMENT_LOG4CXX_OBJECT(NullWriterAppender)
+
+#if defined(LOG4CXX_VERSION_MINOR) && 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("")));
+ 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("")));
+ 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("Logging disabled
trace")->MinWarmUpTime(benchmarker::warmUpSeconds());
+BENCHMARK_REGISTER_F(benchmarker, logDisabledTrace)->Name("Logging disabled
trace")->Threads(benchmarker::threadCount());
+
+BENCHMARK_DEFINE_F(benchmarker, logDisabledDebug)(benchmark::State& state)
+{
+ m_logger->setLevel(Level::getInfo());
+ for (auto _ : state)
+ {
+ LOG4CXX_DEBUG(m_logger, LOG4CXX_STR("This is a static string to
see what happens"));
+ }
+}
+BENCHMARK_REGISTER_F(benchmarker, logDisabledDebug)->Name("Logging disabled
debug");
+
+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 info static
string");
+
+BENCHMARK_DEFINE_F(benchmarker, logEnabledDebug)(benchmark::State& state)
+{
+ m_logger->setLevel( Level::getDebug() );
+ for (auto _ : state)
+ {
+ LOG4CXX_DEBUG( m_logger, LOG4CXX_STR("This is a static string
to see what happens"));
+ }
+}
+BENCHMARK_REGISTER_F(benchmarker, logEnabledDebug)->Name("Logging enabled
debug static string");
+
+BENCHMARK_DEFINE_F(benchmarker, logEnabledTrace)(benchmark::State& state)
+{
+ m_logger->setLevel( Level::getTrace() );
+ for (auto _ : state)
+ {
+ LOG4CXX_DEBUG( m_logger, LOG4CXX_STR("This is a static string
to see what happens"));
+ }
+}
+BENCHMARK_REGISTER_F(benchmarker, logEnabledTrace)->Name("Logging enabled
trace 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 m_logger: 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());
+#endif
+
+BENCHMARK_DEFINE_F(benchmarker, logIntValueStream)(benchmark::State& state)
+{
+ int x = 0;
+ for (auto _ : state)
+ {
+ LOG4CXX_INFO( m_logger, "Hello m_logger: 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());
+
+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();
+