Add transform.cpp std::transform test.

This commit is contained in:
Doncho N. Gunchev 2023-01-21 02:04:58 +02:00
parent 8652bbfd99
commit 6811032084
Signed by: dgunchev
GPG key ID: D30FD19F37E002A9
5 changed files with 318 additions and 1 deletions

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# Project specific
/build/
# Prerequisites
*.d

152
CMakeLists.txt Normal file
View file

@ -0,0 +1,152 @@
cmake_minimum_required(VERSION 3.20.0) # RHEL 8
project(benchmarks
VERSION 0.0.0.1 # PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, and PROJECT_VERSION_TWEAK.
DESCRIPTION "Various benchmarks"
HOMEPAGE_URL "https://github.com/gunchev/bench/"
LANGUAGES C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
# set(CMAKE_VERBOSE_MAKEFILE TRUE) # or "cd build; make VERBOSE=1"
# Build types filter
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING
"Choose the type of build, options are: Debug DebugCov RelWithDebInfo Release MinSizeRel." FORCE)
endif()
# SOVERSION is ignored if NO_SONAME property is set.
# "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}"
set(${PROJECT_NAME}_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
message("${PROJECT_NAME} VERSION ${PROJECT_VERSION} SOVERSION is ${${PROJECT_NAME}_SOVERSION}")
# Build shared library by default
if(NOT BUILD_SHARED_LIBS)
option(BUILD_SHARED_LIBS "Create shared libraries" ON)
endif()
# Add link path(s) to RPATH in shared libraries and executables. Saves setting LD_LIBRARY_PATH each time...
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH 1)
# Library directory - lib or lib64?
# rpm: '%{?_cmake_lib_suffix64}' - https://src.fedoraproject.org/rpms/kid3/blob/rawhide/f/kid3.spec
# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/2558
if (NOT LIB_SUFFIX)
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIB_SUFFIX "")
else ()
set(LIB_SUFFIX 64)
endif ()
endif ()
# -fPIC on all targets
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Compiler/linker flags
if(EXISTS "/etc/fedora-release")
set(CMAKE_C_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
else()
set(CMAKE_C_FLAGS "-Wall -Wextra -Werror")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror")
endif()
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
# https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html#Template-Instantiation
set(CMAKE_REQUIRED_QUIET_OLD ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET ON)
macro(CheckAndAddFlag flag)
# We cannot check for -Wno-foo, check for -Wfoo, see https://stackoverflow.com/a/38786117/1136400 for details.
string(REGEX REPLACE "^-Wno-" "-W" checkedFlag ${flag})
string(REGEX REPLACE "[^A-Za-z0-9]" "_" varName ${checkedFlag})
if(NOT C_CXX${varName}_CHECKED)
CHECK_CXX_COMPILER_FLAG(${checkedFlag} CXX_FLAG${varName}_SUPPORTED)
CHECK_C_COMPILER_FLAG(${checkedFlag} C_FLAG${varName}_SUPPORTED)
set(C_CXX${varName}_CHECKED YES CACHE INTERNAL "")
endif()
if(CXX_FLAG${varName}_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
endif()
if(C_FLAG${varName}_SUPPORTED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
endif()
unset(varName)
unset(checkedFlag)
endmacro()
foreach (I IN ITEMS -fmessage-length=0 -fstack-protector-all -pedantic
-Weffc++ -Wsign-compare -Wpointer-sign -Wpedantic -Wformat=2 -Wformat-security
-Wformat-overflow=2 -Wconversion -Wcast-align -Wcast-qual -Wctor-dtor-privacy
-Wdisabled-optimization -Wlogical-op -Wmissing-declarations -Wnoexcept
-Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-promo
-Wstrict-null-sentinel -Wswitch-default -Wundef -Wfloat-equal -Wstrict-overflow)
CheckAndAddFlag(${I})
endforeach ()
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_OLD})
unset(CMAKE_REQUIRED_QUIET_OLD)
# Linker flags
# http://wiki.gentoo.org/wiki/Project:Quality_Assurance/As-needed
# http://www.bnikolic.co.uk/blog/gnu-ld-as-needed.html ,--no-undefined,--no-allow-shlib-undefined
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-as-needed")
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-as-needed")
# Build target flags
# https://fedoraproject.org/wiki/Changes/fno-omit-frame-pointer#Potential_performance_impact
# Debug, CMAKE_C_FLAGS is prepended to CMAKE_C_FLAGS_DEBUG and so on, don't duplicate...
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb3 -DDEBUG -fno-inline -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb3 -DDEBUG -fno-inline -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fsanitize=address")
#set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "")
#set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "")
# Debug with profiling info
set(CMAKE_C_FLAGS_DEBUGCOV "-O0 -ggdb3 -DDEBUG -fno-inline -fprofile-arcs -ftest-coverage -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUGCOV "-O0 -ggdb3 -DDEBUG -fno-inline -fprofile-arcs -ftest-coverage -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fsanitize=address")
# Release with debug info and extra checks, https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#index-fsanitize_003daddress-676
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -ggdb3 -D_FORTIFY_SOURCE=2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -ggdb3 -D_FORTIFY_SOURCE=2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer")
# Release
set(CMAKE_C_FLAGS_RELEASE "-O3 -ggdb3 -D_FORTIFY_SOURCE=2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ggdb3 -D_FORTIFY_SOURCE=2 -DNDEBUG")
# Minimum size release
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -ggdb3 -D_FORTIFY_SOURCE=2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -ggdb3 -D_FORTIFY_SOURCE=2 -DNDEBUG")
# Enable testing?
include(FindPkgConfig)
pkg_check_modules(CPPUNIT cppunit>=1.14.0) # REQUIRED
if(CPPUNIT_FOUND)
enable_testing()
include(CTest)
find_program(CTEST_COVERAGE_COMMAND NAMES gcov)
find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
endif()
find_package(benchmark REQUIRED)
# Threads library
# set(THREADS_PREFER_PTHREAD_FLAG TRUE)
# find_package(Threads REQUIRED)
# Find all third party packages
# find_package(fmt REQUIRED)
# include_directories(${FMT_INCLUDE_DIR})
# pkg_check_modules(HIREDIS REQUIRED hiredis>=1.0.2)
# include_directories(src)
add_executable(transform src/transform.cpp)
target_link_libraries(transform PRIVATE benchmark::benchmark) # fmt::fmt Threads::Threads)
install(TARGETS transform DESTINATION bin)

105
Makefile Normal file
View file

@ -0,0 +1,105 @@
TOP := $(shell dirname "$(abspath $(lastword $(MAKEFILE_LIST)))")
CMAKE_BUILD_PARALLEL_LEVEL := $(shell (nproc; echo 128) | sort -n | head -n 1)
CMAKE := cmake
CCMAKE := ccmake
.PHONY: help
help:
@echo
@echo "| Help"
@echo "+======"
@echo
@echo "Available targets:"
@echo " debug: debug build"
@echo " debugc: debug build with clang"
@echo " debugcov: debug build with coverage"
@echo " debugcovc: debug build with coverage with clang"
@echo " release: release build"
@echo " releasec: release build with clang"
@echo " relwithdebinfo: release build with debug info"
@echo " relwithdebinfoc: release build with debug info and clang"
@echo " minsizerel: minimum size release build (-Os)"
@echo " minsizerelc: minimum size release build (-Os) and clang"
@echo
@echo " distclean: remove all build files"
@echo
.PHONY: build
build:
( test -d "$(BUILD_DIR)" && cd "$(BUILD_DIR)" && $(MAKE) ) || ( mkdir -p "$(BUILD_DIR)" && cd "$(BUILD_DIR)" && $(CMAKE) -D CMAKE_BUILD_TYPE="$(BUILD_TYPE)" "$(TOP)" && $(MAKE) )
.PHONY: buildc
buildc:
( test -d "$(BUILD_DIR)" && cd "$(BUILD_DIR)" && $(MAKE) ) || ( mkdir -p "$(BUILD_DIR)" && cd "$(BUILD_DIR)" && CC=clang CXX=clang++ $(CMAKE) -D CMAKE_BUILD_TYPE="$(BUILD_TYPE)" "$(TOP)" && $(MAKE) )
.PHONY: debug
debug: BUILD_DIR=$(TOP)/build/debug
debug: BUILD_TYPE=Debug
debug: build
.PHONY: debugc
debugc: BUILD_DIR=$(TOP)/build/debugc
debugc: BUILD_TYPE=Debug
debugc: buildc
.PHONY: debugcov
debugcov: BUILD_DIR=$(TOP)/build/debugcov
debugcov: BUILD_TYPE=DebugCov
debugcov: build
.PHONY: debugcovc
debugcovc: BUILD_DIR=$(TOP)/build/debugcovc
debugcovc: BUILD_TYPE=DebugCov
debugcovc: buildc
.PHONY: release
release: BUILD_DIR=$(TOP)/build/release
release: BUILD_TYPE=Release
release: build
.PHONY: releasec
releasec: BUILD_DIR=$(TOP)/build/releasec
releasec: BUILD_TYPE=Release
releasec: buildc
.PHONY: relwithdebinfo
relwithdebinfo: BUILD_DIR=$(TOP)/build/relwithdebinfo
relwithdebinfo: BUILD_TYPE=RelWithDebInfo
relwithdebinfo: build
.PHONY: relwithdebinfoc
relwithdebinfoc: BUILD_DIR=$(TOP)/build/relwithdebinfoc
relwithdebinfoc: BUILD_TYPE=RelWithDebInfo
relwithdebinfoc: buildc
.PHONY: minsizerel
minsizerel: BUILD_DIR=$(TOP)/build/minsizerel
minsizerel: BUILD_TYPE=MinSizeRel
minsizerel: build
.PHONY: minsizerelc
minsizerelc: BUILD_DIR=$(TOP)/build/minsizerelc
minsizerelc: BUILD_TYPE=MinSizeRel
minsizerelc: buildc
.PHONY: all
all:
make debug
make debugcov
make release
make relwithdebinfo
make minsizerel
make debugc
make debugcovc
make releasec
make relwithdebinfoc
make minsizerelc
distclean:
-rm -rf "$(TOP)"/build/
.PHONY: distclean
dc: distclean

View file

@ -1,2 +1,4 @@
# bench
Various C++ benchmarks
Various C++ benchmarks:
- transform.cpp - benchmark std::transform vs loop and custom lowercase and tolower

55
src/transform.cpp Executable file
View file

@ -0,0 +1,55 @@
/*/true;A="$(readlink -f -- "$0")";g++ --std=c++20 -O3 -Wall -Wextra -lbenchmark -o "$A.bin" "$A"&&"$A.bin" "$@";E=$?;rm "$A.bin";exit $E #*/
#include <algorithm>
#include <benchmark/benchmark.h>
#include <string>
#include <sysexits.h>
const char* data = "Hello world, to be or not to be a long string, that is the question!";
static void algorithm_lowercase_my(benchmark::State& state) {
for (auto _ : state) { // Code inside this loop is measured repeatedly
std::string name = data;
std::transform(name.cbegin(), name.cend(), name.begin(), [](char c) noexcept {
return (c >= 'a' && c <= 'z') ? c = c - 'a' + 'A' : c;
});
benchmark::DoNotOptimize(name); // Make sure the variable is not optimized away by compiler
}
}
BENCHMARK(algorithm_lowercase_my); // Register the function as a benchmark
static void loop_lowercase_my(benchmark::State& state) {
for (auto _ : state) { // Code before the loop is not measured
std::string name = data;
for (char& c : name) {
if (c >= 'a' && c <= 'z') {
c = c - 'a' + 'A';
}
}
benchmark::DoNotOptimize(name); // Make sure the variable is not optimized away by compiler
}
}
BENCHMARK(loop_lowercase_my); // Register the function as a benchmark
static void algorithm_lowercase_toupper(benchmark::State& state) {
for (auto _ : state) { // Code inside this loop is measured repeatedly
std::string name = data;
std::transform(name.cbegin(), name.cend(), name.begin(), [](char c) noexcept {
return std::toupper(static_cast<unsigned char>(c));
});
benchmark::DoNotOptimize(name); // Make sure the variable is not optimized away by compiler
}
}
BENCHMARK(algorithm_lowercase_toupper); // Register the function as a benchmark
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
return EX_USAGE;
}
benchmark::RunSpecifiedBenchmarks();
return EX_OK;
}