chore: import upstream snapshot with attribution
bazel / bazel.ubuntu-latest (push) Failing after 1s
build-and-test-perfcounters / ubuntu-latest.Debug (push) Failing after 0s
build-and-test-perfcounters / ubuntu-latest.Release (push) Failing after 1s
doxygen / Build HTML documentation (push) Failing after 1s
python + Bazel pre-commit checks / pre-commit (push) Failing after 1s
sanitizer / tsan.Debug (push) Failing after 1s
sanitizer / ubsan.Debug (push) Failing after 0s
sanitizer / ubsan.RelWithDebInfo (push) Failing after 1s
build-and-test-min-cmake / ubuntu-latest.min-cmake (push) Failing after 1s
clang-format-lint / check-clang-format (push) Failing after 1s
sanitizer / asan.Debug (push) Failing after 1s
sanitizer / msan.RelWithDebInfo (push) Failing after 1s
clang-tidy / run-clang-tidy (push) Failing after 1s
sanitizer / msan.Debug (push) Failing after 1s
sanitizer / asan.RelWithDebInfo (push) Failing after 0s
sanitizer / tsan.RelWithDebInfo (push) Failing after 0s
test-bindings / Test Rust bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.10 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.11 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.12 bindings on ubuntu-latest (push) Failing after 1s
test-bindings / Test Python 3.13 bindings on ubuntu-latest (push) Failing after 0s
build-and-test / macos-latest.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.clang++ (push) Has been cancelled
bazel / bazel.macos-latest (push) Has been cancelled
bazel / bazel.windows-latest (push) Has been cancelled
build-and-test-min-cmake / macos-latest.min-cmake (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.g++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.g++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2025.Debug.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2022.Release.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Release.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Release.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2025.Release.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.UCRT64 (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2022.Debug.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Debug.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Debug.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Release.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.UCRT64 (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on macos-latest (push) Has been cancelled
build-and-test / windows-latest.Release.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.CLANG64 (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Rust bindings on macos-latest (push) Has been cancelled
test-bindings / Test Rust bindings on windows-latest (push) Has been cancelled
bazel / bazel.ubuntu-latest (push) Failing after 1s
build-and-test-perfcounters / ubuntu-latest.Debug (push) Failing after 0s
build-and-test-perfcounters / ubuntu-latest.Release (push) Failing after 1s
doxygen / Build HTML documentation (push) Failing after 1s
python + Bazel pre-commit checks / pre-commit (push) Failing after 1s
sanitizer / tsan.Debug (push) Failing after 1s
sanitizer / ubsan.Debug (push) Failing after 0s
sanitizer / ubsan.RelWithDebInfo (push) Failing after 1s
build-and-test-min-cmake / ubuntu-latest.min-cmake (push) Failing after 1s
clang-format-lint / check-clang-format (push) Failing after 1s
sanitizer / asan.Debug (push) Failing after 1s
sanitizer / msan.RelWithDebInfo (push) Failing after 1s
clang-tidy / run-clang-tidy (push) Failing after 1s
sanitizer / msan.Debug (push) Failing after 1s
sanitizer / asan.RelWithDebInfo (push) Failing after 0s
sanitizer / tsan.RelWithDebInfo (push) Failing after 0s
test-bindings / Test Rust bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.10 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.11 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.12 bindings on ubuntu-latest (push) Failing after 1s
test-bindings / Test Python 3.13 bindings on ubuntu-latest (push) Failing after 0s
build-and-test / macos-latest.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.clang++ (push) Has been cancelled
bazel / bazel.macos-latest (push) Has been cancelled
bazel / bazel.windows-latest (push) Has been cancelled
build-and-test-min-cmake / macos-latest.min-cmake (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.g++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.g++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2025.Debug.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2022.Release.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Release.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Release.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2025.Release.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.UCRT64 (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2022.Debug.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Debug.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Debug.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Release.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.UCRT64 (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on macos-latest (push) Has been cancelled
build-and-test / windows-latest.Release.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.CLANG64 (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Rust bindings on macos-latest (push) Has been cancelled
test-bindings / Test Rust bindings on windows-latest (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
set(CLANG_SUPPORTED_VERSION "5.0.0")
|
||||
set(GCC_SUPPORTED_VERSION "5.5.0")
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL ${CLANG_SUPPORTED_VERSION})
|
||||
message (WARNING
|
||||
"Unsupported Clang version " ${CMAKE_CXX_COMPILER_VERSION}
|
||||
". Expected is " ${CLANG_SUPPORTED_VERSION}
|
||||
". Assembly tests may be broken.")
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL ${GCC_SUPPORTED_VERSION})
|
||||
message (WARNING
|
||||
"Unsupported GCC version " ${CMAKE_CXX_COMPILER_VERSION}
|
||||
". Expected is " ${GCC_SUPPORTED_VERSION}
|
||||
". Assembly tests may be broken.")
|
||||
endif()
|
||||
else()
|
||||
message (WARNING "Unsupported compiler. Assembly tests may be broken.")
|
||||
endif()
|
||||
|
||||
include(split_list)
|
||||
|
||||
set(ASM_TEST_FLAGS "")
|
||||
check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG)
|
||||
if (BENCHMARK_HAS_O3_FLAG)
|
||||
list(APPEND ASM_TEST_FLAGS -O3)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(-g0 BENCHMARK_HAS_G0_FLAG)
|
||||
if (BENCHMARK_HAS_G0_FLAG)
|
||||
list(APPEND ASM_TEST_FLAGS -g0)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(-fno-stack-protector BENCHMARK_HAS_FNO_STACK_PROTECTOR_FLAG)
|
||||
if (BENCHMARK_HAS_FNO_STACK_PROTECTOR_FLAG)
|
||||
list(APPEND ASM_TEST_FLAGS -fno-stack-protector)
|
||||
endif()
|
||||
|
||||
split_list(ASM_TEST_FLAGS)
|
||||
string(TOUPPER "${CMAKE_CXX_COMPILER_ID}" ASM_TEST_COMPILER)
|
||||
|
||||
macro(add_filecheck_test name)
|
||||
cmake_parse_arguments(ARG "" "" "CHECK_PREFIXES" ${ARGV})
|
||||
add_library(${name} OBJECT ${name}.cc)
|
||||
target_link_libraries(${name} PRIVATE benchmark::benchmark)
|
||||
set_target_properties(${name} PROPERTIES COMPILE_FLAGS "-S ${ASM_TEST_FLAGS}")
|
||||
set(ASM_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}.s")
|
||||
add_custom_target(copy_${name} ALL
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/tools/strip_asm.py
|
||||
$<TARGET_OBJECTS:${name}>
|
||||
${ASM_OUTPUT_FILE}
|
||||
BYPRODUCTS ${ASM_OUTPUT_FILE})
|
||||
add_dependencies(copy_${name} ${name})
|
||||
if (NOT ARG_CHECK_PREFIXES)
|
||||
set(ARG_CHECK_PREFIXES "CHECK")
|
||||
endif()
|
||||
foreach(prefix ${ARG_CHECK_PREFIXES})
|
||||
add_test(NAME run_${name}_${prefix}
|
||||
COMMAND
|
||||
${LLVM_FILECHECK_EXE} ${name}.cc
|
||||
--input-file=${ASM_OUTPUT_FILE}
|
||||
--check-prefixes=CHECK,CHECK-${ASM_TEST_COMPILER}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
|
||||
platform(
|
||||
name = "windows",
|
||||
constraint_values = [
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
)
|
||||
|
||||
TEST_COPTS = [
|
||||
"-pedantic",
|
||||
"-pedantic-errors",
|
||||
"-std=c++17",
|
||||
"-Wall",
|
||||
"-Wconversion",
|
||||
"-Wextra",
|
||||
"-Wshadow",
|
||||
# "-Wshorten-64-to-32",
|
||||
"-Wfloat-equal",
|
||||
"-fstrict-aliasing",
|
||||
## assert() are used a lot in tests upstream, which may be optimised out leading to
|
||||
## unused-variable warning.
|
||||
"-Wno-unused-variable",
|
||||
"-Werror=old-style-cast",
|
||||
]
|
||||
|
||||
TEST_MSVC_OPTS = [
|
||||
"/std:c++17",
|
||||
]
|
||||
|
||||
# Some of the issues with DoNotOptimize only occur when optimization is enabled
|
||||
PER_SRC_COPTS = {
|
||||
"donotoptimize_test.cc": ["-O3"],
|
||||
}
|
||||
|
||||
TEST_ARGS = ["--benchmark_min_time=0.01s"]
|
||||
|
||||
PER_SRC_TEST_ARGS = {
|
||||
"user_counters_tabular_test.cc": [
|
||||
"--benchmark_counters_tabular=true",
|
||||
"--benchmark_min_time=0.2s",
|
||||
],
|
||||
"repetitions_test.cc": [" --benchmark_repetitions=3"],
|
||||
"spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"],
|
||||
"spec_arg_verbosity_test.cc": ["--v=42"],
|
||||
"complexity_test.cc": ["--benchmark_min_time=1000000x"],
|
||||
"user_counters_test.cc": ["--benchmark_min_time=0.2s"],
|
||||
"user_counters_threads_test.cc": ["--benchmark_min_time=0.2s"],
|
||||
}
|
||||
|
||||
cc_library(
|
||||
name = "output_test_helper",
|
||||
testonly = 1,
|
||||
srcs = ["output_test_helper.cc"],
|
||||
hdrs = ["output_test.h"],
|
||||
copts = select({
|
||||
"//:windows": TEST_MSVC_OPTS,
|
||||
"//conditions:default": TEST_COPTS,
|
||||
}),
|
||||
deps = [
|
||||
"//:benchmark",
|
||||
"//:benchmark_internal_headers",
|
||||
],
|
||||
)
|
||||
|
||||
# Tests that use gtest. These rely on `gtest_main`.
|
||||
[
|
||||
cc_test(
|
||||
name = test_src[:-len(".cc")],
|
||||
size = "small",
|
||||
srcs = [test_src],
|
||||
copts = select({
|
||||
"//:windows": TEST_MSVC_OPTS,
|
||||
"//conditions:default": TEST_COPTS,
|
||||
}) + PER_SRC_COPTS.get(test_src, []),
|
||||
deps = [
|
||||
"//:benchmark",
|
||||
"//:benchmark_internal_headers",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
for test_src in glob(["*_gtest.cc"])
|
||||
]
|
||||
|
||||
# Tests that do not use gtest. These have their own `main` defined.
|
||||
[
|
||||
cc_test(
|
||||
name = test_src[:-len(".cc")],
|
||||
size = "small",
|
||||
srcs = [test_src],
|
||||
args = TEST_ARGS + PER_SRC_TEST_ARGS.get(test_src, []),
|
||||
copts = select({
|
||||
"//:windows": TEST_MSVC_OPTS,
|
||||
"//conditions:default": TEST_COPTS,
|
||||
}) + PER_SRC_COPTS.get(test_src, []),
|
||||
deps = [
|
||||
":output_test_helper",
|
||||
"//:benchmark",
|
||||
"//:benchmark_internal_headers",
|
||||
],
|
||||
# FIXME: Add support for assembly tests to bazel.
|
||||
# See Issue #556
|
||||
# https://github.com/google/benchmark/issues/556
|
||||
)
|
||||
for test_src in glob(
|
||||
["*_test.cc"],
|
||||
exclude = [
|
||||
"*_assembly_test.cc",
|
||||
"cxx11_test.cc",
|
||||
"link_main_test.cc",
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
cc_test(
|
||||
name = "cxx11_test",
|
||||
size = "small",
|
||||
srcs = ["cxx11_test.cc"],
|
||||
copts = TEST_COPTS + ["-std=c++11"],
|
||||
target_compatible_with = select({
|
||||
"//:windows": ["@platforms//:incompatible"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
deps = [
|
||||
":output_test_helper",
|
||||
"//:benchmark_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "link_main_test",
|
||||
size = "small",
|
||||
srcs = ["link_main_test.cc"],
|
||||
copts = select({
|
||||
"//:windows": TEST_MSVC_OPTS,
|
||||
"//conditions:default": TEST_COPTS,
|
||||
}),
|
||||
deps = ["//:benchmark_main"],
|
||||
)
|
||||
@@ -0,0 +1,341 @@
|
||||
#Enable the tests
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
add_cxx_compiler_flag(-Wno-unused-variable)
|
||||
|
||||
# NOTE: Some tests use `<cassert>` to perform the test. Therefore we must
|
||||
# strip -DNDEBUG from the default CMake flags in DEBUG mode.
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" )
|
||||
add_definitions( -UNDEBUG )
|
||||
add_definitions(-DTEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS)
|
||||
# Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines.
|
||||
foreach (flags_var_to_scrub
|
||||
CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS_MINSIZEREL)
|
||||
string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " "
|
||||
"${flags_var_to_scrub}" "${${flags_var_to_scrub}}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
add_definitions(-DBENCHMARK_STATIC_DEFINE)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG)
|
||||
set(BENCHMARK_O3_FLAG "")
|
||||
if (BENCHMARK_HAS_O3_FLAG)
|
||||
set(BENCHMARK_O3_FLAG "-O3")
|
||||
endif()
|
||||
|
||||
# NOTE: These flags must be added after find_package(Threads REQUIRED) otherwise
|
||||
# they will break the configuration check.
|
||||
if (DEFINED BENCHMARK_CXX_LINKER_FLAGS)
|
||||
list(APPEND CMAKE_EXE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
add_library(output_test_helper STATIC output_test_helper.cc output_test.h)
|
||||
target_link_libraries(output_test_helper PRIVATE benchmark::benchmark)
|
||||
|
||||
macro(compile_benchmark_test name)
|
||||
add_executable(${name} "${name}.cc")
|
||||
target_link_libraries(${name} benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "NVHPC")
|
||||
target_compile_options( ${name} PRIVATE --diag_suppress partial_override )
|
||||
endif()
|
||||
endmacro(compile_benchmark_test)
|
||||
|
||||
macro(compile_benchmark_test_with_main name)
|
||||
add_executable(${name} "${name}.cc")
|
||||
target_link_libraries(${name} benchmark::benchmark_main)
|
||||
endmacro(compile_benchmark_test_with_main)
|
||||
|
||||
macro(compile_output_test name)
|
||||
add_executable(${name} "${name}.cc" output_test.h)
|
||||
target_link_libraries(${name} output_test_helper benchmark::benchmark_main
|
||||
${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endmacro(compile_output_test)
|
||||
|
||||
macro(benchmark_add_test)
|
||||
add_test(${ARGV})
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
cmake_parse_arguments(TEST "" "NAME" "" ${ARGN})
|
||||
set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:benchmark::benchmark>")
|
||||
endif()
|
||||
endmacro(benchmark_add_test)
|
||||
|
||||
# Demonstration executable
|
||||
|
||||
compile_benchmark_test_with_main(cxx11_test)
|
||||
if(DEFINED MSVC)
|
||||
# MSVC does not really support C++11.
|
||||
set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 14)
|
||||
else()
|
||||
set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 11)
|
||||
endif()
|
||||
set_property(TARGET cxx11_test PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
set_property(TARGET cxx11_test PROPERTY CXX_EXTENSIONS OFF)
|
||||
benchmark_add_test(NAME cxx11_test COMMAND cxx11_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(benchmark_test)
|
||||
benchmark_add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(spec_arg_test)
|
||||
benchmark_add_test(NAME spec_arg COMMAND spec_arg_test --benchmark_filter=BM_NotChosen)
|
||||
|
||||
compile_benchmark_test(spec_arg_verbosity_test)
|
||||
benchmark_add_test(NAME spec_arg_verbosity COMMAND spec_arg_verbosity_test --v=42)
|
||||
|
||||
compile_benchmark_test(benchmark_setup_teardown_test)
|
||||
benchmark_add_test(NAME benchmark_setup_teardown COMMAND benchmark_setup_teardown_test)
|
||||
|
||||
compile_benchmark_test(filter_test)
|
||||
macro(add_filter_test name filter expect)
|
||||
benchmark_add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01s --benchmark_filter=${filter} ${expect})
|
||||
benchmark_add_test(NAME ${name}_list_only COMMAND filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect})
|
||||
endmacro(add_filter_test)
|
||||
|
||||
compile_benchmark_test(benchmark_min_time_flag_time_test)
|
||||
benchmark_add_test(NAME min_time_flag_time COMMAND benchmark_min_time_flag_time_test)
|
||||
|
||||
compile_benchmark_test(benchmark_min_time_flag_iters_test)
|
||||
benchmark_add_test(NAME min_time_flag_iters COMMAND benchmark_min_time_flag_iters_test)
|
||||
|
||||
add_filter_test(filter_simple "Foo" 3)
|
||||
add_filter_test(filter_simple_negative "-Foo" 2)
|
||||
add_filter_test(filter_suffix "BM_.*" 4)
|
||||
add_filter_test(filter_suffix_negative "-BM_.*" 1)
|
||||
add_filter_test(filter_regex_all ".*" 5)
|
||||
add_filter_test(filter_regex_all_negative "-.*" 0)
|
||||
add_filter_test(filter_regex_blank "" 5)
|
||||
add_filter_test(filter_regex_blank_negative "-" 0)
|
||||
add_filter_test(filter_regex_none "monkey" 0)
|
||||
add_filter_test(filter_regex_none_negative "-monkey" 5)
|
||||
add_filter_test(filter_regex_wildcard ".*Foo.*" 3)
|
||||
add_filter_test(filter_regex_wildcard_negative "-.*Foo.*" 2)
|
||||
add_filter_test(filter_regex_begin "^BM_.*" 4)
|
||||
add_filter_test(filter_regex_begin_negative "-^BM_.*" 1)
|
||||
add_filter_test(filter_regex_begin2 "^N" 1)
|
||||
add_filter_test(filter_regex_begin2_negative "-^N" 4)
|
||||
add_filter_test(filter_regex_end ".*Ba$" 1)
|
||||
add_filter_test(filter_regex_end_negative "-.*Ba$" 4)
|
||||
|
||||
compile_benchmark_test(options_test)
|
||||
benchmark_add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(basic_test)
|
||||
benchmark_add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(repetitions_test)
|
||||
benchmark_add_test(NAME repetitions_benchmark COMMAND repetitions_test --benchmark_min_time=0.01s --benchmark_repetitions=3)
|
||||
|
||||
compile_benchmark_test(diagnostics_test)
|
||||
benchmark_add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(skip_with_error_test)
|
||||
benchmark_add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(donotoptimize_test)
|
||||
# Enable errors for deprecated deprecations (DoNotOptimize(Tp const& value)).
|
||||
check_cxx_compiler_flag(-Werror=deprecated-declarations BENCHMARK_HAS_DEPRECATED_DECLARATIONS_FLAG)
|
||||
if (BENCHMARK_HAS_DEPRECATED_DECLARATIONS_FLAG)
|
||||
target_compile_options (donotoptimize_test PRIVATE "-Werror=deprecated-declarations")
|
||||
endif()
|
||||
# Some of the issues with DoNotOptimize only occur when optimization is enabled
|
||||
check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG)
|
||||
if (BENCHMARK_HAS_O3_FLAG)
|
||||
set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3")
|
||||
endif()
|
||||
benchmark_add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(fixture_test)
|
||||
benchmark_add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(register_benchmark_test)
|
||||
benchmark_add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(map_test)
|
||||
benchmark_add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(multiple_ranges_test)
|
||||
benchmark_add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(args_product_test)
|
||||
benchmark_add_test(NAME args_product_test COMMAND args_product_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test_with_main(link_main_test)
|
||||
benchmark_add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(reporter_output_test)
|
||||
benchmark_add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(templated_fixture_test)
|
||||
benchmark_add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(templated_fixture_method_test)
|
||||
benchmark_add_test(NAME templated_fixture_method_test COMMAND templated_fixture_method_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(user_counters_test)
|
||||
benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.2s)
|
||||
|
||||
compile_output_test(user_counters_threads_test)
|
||||
benchmark_add_test(NAME user_counters_threads_test COMMAND user_counters_threads_test --benchmark_min_time=0.2s)
|
||||
|
||||
compile_output_test(perf_counters_test)
|
||||
benchmark_add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS)
|
||||
|
||||
compile_output_test(internal_threading_test)
|
||||
benchmark_add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(manual_threading_test)
|
||||
benchmark_add_test(NAME manual_threading_test COMMAND manual_threading_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(report_aggregates_only_test)
|
||||
benchmark_add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(display_aggregates_only_test)
|
||||
benchmark_add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(user_counters_tabular_test)
|
||||
benchmark_add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.2s)
|
||||
|
||||
compile_output_test(user_counters_thousands_test)
|
||||
benchmark_add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(memory_manager_test)
|
||||
benchmark_add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_output_test(profiler_manager_test)
|
||||
benchmark_add_test(NAME profiler_manager_test COMMAND profiler_manager_test --benchmark_min_time=0.01s)
|
||||
|
||||
compile_benchmark_test(profiler_manager_iterations_test)
|
||||
benchmark_add_test(NAME profiler_manager_iterations COMMAND profiler_manager_iterations_test)
|
||||
|
||||
compile_output_test(complexity_test)
|
||||
benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=1000000x)
|
||||
|
||||
compile_output_test(locale_impermeability_test)
|
||||
benchmark_add_test(NAME locale_impermeability_test COMMAND locale_impermeability_test)
|
||||
|
||||
compile_output_test(scoped_pause_test)
|
||||
benchmark_add_test(NAME scoped_pause_test COMMAND scoped_pause_test)
|
||||
|
||||
###############################################################################
|
||||
# GoogleTest Unit Tests
|
||||
###############################################################################
|
||||
|
||||
if (BENCHMARK_ENABLE_GTEST_TESTS)
|
||||
macro(compile_gtest name)
|
||||
add_executable(${name} "${name}.cc")
|
||||
target_link_libraries(${name} benchmark::benchmark
|
||||
gmock_main ${CMAKE_THREAD_LIBS_INIT})
|
||||
endmacro(compile_gtest)
|
||||
|
||||
macro(add_gtest name)
|
||||
compile_gtest(${name})
|
||||
benchmark_add_test(NAME ${name} COMMAND ${name})
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
set_tests_properties(${name} PROPERTIES
|
||||
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:benchmark::benchmark>;PATH=path_list_prepend:$<TARGET_FILE_DIR:gmock_main>"
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
add_gtest(benchmark_gtest)
|
||||
add_gtest(benchmark_name_gtest)
|
||||
add_gtest(benchmark_random_interleaving_gtest)
|
||||
add_gtest(commandlineflags_gtest)
|
||||
add_gtest(statistics_gtest)
|
||||
add_gtest(string_util_gtest)
|
||||
add_gtest(perf_counters_gtest)
|
||||
add_gtest(time_unit_gtest)
|
||||
add_gtest(min_time_parse_gtest)
|
||||
add_gtest(profiler_manager_gtest)
|
||||
add_gtest(benchmark_setup_teardown_cb_types_gtest)
|
||||
add_gtest(memory_results_gtest)
|
||||
endif(BENCHMARK_ENABLE_GTEST_TESTS)
|
||||
|
||||
###############################################################################
|
||||
# Assembly Unit Tests
|
||||
###############################################################################
|
||||
|
||||
if (BENCHMARK_ENABLE_ASSEMBLY_TESTS)
|
||||
if (NOT LLVM_FILECHECK_EXE)
|
||||
message(FATAL_ERROR "LLVM FileCheck is required when including this file")
|
||||
endif()
|
||||
include(AssemblyTests.cmake)
|
||||
add_filecheck_test(donotoptimize_assembly_test)
|
||||
add_filecheck_test(state_assembly_test)
|
||||
add_filecheck_test(clobber_memory_assembly_test)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Code Coverage Configuration
|
||||
###############################################################################
|
||||
|
||||
# Add the coverage command(s)
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
|
||||
endif()
|
||||
if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage")
|
||||
find_program(GCOV gcov)
|
||||
find_program(LCOV lcov)
|
||||
find_program(GENHTML genhtml)
|
||||
find_program(CTEST ctest)
|
||||
if (GCOV AND LCOV AND GENHTML AND CTEST AND HAVE_CXX_FLAG_COVERAGE)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/lcov/index.html
|
||||
COMMAND ${LCOV} -q -z -d .
|
||||
COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o before.lcov -i
|
||||
COMMAND ${CTEST} --force-new-ctest-process
|
||||
COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o after.lcov
|
||||
COMMAND ${LCOV} -q -a before.lcov -a after.lcov --output-file final.lcov
|
||||
COMMAND ${LCOV} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/test/*'" -o final.lcov
|
||||
COMMAND ${GENHTML} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_BINARY_DIR}" -t benchmark
|
||||
DEPENDS filter_test benchmark_test options_test basic_test fixture_test complexity_test
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
COMMENT "Running LCOV"
|
||||
)
|
||||
add_custom_target(coverage
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/lcov/index.html
|
||||
COMMENT "LCOV report at lcov/index.html"
|
||||
)
|
||||
message(STATUS "Coverage command added")
|
||||
else()
|
||||
if (HAVE_CXX_FLAG_COVERAGE)
|
||||
set(CXX_FLAG_COVERAGE_MESSAGE supported)
|
||||
else()
|
||||
set(CXX_FLAG_COVERAGE_MESSAGE unavailable)
|
||||
endif()
|
||||
message(WARNING
|
||||
"Coverage not available:\n"
|
||||
" gcov: ${GCOV}\n"
|
||||
" lcov: ${LCOV}\n"
|
||||
" genhtml: ${GENHTML}\n"
|
||||
" ctest: ${CTEST}\n"
|
||||
" --coverage flag: ${CXX_FLAG_COVERAGE_MESSAGE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (BENCHMARK_ENABLE_RUST_BINDINGS)
|
||||
find_program(CARGO_EXECUTABLE cargo REQUIRED)
|
||||
add_custom_target(build_rust_bindings ALL
|
||||
COMMAND ${CARGO_EXECUTABLE} build --tests
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bindings/rust
|
||||
COMMENT "Building Rust bindings and tests"
|
||||
)
|
||||
add_test(NAME rust_bindings_tests
|
||||
COMMAND ${CARGO_EXECUTABLE} test
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bindings/rust
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
class ArgsProductFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
ArgsProductFixture()
|
||||
: expectedValues({{0, 100, 2000, 30000},
|
||||
{1, 15, 3, 8},
|
||||
{1, 15, 3, 9},
|
||||
{1, 15, 7, 8},
|
||||
{1, 15, 7, 9},
|
||||
{1, 15, 10, 8},
|
||||
{1, 15, 10, 9},
|
||||
{2, 15, 3, 8},
|
||||
{2, 15, 3, 9},
|
||||
{2, 15, 7, 8},
|
||||
{2, 15, 7, 9},
|
||||
{2, 15, 10, 8},
|
||||
{2, 15, 10, 9},
|
||||
{4, 5, 6, 11}}) {}
|
||||
|
||||
void SetUp(const ::benchmark::State& state) override {
|
||||
std::vector<int64_t> ranges = {state.range(0), state.range(1),
|
||||
state.range(2), state.range(3)};
|
||||
|
||||
assert(expectedValues.find(ranges) != expectedValues.end());
|
||||
|
||||
actualValues.insert(ranges);
|
||||
}
|
||||
|
||||
// NOTE: This is not TearDown as we want to check after _all_ runs are
|
||||
// complete.
|
||||
~ArgsProductFixture() override {
|
||||
if (actualValues != expectedValues) {
|
||||
std::cout << "EXPECTED\n";
|
||||
for (const auto& v : expectedValues) {
|
||||
std::cout << "{";
|
||||
for (int64_t iv : v) {
|
||||
std::cout << iv << ", ";
|
||||
}
|
||||
std::cout << "}\n";
|
||||
}
|
||||
std::cout << "ACTUAL\n";
|
||||
for (const auto& v : actualValues) {
|
||||
std::cout << "{";
|
||||
for (int64_t iv : v) {
|
||||
std::cout << iv << ", ";
|
||||
}
|
||||
std::cout << "}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::vector<int64_t>> expectedValues;
|
||||
std::set<std::vector<int64_t>> actualValues;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(ArgsProductFixture, Empty)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
int64_t product =
|
||||
state.range(0) * state.range(1) * state.range(2) * state.range(3);
|
||||
for (int64_t x = 0; x < product; x++) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(ArgsProductFixture, Empty)
|
||||
->Args({0, 100, 2000, 30000})
|
||||
->ArgsProduct({{1, 2}, {15}, {3, 7, 10}, {8, 9}})
|
||||
->Args({4, 5, 6, 11});
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,184 @@
|
||||
|
||||
#include "benchmark/macros.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/types.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#define BASIC_BENCHMARK_TEST(x) BENCHMARK(x)->Arg(8)->Arg(512)->Arg(8192)
|
||||
|
||||
namespace {
|
||||
void BM_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty);
|
||||
BENCHMARK(BM_empty)->ThreadPerCpu();
|
||||
|
||||
void BM_spin_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
for (auto x = 0; x < state.range(0); ++x) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
BASIC_BENCHMARK_TEST(BM_spin_empty);
|
||||
BASIC_BENCHMARK_TEST(BM_spin_empty)->ThreadPerCpu();
|
||||
|
||||
void BM_spin_pause_before(benchmark::State& state) {
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
for (auto _ : state) {
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_before);
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_before)->ThreadPerCpu();
|
||||
|
||||
void BM_spin_pause_during(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
state.PauseTiming();
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
state.ResumeTiming();
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_during);
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_during)->ThreadPerCpu();
|
||||
|
||||
void BM_pause_during(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
state.PauseTiming();
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_pause_during);
|
||||
BENCHMARK(BM_pause_during)->ThreadPerCpu();
|
||||
BENCHMARK(BM_pause_during)->UseRealTime();
|
||||
BENCHMARK(BM_pause_during)->UseRealTime()->ThreadPerCpu();
|
||||
|
||||
void BM_spin_pause_after(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_after);
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_after)->ThreadPerCpu();
|
||||
|
||||
void BM_spin_pause_before_and_after(benchmark::State& state) {
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
for (auto _ : state) {
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
for (auto i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after);
|
||||
BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after)->ThreadPerCpu();
|
||||
|
||||
void BM_empty_stop_start(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty_stop_start);
|
||||
BENCHMARK(BM_empty_stop_start)->ThreadPerCpu();
|
||||
|
||||
void BM_KeepRunning(benchmark::State& state) {
|
||||
benchmark::IterationCount iter_count = 0;
|
||||
assert(iter_count == state.iterations());
|
||||
while (state.KeepRunning()) {
|
||||
++iter_count;
|
||||
}
|
||||
assert(iter_count == state.iterations());
|
||||
}
|
||||
BENCHMARK(BM_KeepRunning);
|
||||
|
||||
void BM_KeepRunningBatch(benchmark::State& state) {
|
||||
// Choose a batch size >1000 to skip the typical runs with iteration
|
||||
// targets of 10, 100 and 1000. If these are not actually skipped the
|
||||
// bug would be detectable as consecutive runs with the same iteration
|
||||
// count. Below we assert that this does not happen.
|
||||
const benchmark::IterationCount batch_size = 1009;
|
||||
|
||||
static benchmark::IterationCount prior_iter_count = 0;
|
||||
benchmark::IterationCount iter_count = 0;
|
||||
while (state.KeepRunningBatch(batch_size)) {
|
||||
iter_count += batch_size;
|
||||
}
|
||||
assert(state.iterations() == iter_count);
|
||||
|
||||
// Verify that the iteration count always increases across runs (see
|
||||
// comment above).
|
||||
assert(iter_count == batch_size // max_iterations == 1
|
||||
|| iter_count > prior_iter_count); // max_iterations > batch_size
|
||||
prior_iter_count = iter_count;
|
||||
}
|
||||
// Register with a fixed repetition count to establish the invariant that
|
||||
// the iteration count should always change across runs. This overrides
|
||||
// the --benchmark_repetitions command line flag, which would otherwise
|
||||
// cause this test to fail if set > 1.
|
||||
BENCHMARK(BM_KeepRunningBatch)->Repetitions(1);
|
||||
|
||||
void BM_RangedFor(benchmark::State& state) {
|
||||
benchmark::IterationCount iter_count = 0;
|
||||
for (auto _ : state) {
|
||||
++iter_count;
|
||||
}
|
||||
assert(iter_count == state.max_iterations);
|
||||
}
|
||||
BENCHMARK(BM_RangedFor);
|
||||
|
||||
template <typename T>
|
||||
void BM_OneTemplateFunc(benchmark::State& state) {
|
||||
auto arg = state.range(0);
|
||||
BENCHMARK_UNUSED T sum = 0;
|
||||
for (auto _ : state) {
|
||||
sum += static_cast<T>(arg);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_OneTemplateFunc<int>)->Arg(1);
|
||||
BENCHMARK(BM_OneTemplateFunc<double>)->Arg(1);
|
||||
|
||||
template <typename A, typename B>
|
||||
void BM_TwoTemplateFunc(benchmark::State& state) {
|
||||
auto arg = state.range(0);
|
||||
BENCHMARK_UNUSED A sum = 0;
|
||||
BENCHMARK_UNUSED B prod = 1;
|
||||
for (auto _ : state) {
|
||||
sum += static_cast<A>(arg);
|
||||
prod *= static_cast<B>(arg);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_TwoTemplateFunc<int, double>)->Arg(1);
|
||||
BENCHMARK(BM_TwoTemplateFunc<double, int>)->Arg(1);
|
||||
|
||||
// Ensure that StateIterator provides all the necessary typedefs required to
|
||||
// instantiate std::iterator_traits.
|
||||
static_assert(
|
||||
std::is_same<typename std::iterator_traits<
|
||||
benchmark::State::StateIterator>::value_type,
|
||||
typename benchmark::State::StateIterator::value_type>::value,
|
||||
"");
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,169 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/benchmark_register.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(AddRangeTest, Simple) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, 1, 2, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(1, 2));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, Simple64) {
|
||||
std::vector<int64_t> dst;
|
||||
AddRange(&dst, static_cast<int64_t>(1), static_cast<int64_t>(2), 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(1, 2));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, Advanced) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, 5, 15, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(5, 8, 15));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, Advanced64) {
|
||||
std::vector<int64_t> dst;
|
||||
AddRange(&dst, static_cast<int64_t>(5), static_cast<int64_t>(15), 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(5, 8, 15));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, FullRange8) {
|
||||
std::vector<int8_t> dst;
|
||||
AddRange(&dst, int8_t{1}, std::numeric_limits<int8_t>::max(), 8);
|
||||
EXPECT_THAT(
|
||||
dst, testing::ElementsAre(int8_t{1}, int8_t{8}, int8_t{64}, int8_t{127}));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, FullRange64) {
|
||||
std::vector<int64_t> dst;
|
||||
AddRange(&dst, int64_t{1}, std::numeric_limits<int64_t>::max(), 1024);
|
||||
EXPECT_THAT(
|
||||
dst, testing::ElementsAre(1LL, 1024LL, 1048576LL, 1073741824LL,
|
||||
1099511627776LL, 1125899906842624LL,
|
||||
1152921504606846976LL, 9223372036854775807LL));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, NegativeRanges) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -8, 0, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1, 0));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, StrictlyNegative) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -8, -1, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, SymmetricNegativeRanges) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -8, 8, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1, 0, 1, 2, 4, 8));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, SymmetricNegativeRangesOddMult) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -30, 32, 5);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-30, -25, -5, -1, 0, 1, 5, 25, 32));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, NegativeRangesAsymmetric) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -3, 5, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-3, -2, -1, 0, 1, 2, 4, 5));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, NegativeRangesLargeStep) {
|
||||
// Always include -1, 0, 1 when crossing zero.
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, -8, 8, 10);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-8, -1, 0, 1, 8));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, ZeroOnlyRange) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, 0, 0, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, ZeroStartingRange) {
|
||||
std::vector<int> dst;
|
||||
AddRange(&dst, 0, 2, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(0, 1, 2));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, NegativeRange64) {
|
||||
std::vector<int64_t> dst;
|
||||
AddRange<int64_t>(&dst, -4, 4, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(-4, -2, -1, 0, 1, 2, 4));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, NegativeRangePreservesExistingOrder) {
|
||||
// If elements already exist in the range, ensure we don't change
|
||||
// their ordering by adding negative values.
|
||||
std::vector<int64_t> dst = {1, 2, 3};
|
||||
AddRange<int64_t>(&dst, -2, 2, 2);
|
||||
EXPECT_THAT(dst, testing::ElementsAre(1, 2, 3, -2, -1, 0, 1, 2));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, FullNegativeRange64) {
|
||||
std::vector<int64_t> dst;
|
||||
const auto min = std::numeric_limits<int64_t>::min();
|
||||
const auto max = std::numeric_limits<int64_t>::max();
|
||||
AddRange(&dst, min, max, 1024);
|
||||
EXPECT_THAT(
|
||||
dst, testing::ElementsAreArray(std::vector<int64_t>{
|
||||
min, -1152921504606846976LL, -1125899906842624LL,
|
||||
-1099511627776LL, -1073741824LL, -1048576LL, -1024LL, -1LL, 0LL,
|
||||
1LL, 1024LL, 1048576LL, 1073741824LL, 1099511627776LL,
|
||||
1125899906842624LL, 1152921504606846976LL, max}));
|
||||
}
|
||||
|
||||
TEST(AddRangeTest, Simple8) {
|
||||
std::vector<int8_t> dst;
|
||||
AddRange<int8_t>(&dst, int8_t{1}, int8_t{8}, int8_t{2});
|
||||
EXPECT_THAT(dst,
|
||||
testing::ElementsAre(int8_t{1}, int8_t{2}, int8_t{4}, int8_t{8}));
|
||||
}
|
||||
|
||||
TEST(AddCustomContext, Simple) {
|
||||
std::map<std::string, std::string>*& global_context = GetGlobalContext();
|
||||
EXPECT_THAT(global_context, nullptr);
|
||||
|
||||
AddCustomContext("foo", "bar");
|
||||
AddCustomContext("baz", "qux");
|
||||
|
||||
EXPECT_THAT(*global_context,
|
||||
testing::UnorderedElementsAre(testing::Pair("foo", "bar"),
|
||||
testing::Pair("baz", "qux")));
|
||||
|
||||
delete global_context;
|
||||
global_context = nullptr;
|
||||
}
|
||||
|
||||
TEST(AddCustomContext, DuplicateKey) {
|
||||
std::map<std::string, std::string>*& global_context = GetGlobalContext();
|
||||
EXPECT_THAT(global_context, nullptr);
|
||||
|
||||
AddCustomContext("foo", "bar");
|
||||
AddCustomContext("foo", "qux");
|
||||
|
||||
EXPECT_THAT(*global_context,
|
||||
testing::UnorderedElementsAre(testing::Pair("foo", "bar")));
|
||||
|
||||
delete global_context;
|
||||
global_context = nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
// Tests that we can specify the number of iterations with
|
||||
// --benchmark_min_time=<NUM>x.
|
||||
namespace {
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& context) override {
|
||||
return ConsoleReporter::ReportContext(context);
|
||||
};
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
assert(report.size() == 1);
|
||||
iter_nums_.push_back(report[0].iterations);
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
};
|
||||
|
||||
TestReporter() {}
|
||||
|
||||
~TestReporter() override {}
|
||||
|
||||
const std::vector<benchmark::IterationCount>& GetIters() const {
|
||||
return iter_nums_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<benchmark::IterationCount> iter_nums_;
|
||||
};
|
||||
|
||||
void BM_MyBench(benchmark::State& state) {
|
||||
for (auto s : state) {
|
||||
}
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK(BM_MyBench);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
// Make a fake argv and append the new --benchmark_min_time=<foo> to it.
|
||||
int fake_argc = argc + 1;
|
||||
std::vector<const char*> fake_argv(static_cast<size_t>(fake_argc));
|
||||
for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
|
||||
fake_argv[i] = argv[i];
|
||||
}
|
||||
fake_argv[static_cast<size_t>(argc)] = "--benchmark_min_time=4x";
|
||||
|
||||
benchmark::Initialize(&fake_argc, const_cast<char**>(fake_argv.data()));
|
||||
|
||||
TestReporter test_reporter;
|
||||
const size_t returned_count =
|
||||
benchmark::RunSpecifiedBenchmarks(&test_reporter, "BM_MyBench");
|
||||
assert(returned_count == 1);
|
||||
|
||||
// Check the executed iters.
|
||||
const std::vector<benchmark::IterationCount> iters = test_reporter.GetIters();
|
||||
assert(!iters.empty() && iters[0] == 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
// Tests that we can specify the min time with
|
||||
// --benchmark_min_time=<NUM> (no suffix needed) OR
|
||||
// --benchmark_min_time=<NUM>s
|
||||
namespace {
|
||||
|
||||
// This is from benchmark.h
|
||||
typedef int64_t IterationCount;
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& context) override {
|
||||
return ConsoleReporter::ReportContext(context);
|
||||
};
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
assert(report.size() == 1);
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
};
|
||||
|
||||
void ReportRunsConfig(double min_time, bool /* has_explicit_iters */,
|
||||
IterationCount /* iters */) override {
|
||||
min_times_.push_back(min_time);
|
||||
}
|
||||
|
||||
TestReporter() {}
|
||||
|
||||
~TestReporter() override {}
|
||||
|
||||
const std::vector<double>& GetMinTimes() const { return min_times_; }
|
||||
|
||||
private:
|
||||
std::vector<double> min_times_;
|
||||
};
|
||||
|
||||
bool AlmostEqual(double a, double b) {
|
||||
return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
void DoTestHelper(int* argc, const char** argv, double expected) {
|
||||
benchmark::Initialize(argc, const_cast<char**>(argv));
|
||||
|
||||
TestReporter test_reporter;
|
||||
const size_t returned_count =
|
||||
benchmark::RunSpecifiedBenchmarks(&test_reporter, "BM_MyBench");
|
||||
assert(returned_count == 1);
|
||||
|
||||
// Check the min_time
|
||||
const std::vector<double>& min_times = test_reporter.GetMinTimes();
|
||||
assert(!min_times.empty() && AlmostEqual(min_times[0], expected));
|
||||
}
|
||||
|
||||
void BM_MyBench(benchmark::State& state) {
|
||||
for (auto s : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_MyBench);
|
||||
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
// Make a fake argv and append the new --benchmark_min_time=<foo> to it.
|
||||
int fake_argc = argc + 1;
|
||||
std::vector<const char*> fake_argv(static_cast<size_t>(fake_argc));
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
|
||||
fake_argv[i] = argv[i];
|
||||
}
|
||||
|
||||
const char* no_suffix = "--benchmark_min_time=4";
|
||||
const char* with_suffix = "--benchmark_min_time=4.0s";
|
||||
double expected = 4.0;
|
||||
|
||||
fake_argv[static_cast<size_t>(argc)] = no_suffix;
|
||||
DoTestHelper(&fake_argc, fake_argv.data(), expected);
|
||||
|
||||
fake_argv[static_cast<size_t>(argc)] = with_suffix;
|
||||
DoTestHelper(&fake_argc, fake_argv.data(), expected);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "benchmark/reporter.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace benchmark;
|
||||
using namespace benchmark::internal;
|
||||
|
||||
TEST(BenchmarkNameTest, Empty) {
|
||||
const auto name = BenchmarkName();
|
||||
EXPECT_EQ(name.str(), std::string());
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, FunctionName) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
EXPECT_EQ(name.str(), "function_name");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, FunctionNameAndArgs) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.args = "some_args:3/4/5";
|
||||
EXPECT_EQ(name.str(), "function_name/some_args:3/4/5");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, MinTime) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.args = "some_args:3/4";
|
||||
name.min_time = "min_time:3.4s";
|
||||
EXPECT_EQ(name.str(), "function_name/some_args:3/4/min_time:3.4s");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, MinWarmUpTime) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.args = "some_args:3/4";
|
||||
name.min_warmup_time = "min_warmup_time:3.5s";
|
||||
EXPECT_EQ(name.str(), "function_name/some_args:3/4/min_warmup_time:3.5s");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, Iterations) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.min_time = "min_time:3.4s";
|
||||
name.iterations = "iterations:42";
|
||||
EXPECT_EQ(name.str(), "function_name/min_time:3.4s/iterations:42");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, Repetitions) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.min_time = "min_time:3.4s";
|
||||
name.repetitions = "repetitions:24";
|
||||
EXPECT_EQ(name.str(), "function_name/min_time:3.4s/repetitions:24");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, TimeType) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.min_time = "min_time:3.4s";
|
||||
name.time_type = "hammer_time";
|
||||
EXPECT_EQ(name.str(), "function_name/min_time:3.4s/hammer_time");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, Threads) {
|
||||
auto name = BenchmarkName();
|
||||
name.function_name = "function_name";
|
||||
name.min_time = "min_time:3.4s";
|
||||
name.threads = "threads:256";
|
||||
EXPECT_EQ(name.str(), "function_name/min_time:3.4s/threads:256");
|
||||
}
|
||||
|
||||
TEST(BenchmarkNameTest, TestEmptyFunctionName) {
|
||||
auto name = BenchmarkName();
|
||||
name.args = "first:3/second:4";
|
||||
name.threads = "threads:22";
|
||||
EXPECT_EQ(name.str(), "first:3/second:4/threads:22");
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
@@ -0,0 +1,130 @@
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/commandlineflags.h"
|
||||
#include "../src/string_util.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
BM_DECLARE_bool(benchmark_enable_random_interleaving);
|
||||
BM_DECLARE_string(benchmark_filter);
|
||||
BM_DECLARE_int32(benchmark_repetitions);
|
||||
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
class EventQueue : public std::queue<std::string> {
|
||||
public:
|
||||
void Put(const std::string& event) { push(event); }
|
||||
|
||||
void Clear() {
|
||||
while (!empty()) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Get() {
|
||||
std::string event = front();
|
||||
pop();
|
||||
return event;
|
||||
}
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
EventQueue* const queue = new EventQueue();
|
||||
|
||||
class NullReporter : public BenchmarkReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& /*context*/) override { return true; }
|
||||
void ReportRuns(const std::vector<Run>& /* report */) override {}
|
||||
};
|
||||
|
||||
class BenchmarkTest : public testing::Test {
|
||||
public:
|
||||
static void SetupHook(int /* num_threads */) { queue->push("Setup"); }
|
||||
|
||||
static void TeardownHook(int /* num_threads */) { queue->push("Teardown"); }
|
||||
|
||||
static void Execute(const std::string& pattern) {
|
||||
queue->Clear();
|
||||
|
||||
std::unique_ptr<BenchmarkReporter> reporter(new NullReporter());
|
||||
FLAGS_benchmark_filter = pattern;
|
||||
RunSpecifiedBenchmarks(reporter.get());
|
||||
|
||||
queue->Put("DONE"); // End marker
|
||||
}
|
||||
};
|
||||
|
||||
void BM_Match1(benchmark::State& state) {
|
||||
const int64_t arg = state.range(0);
|
||||
|
||||
for (auto _ : state) {
|
||||
}
|
||||
queue->Put(StrFormat("BM_Match1/%d", static_cast<int>(arg)));
|
||||
}
|
||||
BENCHMARK(BM_Match1)
|
||||
->Iterations(100)
|
||||
->Arg(1)
|
||||
->Arg(2)
|
||||
->Arg(3)
|
||||
->Range(10, 80)
|
||||
->Args({90})
|
||||
->Args({100});
|
||||
|
||||
TEST_F(BenchmarkTest, Match1) {
|
||||
Execute("BM_Match1");
|
||||
ASSERT_EQ("BM_Match1/1", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/2", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/3", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/10", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/64", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/80", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/90", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/100", queue->Get());
|
||||
ASSERT_EQ("DONE", queue->Get());
|
||||
}
|
||||
|
||||
TEST_F(BenchmarkTest, Match1WithRepetition) {
|
||||
FLAGS_benchmark_repetitions = 2;
|
||||
|
||||
Execute("BM_Match1/(64|80)");
|
||||
ASSERT_EQ("BM_Match1/64", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/64", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/80", queue->Get());
|
||||
ASSERT_EQ("BM_Match1/80", queue->Get());
|
||||
ASSERT_EQ("DONE", queue->Get());
|
||||
}
|
||||
|
||||
TEST_F(BenchmarkTest, Match1WithRandomInterleaving) {
|
||||
FLAGS_benchmark_enable_random_interleaving = true;
|
||||
FLAGS_benchmark_repetitions = 100;
|
||||
|
||||
std::map<std::string, int> element_count;
|
||||
std::map<std::string, int> interleaving_count;
|
||||
Execute("BM_Match1/(64|80)");
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
std::vector<std::string> interleaving;
|
||||
interleaving.push_back(queue->Get());
|
||||
interleaving.push_back(queue->Get());
|
||||
element_count[interleaving[0]]++;
|
||||
element_count[interleaving[1]]++;
|
||||
interleaving_count[StrFormat("%s,%s", interleaving[0].c_str(),
|
||||
interleaving[1].c_str())]++;
|
||||
}
|
||||
EXPECT_EQ(element_count["BM_Match1/64"], 100) << "Unexpected repetitions.";
|
||||
EXPECT_EQ(element_count["BM_Match1/80"], 100) << "Unexpected repetitions.";
|
||||
EXPECT_GE(interleaving_count.size(), 2) << "Interleaving was not randomized.";
|
||||
ASSERT_EQ("DONE", queue->Get());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/types.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using benchmark::Benchmark;
|
||||
using benchmark::BenchmarkReporter;
|
||||
using benchmark::callback_function;
|
||||
using benchmark::ClearRegisteredBenchmarks;
|
||||
using benchmark::RegisterBenchmark;
|
||||
using benchmark::RunSpecifiedBenchmarks;
|
||||
using benchmark::State;
|
||||
|
||||
static int functor_called = 0;
|
||||
struct Functor {
|
||||
void operator()(const benchmark::State& /*unused*/) { functor_called++; }
|
||||
};
|
||||
|
||||
class NullReporter : public BenchmarkReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& /*context*/) override { return true; }
|
||||
void ReportRuns(const std::vector<Run>& /* report */) override {}
|
||||
};
|
||||
|
||||
class BenchmarkTest : public testing::Test {
|
||||
public:
|
||||
Benchmark* bm;
|
||||
NullReporter null_reporter;
|
||||
|
||||
int setup_calls;
|
||||
int teardown_calls;
|
||||
|
||||
void SetUp() override {
|
||||
setup_calls = 0;
|
||||
teardown_calls = 0;
|
||||
functor_called = 0;
|
||||
|
||||
bm = RegisterBenchmark("BM", [](State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
});
|
||||
bm->Iterations(1);
|
||||
}
|
||||
|
||||
void TearDown() override { ClearRegisteredBenchmarks(); }
|
||||
};
|
||||
|
||||
// Test that Setup/Teardown can correctly take a lambda expressions
|
||||
TEST_F(BenchmarkTest, LambdaTestCopy) {
|
||||
auto setup_lambda = [this](const State&) { setup_calls++; };
|
||||
auto teardown_lambda = [this](const State&) { teardown_calls++; };
|
||||
bm->Setup(setup_lambda);
|
||||
bm->Teardown(teardown_lambda);
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(setup_calls, 1);
|
||||
EXPECT_EQ(teardown_calls, 1);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can correctly take a lambda expressions
|
||||
TEST_F(BenchmarkTest, LambdaTestMove) {
|
||||
auto setup_lambda = [this](const State&) { setup_calls++; };
|
||||
auto teardown_lambda = [this](const State&) { teardown_calls++; };
|
||||
bm->Setup(std::move(setup_lambda));
|
||||
bm->Teardown(std::move(teardown_lambda));
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(setup_calls, 1);
|
||||
EXPECT_EQ(teardown_calls, 1);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can correctly take std::function
|
||||
TEST_F(BenchmarkTest, CallbackFunctionCopy) {
|
||||
callback_function setup_lambda = [this](const State&) { setup_calls++; };
|
||||
callback_function teardown_lambda = [this](const State&) {
|
||||
teardown_calls++;
|
||||
};
|
||||
bm->Setup(setup_lambda);
|
||||
bm->Teardown(teardown_lambda);
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(setup_calls, 1);
|
||||
EXPECT_EQ(teardown_calls, 1);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can correctly take std::function
|
||||
TEST_F(BenchmarkTest, CallbackFunctionMove) {
|
||||
callback_function setup_lambda = [this](const State&) { setup_calls++; };
|
||||
callback_function teardown_lambda = [this](const State&) {
|
||||
teardown_calls++;
|
||||
};
|
||||
bm->Setup(std::move(setup_lambda));
|
||||
bm->Teardown(std::move(teardown_lambda));
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(setup_calls, 1);
|
||||
EXPECT_EQ(teardown_calls, 1);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can correctly take functors
|
||||
TEST_F(BenchmarkTest, FunctorCopy) {
|
||||
Functor func;
|
||||
bm->Setup(func);
|
||||
bm->Teardown(func);
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(functor_called, 2);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can correctly take functors
|
||||
TEST_F(BenchmarkTest, FunctorMove) {
|
||||
Functor func1;
|
||||
Functor func2;
|
||||
bm->Setup(std::move(func1));
|
||||
bm->Teardown(std::move(func2));
|
||||
RunSpecifiedBenchmarks(&null_reporter);
|
||||
EXPECT_EQ(functor_called, 2);
|
||||
}
|
||||
|
||||
// Test that Setup/Teardown can not take nullptr
|
||||
TEST_F(BenchmarkTest, NullptrTest) {
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
// Tests only runnable in debug mode (when BM_CHECK is enabled).
|
||||
#ifndef NDEBUG
|
||||
#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS
|
||||
EXPECT_DEATH(bm->Setup(nullptr), "setup != nullptr");
|
||||
EXPECT_DEATH(bm->Teardown(nullptr), "teardown != nullptr");
|
||||
#else
|
||||
GTEST_SKIP() << "Test skipped because BM_CHECK is disabled";
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
// Test that Setup() and Teardown() are called exactly once
|
||||
// for each benchmark run (single-threaded).
|
||||
namespace {
|
||||
namespace singlethreaded {
|
||||
static int setup_call = 0;
|
||||
static int teardown_call = 0;
|
||||
} // namespace singlethreaded
|
||||
} // namespace
|
||||
static void DoSetup1(const benchmark::State& state) {
|
||||
++singlethreaded::setup_call;
|
||||
|
||||
// Setup/Teardown should never be called with any thread_idx != 0.
|
||||
assert(state.thread_index() == 0);
|
||||
}
|
||||
|
||||
static void DoTeardown1(const benchmark::State& state) {
|
||||
++singlethreaded::teardown_call;
|
||||
assert(state.thread_index() == 0);
|
||||
}
|
||||
|
||||
static void BM_with_setup(benchmark::State& state) {
|
||||
for (auto s : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_with_setup)
|
||||
->Arg(1)
|
||||
->Arg(3)
|
||||
->Arg(5)
|
||||
->Arg(7)
|
||||
->Iterations(100)
|
||||
->Setup(DoSetup1)
|
||||
->Teardown(DoTeardown1);
|
||||
|
||||
// Test that Setup() and Teardown() are called once for each group of threads.
|
||||
namespace {
|
||||
namespace concurrent {
|
||||
static std::atomic<int> setup_call(0);
|
||||
static std::atomic<int> teardown_call(0);
|
||||
static std::atomic<int> func_call(0);
|
||||
} // namespace concurrent
|
||||
|
||||
void DoSetup2(const benchmark::State& state) {
|
||||
concurrent::setup_call.fetch_add(1, std::memory_order_acquire);
|
||||
assert(state.thread_index() == 0);
|
||||
}
|
||||
|
||||
void DoTeardown2(const benchmark::State& state) {
|
||||
concurrent::teardown_call.fetch_add(1, std::memory_order_acquire);
|
||||
assert(state.thread_index() == 0);
|
||||
}
|
||||
|
||||
void BM_concurrent(benchmark::State& state) {
|
||||
for (auto s : state) {
|
||||
}
|
||||
concurrent::func_call.fetch_add(1, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
BENCHMARK(BM_concurrent)
|
||||
->Setup(DoSetup2)
|
||||
->Teardown(DoTeardown2)
|
||||
->Iterations(100)
|
||||
->Threads(5)
|
||||
->Threads(10)
|
||||
->Threads(15);
|
||||
|
||||
// Testing interaction with Fixture::Setup/Teardown
|
||||
namespace fixture_interaction {
|
||||
int setup = 0;
|
||||
int fixture_setup = 0;
|
||||
} // namespace fixture_interaction
|
||||
|
||||
#define FIXTURE_BECHMARK_NAME MyFixture
|
||||
|
||||
class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& /*unused*/) override {
|
||||
fixture_interaction::fixture_setup++;
|
||||
}
|
||||
|
||||
~FIXTURE_BECHMARK_NAME() override {}
|
||||
};
|
||||
|
||||
BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
}
|
||||
|
||||
void DoSetupWithFixture(const benchmark::State& /*unused*/) {
|
||||
fixture_interaction::setup++;
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)
|
||||
->Arg(1)
|
||||
->Arg(3)
|
||||
->Arg(5)
|
||||
->Arg(7)
|
||||
->Setup(DoSetupWithFixture)
|
||||
->Repetitions(1)
|
||||
->Iterations(100);
|
||||
|
||||
// Testing repetitions.
|
||||
namespace repetitions {
|
||||
int setup = 0;
|
||||
}
|
||||
|
||||
void DoSetupWithRepetitions(const benchmark::State& /*unused*/) {
|
||||
repetitions::setup++;
|
||||
}
|
||||
void BM_WithRep(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_WithRep)
|
||||
->Arg(1)
|
||||
->Arg(3)
|
||||
->Arg(5)
|
||||
->Arg(7)
|
||||
->Setup(DoSetupWithRepetitions)
|
||||
->Iterations(100)
|
||||
->Repetitions(4);
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
size_t ret = benchmark::RunSpecifiedBenchmarks(".");
|
||||
assert(ret > 0);
|
||||
|
||||
// Setup/Teardown is called once for each arg group (1,3,5,7).
|
||||
assert(singlethreaded::setup_call == 4);
|
||||
assert(singlethreaded::teardown_call == 4);
|
||||
|
||||
// 3 group of threads calling this function (3,5,10).
|
||||
assert(concurrent::setup_call.load(std::memory_order_relaxed) == 3);
|
||||
assert(concurrent::teardown_call.load(std::memory_order_relaxed) == 3);
|
||||
assert((5 + 10 + 15) ==
|
||||
concurrent::func_call.load(std::memory_order_relaxed));
|
||||
|
||||
// Setup is called 4 times, once for each arg group (1,3,5,7)
|
||||
assert(fixture_interaction::setup == 4);
|
||||
// Fixture::Setup is called every time the bm routine is run.
|
||||
// The exact number is indeterministic, so we just assert that
|
||||
// it's more than setup.
|
||||
assert(fixture_interaction::fixture_setup > fixture_interaction::setup);
|
||||
|
||||
// Setup is call once for each repetition * num_arg = 4 * 4 = 16.
|
||||
assert(repetitions::setup == 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <complex>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define BENCHMARK_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define BENCHMARK_NOINLINE
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
int BENCHMARK_NOINLINE Factorial(int n) {
|
||||
return (n == 1) ? 1 : n * Factorial(n - 1);
|
||||
}
|
||||
|
||||
double CalculatePi(int depth) {
|
||||
double pi = 0.0;
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
double numerator = static_cast<double>(((i % 2) * 2) - 1);
|
||||
double denominator = static_cast<double>((2 * i) - 1);
|
||||
pi += numerator / denominator;
|
||||
}
|
||||
return (pi - 1.0) * 4;
|
||||
}
|
||||
|
||||
std::set<int64_t> ConstructRandomSet(int64_t size) {
|
||||
std::set<int64_t> s;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
s.insert(s.end(), i);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::mutex test_vector_mu;
|
||||
std::optional<std::vector<int>> test_vector;
|
||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
void BM_Factorial(benchmark::State& state) {
|
||||
int fac_42 = 0;
|
||||
for (auto _ : state) {
|
||||
fac_42 = Factorial(8);
|
||||
}
|
||||
// Prevent compiler optimizations
|
||||
std::stringstream ss;
|
||||
ss << fac_42;
|
||||
state.SetLabel(ss.str());
|
||||
}
|
||||
BENCHMARK(BM_Factorial);
|
||||
BENCHMARK(BM_Factorial)->UseRealTime();
|
||||
|
||||
void BM_CalculatePiRange(benchmark::State& state) {
|
||||
double pi = 0.0;
|
||||
for (auto _ : state) {
|
||||
pi = CalculatePi(static_cast<int>(state.range(0)));
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << pi;
|
||||
state.SetLabel(ss.str());
|
||||
}
|
||||
BENCHMARK_RANGE(BM_CalculatePiRange, 1, 1024 * 1024);
|
||||
|
||||
void BM_CalculatePi(benchmark::State& state) {
|
||||
static const int depth = 1024;
|
||||
for (auto _ : state) {
|
||||
double pi = CalculatePi(static_cast<int>(depth));
|
||||
benchmark::DoNotOptimize(pi);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CalculatePi)->Threads(8);
|
||||
BENCHMARK(BM_CalculatePi)->ThreadRange(1, 32);
|
||||
BENCHMARK(BM_CalculatePi)->ThreadPerCpu();
|
||||
|
||||
void BM_SetInsert(benchmark::State& state) {
|
||||
std::set<int64_t> data;
|
||||
for (auto _ : state) {
|
||||
state.PauseTiming();
|
||||
data = ConstructRandomSet(state.range(0));
|
||||
state.ResumeTiming();
|
||||
for (int j = 0; j < state.range(1); ++j) {
|
||||
data.insert(rand());
|
||||
}
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * state.range(1));
|
||||
state.SetBytesProcessed(state.iterations() * state.range(1) *
|
||||
static_cast<int64_t>(sizeof(int)));
|
||||
}
|
||||
|
||||
// Test many inserts at once to reduce the total iterations needed. Otherwise,
|
||||
// the slower, non-timed part of each iteration will make the benchmark take
|
||||
// forever.
|
||||
BENCHMARK(BM_SetInsert)->Ranges({{1 << 10, 8 << 10}, {128, 512}});
|
||||
|
||||
template <typename Container,
|
||||
typename ValueType = typename Container::value_type>
|
||||
void BM_Sequential(benchmark::State& state) {
|
||||
ValueType v = 42;
|
||||
for (auto _ : state) {
|
||||
Container c;
|
||||
for (int64_t i = state.range(0); --i;) {
|
||||
c.push_back(v);
|
||||
}
|
||||
}
|
||||
const int64_t items_processed = state.iterations() * state.range(0);
|
||||
state.SetItemsProcessed(items_processed);
|
||||
state.SetBytesProcessed(items_processed * static_cast<int64_t>(sizeof(v)));
|
||||
}
|
||||
BENCHMARK_TEMPLATE2(BM_Sequential, std::vector<int>, int)
|
||||
->Range(1 << 0, 1 << 10);
|
||||
BENCHMARK_TEMPLATE(BM_Sequential, std::list<int>)->Range(1 << 0, 1 << 10);
|
||||
// Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond.
|
||||
BENCHMARK_TEMPLATE(BM_Sequential, std::vector<int>, int)->Arg(512);
|
||||
|
||||
void BM_StringCompare(benchmark::State& state) {
|
||||
size_t len = static_cast<size_t>(state.range(0));
|
||||
std::string s1(len, '-');
|
||||
std::string s2(len, '-');
|
||||
for (auto _ : state) {
|
||||
auto comp = s1.compare(s2);
|
||||
benchmark::DoNotOptimize(comp);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_StringCompare)->Range(1, 1 << 20);
|
||||
|
||||
void BM_SetupTeardown(benchmark::State& state) {
|
||||
if (state.thread_index() == 0) {
|
||||
// No need to lock test_vector_mu here as this is running single-threaded.
|
||||
test_vector = std::vector<int>();
|
||||
}
|
||||
int i = 0;
|
||||
for (auto _ : state) {
|
||||
std::lock_guard<std::mutex> l(test_vector_mu);
|
||||
if (i % 2 == 0) {
|
||||
test_vector->push_back(i);
|
||||
} else {
|
||||
test_vector->pop_back();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (state.thread_index() == 0) {
|
||||
test_vector.reset();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SetupTeardown)->ThreadPerCpu();
|
||||
|
||||
void BM_LongTest(benchmark::State& state) {
|
||||
double tracker = 0.0;
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(tracker += i);
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_LongTest)->Range(1 << 16, 1 << 28);
|
||||
|
||||
void BM_ParallelMemset(benchmark::State& state) {
|
||||
int64_t size = state.range(0) / static_cast<int64_t>(sizeof(int));
|
||||
int thread_size = static_cast<int>(size) / state.threads();
|
||||
int from = thread_size * state.thread_index();
|
||||
int to = from + thread_size;
|
||||
|
||||
if (state.thread_index() == 0) {
|
||||
test_vector = std::vector<int>(static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = from; i < to; i++) {
|
||||
// No need to lock test_vector_mu as ranges
|
||||
// do not overlap between threads.
|
||||
benchmark::DoNotOptimize(test_vector->at(static_cast<size_t>(i)) = 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.thread_index() == 0) {
|
||||
test_vector.reset();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4);
|
||||
|
||||
void BM_ManualTiming(benchmark::State& state) {
|
||||
int64_t slept_for = 0;
|
||||
int64_t microseconds = state.range(0);
|
||||
std::chrono::duration<double, std::micro> sleep_duration{
|
||||
static_cast<double>(microseconds)};
|
||||
|
||||
for (auto _ : state) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
// Simulate some useful workload with a sleep
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(sleep_duration));
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto elapsed =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
|
||||
|
||||
state.SetIterationTime(elapsed.count());
|
||||
slept_for += microseconds;
|
||||
}
|
||||
state.SetItemsProcessed(slept_for);
|
||||
}
|
||||
BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseRealTime();
|
||||
BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseManualTime();
|
||||
|
||||
template <class... Args>
|
||||
void BM_with_args(benchmark::State& state, Args&&...) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK_CAPTURE(BM_with_args, int_test, 42, 43, 44);
|
||||
BENCHMARK_CAPTURE(BM_with_args, string_and_pair_test, std::string("abc"),
|
||||
std::pair<int, double>(42, 3.8));
|
||||
|
||||
void BM_non_template_args(benchmark::State& state, int, double) {
|
||||
while (state.KeepRunning()) {
|
||||
}
|
||||
}
|
||||
BENCHMARK_CAPTURE(BM_non_template_args, basic_test, 0, 0);
|
||||
|
||||
template <class T, class U, class... ExtraArgs>
|
||||
void BM_template2_capture(benchmark::State& state, ExtraArgs&&... extra_args) {
|
||||
static_assert(std::is_same<T, void>::value, "");
|
||||
static_assert(std::is_same<U, char*>::value, "");
|
||||
static_assert(std::is_same<ExtraArgs..., unsigned int>::value, "");
|
||||
unsigned int dummy[sizeof...(ExtraArgs)] = {extra_args...};
|
||||
assert(dummy[0] == 42);
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK_TEMPLATE2_CAPTURE(BM_template2_capture, void, char*, foo, 42U);
|
||||
BENCHMARK_CAPTURE((BM_template2_capture<void, char*>), foo, 42U);
|
||||
|
||||
template <class T, class... ExtraArgs>
|
||||
void BM_template1_capture(benchmark::State& state, ExtraArgs&&... extra_args) {
|
||||
static_assert(std::is_same<T, void>::value, "");
|
||||
static_assert(std::is_same<ExtraArgs..., unsigned long>::value, "");
|
||||
unsigned long dummy[sizeof...(ExtraArgs)] = {extra_args...};
|
||||
assert(dummy[0] == 24);
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL);
|
||||
BENCHMARK_CAPTURE(BM_template1_capture<void>, foo, 24UL);
|
||||
|
||||
void BM_DenseThreadRanges(benchmark::State& st) {
|
||||
switch (st.range(0)) {
|
||||
case 1:
|
||||
assert(st.threads() == 1 || st.threads() == 2 || st.threads() == 3);
|
||||
break;
|
||||
case 2:
|
||||
assert(st.threads() == 1 || st.threads() == 3 || st.threads() == 4);
|
||||
break;
|
||||
case 3:
|
||||
assert(st.threads() == 5 || st.threads() == 8 || st.threads() == 11 ||
|
||||
st.threads() == 14);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid test case number");
|
||||
}
|
||||
while (st.KeepRunning()) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_DenseThreadRanges)->Arg(1)->DenseThreadRange(1, 3);
|
||||
BENCHMARK(BM_DenseThreadRanges)->Arg(2)->DenseThreadRange(1, 4, 2);
|
||||
BENCHMARK(BM_DenseThreadRanges)->Arg(3)->DenseThreadRange(5, 14, 3);
|
||||
|
||||
void BM_BenchmarkName(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
|
||||
// Check that the benchmark name is passed correctly to `state`.
|
||||
assert("BM_BenchmarkName" == state.name());
|
||||
}
|
||||
BENCHMARK(BM_BenchmarkName);
|
||||
|
||||
// regression test for #1446
|
||||
template <typename type>
|
||||
void BM_templated_test(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
type created_string;
|
||||
benchmark::DoNotOptimize(created_string);
|
||||
}
|
||||
}
|
||||
|
||||
const auto BM_templated_test_double = BM_templated_test<std::complex<double>>;
|
||||
BENCHMARK(BM_templated_test_double);
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "benchmark/macros.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wreturn-type"
|
||||
#endif
|
||||
BENCHMARK_DISABLE_DEPRECATED_WARNING
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern int ExternInt;
|
||||
extern int ExternInt2;
|
||||
extern int ExternInt3;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_basic:
|
||||
extern "C" void test_basic() {
|
||||
int x;
|
||||
benchmark::DoNotOptimize(&x);
|
||||
x = 101;
|
||||
benchmark::ClobberMemory();
|
||||
// CHECK: leaq [[DEST:[^,]+]], %rax
|
||||
// CHECK: movl $101, [[DEST]]
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_redundant_store:
|
||||
extern "C" void test_redundant_store() {
|
||||
ExternInt = 3;
|
||||
benchmark::ClobberMemory();
|
||||
ExternInt = 51;
|
||||
// CHECK-DAG: ExternInt
|
||||
// CHECK-DAG: movl $3
|
||||
// CHECK: movl $51
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_redundant_read:
|
||||
extern "C" void test_redundant_read() {
|
||||
int x;
|
||||
benchmark::DoNotOptimize(&x);
|
||||
x = ExternInt;
|
||||
benchmark::ClobberMemory();
|
||||
x = ExternInt2;
|
||||
// CHECK: leaq [[DEST:[^,]+]], %rax
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, [[DEST]]
|
||||
// CHECK-NOT: ExternInt2
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_redundant_read2:
|
||||
extern "C" void test_redundant_read2() {
|
||||
int x;
|
||||
benchmark::DoNotOptimize(&x);
|
||||
x = ExternInt;
|
||||
benchmark::ClobberMemory();
|
||||
x = ExternInt2;
|
||||
benchmark::ClobberMemory();
|
||||
// CHECK: leaq [[DEST:[^,]+]], %rax
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, [[DEST]]
|
||||
// CHECK: ExternInt2(%rip)
|
||||
// CHECK: movl %eax, [[DEST]]
|
||||
// CHECK: ret
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../src/commandlineflags.h"
|
||||
#include "../src/internal_macros.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace {
|
||||
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
int setenv(const char* name, const char* value, int overwrite) {
|
||||
if (!overwrite) {
|
||||
// NOTE: getenv_s is far superior but not available under mingw.
|
||||
char* env_value = getenv(name);
|
||||
if (env_value == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return _putenv_s(name, value);
|
||||
}
|
||||
|
||||
int unsetenv(const char* name) { return _putenv_s(name, ""); }
|
||||
|
||||
#endif // BENCHMARK_OS_WINDOWS
|
||||
|
||||
TEST(BoolFromEnv, Default) {
|
||||
ASSERT_EQ(unsetenv("NOT_IN_ENV"), 0);
|
||||
EXPECT_EQ(BoolFromEnv("not_in_env", true), true);
|
||||
}
|
||||
|
||||
TEST(BoolFromEnv, False) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "0", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "N", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "n", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "NO", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "No", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "no", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "F", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "f", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "FALSE", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "False", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "false", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "OFF", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "Off", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "off", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", true), false);
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(BoolFromEnv, True) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "1", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "Y", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "y", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "YES", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "Yes", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "yes", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "T", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "t", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "TRUE", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "True", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "true", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "ON", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "On", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
ASSERT_EQ(setenv("IN_ENV", "on", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
ASSERT_EQ(setenv("IN_ENV", "", 1), 0);
|
||||
EXPECT_EQ(BoolFromEnv("in_env", false), true);
|
||||
unsetenv("IN_ENV");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Int32FromEnv, NotInEnv) {
|
||||
ASSERT_EQ(unsetenv("NOT_IN_ENV"), 0);
|
||||
EXPECT_EQ(Int32FromEnv("not_in_env", 42), 42);
|
||||
}
|
||||
|
||||
TEST(Int32FromEnv, InvalidInteger) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo", 1), 0);
|
||||
EXPECT_EQ(Int32FromEnv("in_env", 42), 42);
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(Int32FromEnv, ValidInteger) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "42", 1), 0);
|
||||
EXPECT_EQ(Int32FromEnv("in_env", 64), 42);
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(DoubleFromEnv, NotInEnv) {
|
||||
ASSERT_EQ(unsetenv("NOT_IN_ENV"), 0);
|
||||
EXPECT_EQ(DoubleFromEnv("not_in_env", 0.51), 0.51);
|
||||
}
|
||||
|
||||
TEST(DoubleFromEnv, InvalidReal) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo", 1), 0);
|
||||
EXPECT_EQ(DoubleFromEnv("in_env", 0.51), 0.51);
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(DoubleFromEnv, ValidReal) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "0.51", 1), 0);
|
||||
EXPECT_EQ(DoubleFromEnv("in_env", 0.71), 0.51);
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(StringFromEnv, Default) {
|
||||
ASSERT_EQ(unsetenv("NOT_IN_ENV"), 0);
|
||||
EXPECT_STREQ(StringFromEnv("not_in_env", "foo"), "foo");
|
||||
}
|
||||
|
||||
TEST(StringFromEnv, Valid) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo", 1), 0);
|
||||
EXPECT_STREQ(StringFromEnv("in_env", "bar"), "foo");
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(KvPairsFromEnv, Default) {
|
||||
ASSERT_EQ(unsetenv("NOT_IN_ENV"), 0);
|
||||
EXPECT_THAT(KvPairsFromEnv("not_in_env", {{"foo", "bar"}}),
|
||||
testing::ElementsAre(testing::Pair("foo", "bar")));
|
||||
}
|
||||
|
||||
TEST(KvPairsFromEnv, MalformedReturnsDefault) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo", 1), 0);
|
||||
EXPECT_THAT(KvPairsFromEnv("in_env", {{"foo", "bar"}}),
|
||||
testing::ElementsAre(testing::Pair("foo", "bar")));
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(KvPairsFromEnv, Single) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo=bar", 1), 0);
|
||||
EXPECT_THAT(KvPairsFromEnv("in_env", {}),
|
||||
testing::ElementsAre(testing::Pair("foo", "bar")));
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
TEST(KvPairsFromEnv, Multiple) {
|
||||
ASSERT_EQ(setenv("IN_ENV", "foo=bar,baz=qux", 1), 0);
|
||||
EXPECT_THAT(KvPairsFromEnv("in_env", {}),
|
||||
testing::UnorderedElementsAre(testing::Pair("foo", "bar"),
|
||||
testing::Pair("baz", "qux")));
|
||||
unsetenv("IN_ENV");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace benchmark
|
||||
@@ -0,0 +1,278 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/statistics.h"
|
||||
#include "benchmark/types.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#define ADD_COMPLEXITY_CASES(...) \
|
||||
const int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__)
|
||||
|
||||
int AddComplexityTest(const std::string& test_name,
|
||||
const std::string& big_o_test_name,
|
||||
const std::string& rms_test_name,
|
||||
const std::string& big_o, int family_index) {
|
||||
SetSubstitutions({{"%name", test_name},
|
||||
{"%bigo_name", big_o_test_name},
|
||||
{"%rms_name", rms_test_name},
|
||||
{"%bigo_str", "[ ]* %float " + big_o},
|
||||
{"%bigo", big_o},
|
||||
{"%rms", "[ ]*[0-9]+ %"}});
|
||||
AddCases(
|
||||
TC_ConsoleOut,
|
||||
{{"^%bigo_name %bigo_str %bigo_str[ ]*$"},
|
||||
{"^%bigo_name", MR_Not}, // Assert we we didn't only matched a name.
|
||||
{"^%rms_name %rms %rms[ ]*$", MR_Next}});
|
||||
AddCases(
|
||||
TC_JSONOut,
|
||||
{{"\"name\": \"%bigo_name\",$"},
|
||||
{"\"family_index\": " + std::to_string(family_index) + ",$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"%name\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": %int,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"BigO\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"cpu_coefficient\": %float,$", MR_Next},
|
||||
{"\"real_coefficient\": %float,$", MR_Next},
|
||||
{"\"big_o\": \"%bigo\",$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next},
|
||||
{"\"name\": \"%rms_name\",$"},
|
||||
{"\"family_index\": " + std::to_string(family_index) + ",$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"%name\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": %int,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"RMS\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"percentage\",$", MR_Next},
|
||||
{"\"rms\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
AddCases(TC_CSVOut, {{"^\"%bigo_name\",,%float,%float,%bigo,,,,,$"},
|
||||
{"^\"%bigo_name\"", MR_Not},
|
||||
{"^\"%rms_name\",,%float,%float,,,,,,$", MR_Next}});
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- Testing BigO O(1) --------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Complexity_O1(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
double tmp = static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) {
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
tmp *= static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
}
|
||||
|
||||
// always 1ns per iteration
|
||||
state.SetIterationTime(42 * 1e-9);
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O1)
|
||||
->Range(1, 1 << 18)
|
||||
->UseManualTime()
|
||||
->Complexity(benchmark::o1);
|
||||
BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->UseManualTime()->Complexity();
|
||||
BENCHMARK(BM_Complexity_O1)
|
||||
->Range(1, 1 << 18)
|
||||
->UseManualTime()
|
||||
->Complexity([](benchmark::IterationCount) { return 1.0; });
|
||||
|
||||
constexpr char one_test_name[] = "BM_Complexity_O1/manual_time";
|
||||
constexpr char big_o_1_test_name[] = "BM_Complexity_O1/manual_time_BigO";
|
||||
constexpr char rms_o_1_test_name[] = "BM_Complexity_O1/manual_time_RMS";
|
||||
constexpr char enum_auto_big_o_1[] = "\\([0-9]+\\)";
|
||||
constexpr char lambda_big_o_1[] = "f\\(N\\)";
|
||||
|
||||
// Add enum tests
|
||||
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
|
||||
enum_auto_big_o_1, /*family_index=*/0);
|
||||
|
||||
// Add auto tests
|
||||
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
|
||||
enum_auto_big_o_1, /*family_index=*/1);
|
||||
|
||||
// Add lambda tests
|
||||
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
|
||||
lambda_big_o_1, /*family_index=*/2);
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- Testing BigO O(N) --------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Complexity_O_N(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
double tmp = static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) {
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
tmp *= static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
}
|
||||
|
||||
// 1ns per iteration per entry
|
||||
state.SetIterationTime(static_cast<double>(state.range(0)) * 42 * 1e-9);
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1 << 20)
|
||||
->UseManualTime()
|
||||
->Complexity(benchmark::oN);
|
||||
BENCHMARK(BM_Complexity_O_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1 << 20)
|
||||
->UseManualTime()
|
||||
->Complexity();
|
||||
BENCHMARK(BM_Complexity_O_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1 << 20)
|
||||
->UseManualTime()
|
||||
->Complexity([](benchmark::IterationCount n) -> double {
|
||||
return static_cast<double>(n);
|
||||
});
|
||||
|
||||
constexpr char n_test_name[] = "BM_Complexity_O_N/manual_time";
|
||||
constexpr char big_o_n_test_name[] = "BM_Complexity_O_N/manual_time_BigO";
|
||||
constexpr char rms_o_n_test_name[] = "BM_Complexity_O_N/manual_time_RMS";
|
||||
constexpr char enum_auto_big_o_n[] = "N";
|
||||
constexpr char lambda_big_o_n[] = "f\\(N\\)";
|
||||
|
||||
// Add enum tests
|
||||
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
|
||||
enum_auto_big_o_n, /*family_index=*/3);
|
||||
|
||||
// Add auto tests
|
||||
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
|
||||
enum_auto_big_o_n, /*family_index=*/4);
|
||||
|
||||
// Add lambda tests
|
||||
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
|
||||
lambda_big_o_n, /*family_index=*/5);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Testing BigO O(NlgN) ------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
const double kLog2E = 1.44269504088896340736;
|
||||
void BM_Complexity_O_N_log_N(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
double tmp = static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) {
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
tmp *= static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
}
|
||||
|
||||
state.SetIterationTime(static_cast<double>(state.range(0)) * kLog2E *
|
||||
std::log(state.range(0)) * 42 * 1e-9);
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O_N_log_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1U << 24)
|
||||
->UseManualTime()
|
||||
->Complexity(benchmark::oNLogN);
|
||||
BENCHMARK(BM_Complexity_O_N_log_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1U << 24)
|
||||
->UseManualTime()
|
||||
->Complexity();
|
||||
BENCHMARK(BM_Complexity_O_N_log_N)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1 << 10, 1U << 24)
|
||||
->UseManualTime()
|
||||
->Complexity([](benchmark::IterationCount n) {
|
||||
return kLog2E * static_cast<double>(n) * std::log(static_cast<double>(n));
|
||||
});
|
||||
|
||||
constexpr char n_lg_n_test_name[] = "BM_Complexity_O_N_log_N/manual_time";
|
||||
constexpr char big_o_n_lg_n_test_name[] =
|
||||
"BM_Complexity_O_N_log_N/manual_time_BigO";
|
||||
constexpr char rms_o_n_lg_n_test_name[] =
|
||||
"BM_Complexity_O_N_log_N/manual_time_RMS";
|
||||
constexpr char enum_auto_big_o_n_lg_n[] = "NlgN";
|
||||
constexpr char lambda_big_o_n_lg_n[] = "f\\(N\\)";
|
||||
|
||||
// Add enum tests
|
||||
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
|
||||
rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n,
|
||||
/*family_index=*/6);
|
||||
|
||||
// NOTE: auto big-o is wron.g
|
||||
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
|
||||
rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n,
|
||||
/*family_index=*/7);
|
||||
|
||||
//// Add lambda tests
|
||||
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
|
||||
rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n,
|
||||
/*family_index=*/8);
|
||||
|
||||
// ========================================================================= //
|
||||
// -------- Testing formatting of Complexity with captured args ------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_ComplexityCaptureArgs(benchmark::State& state, int n) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
double tmp = static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) {
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
tmp *= static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
}
|
||||
|
||||
state.SetIterationTime(static_cast<double>(state.range(0)) * 42 * 1e-9);
|
||||
}
|
||||
state.SetComplexityN(n);
|
||||
}
|
||||
|
||||
BENCHMARK_CAPTURE(BM_ComplexityCaptureArgs, capture_test, 100)
|
||||
->UseManualTime()
|
||||
->Complexity(benchmark::oN)
|
||||
->Ranges({{1, 2}, {3, 4}});
|
||||
|
||||
const std::string complexity_capture_name =
|
||||
"BM_ComplexityCaptureArgs/capture_test/manual_time";
|
||||
|
||||
ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO",
|
||||
complexity_capture_name + "_RMS", "N",
|
||||
/*family_index=*/9);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "benchmark/benchmark_api.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSVC_LANG != 201402L
|
||||
// MSVC, even in C++11 mode, dooes not claim to be in C++11 mode.
|
||||
#error "Trying to compile C++11 test with wrong C++ standard"
|
||||
#endif // _MSVC_LANG
|
||||
#else // Non-MSVC
|
||||
#if __cplusplus != 201103L
|
||||
#error "Trying to compile C++11 test with wrong C++ standard"
|
||||
#endif // Non-MSVC
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
// Testing:
|
||||
// State::PauseTiming()
|
||||
// State::ResumeTiming()
|
||||
// Test that CHECK's within these function diagnose when they are called
|
||||
// outside of the KeepRunning() loop.
|
||||
//
|
||||
// NOTE: Users should NOT include or use src/check.h. This is only done in
|
||||
// order to test library internals.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../src/check.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
||||
#define TEST_HAS_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
void TestHandler() {
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
throw std::logic_error("");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void try_invalid_pause_resume(benchmark::State& state) {
|
||||
#if !defined(TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS) && \
|
||||
!defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
try {
|
||||
state.PauseTiming();
|
||||
std::abort();
|
||||
} catch (std::logic_error const&) {
|
||||
}
|
||||
try {
|
||||
state.ResumeTiming();
|
||||
std::abort();
|
||||
} catch (std::logic_error const&) {
|
||||
}
|
||||
#else
|
||||
(void)state; // avoid unused warning
|
||||
#endif
|
||||
}
|
||||
|
||||
void BM_diagnostic_test(benchmark::State& state) {
|
||||
static bool called_once = false;
|
||||
|
||||
if (!called_once) {
|
||||
try_invalid_pause_resume(state);
|
||||
}
|
||||
|
||||
for (auto _ : state) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
|
||||
if (!called_once) {
|
||||
try_invalid_pause_resume(state);
|
||||
}
|
||||
|
||||
called_once = true;
|
||||
}
|
||||
BENCHMARK(BM_diagnostic_test);
|
||||
|
||||
void BM_diagnostic_test_keep_running(benchmark::State& state) {
|
||||
static bool called_once = false;
|
||||
|
||||
if (!called_once) {
|
||||
try_invalid_pause_resume(state);
|
||||
}
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
|
||||
if (!called_once) {
|
||||
try_invalid_pause_resume(state);
|
||||
}
|
||||
|
||||
called_once = true;
|
||||
}
|
||||
BENCHMARK(BM_diagnostic_test_keep_running);
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef NDEBUG
|
||||
// This test is exercising functionality for debug builds, which are not
|
||||
// available in release builds. Skip the test if we are in that environment
|
||||
// to avoid a test failure.
|
||||
std::cout << "Diagnostic test disabled in release build\n";
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#else
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
benchmark::internal::GetAbortHandler() = &TestHandler;
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#undef NDEBUG
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
// Ok this test is super ugly. We want to check what happens with the file
|
||||
// reporter in the presence of DisplayAggregatesOnly().
|
||||
// We do not care about console output, the normal tests check that already.
|
||||
|
||||
namespace {
|
||||
void BM_SummaryRepeat(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->DisplayAggregatesOnly();
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
const std::string output = GetFileReporterOutput(argc, argv);
|
||||
|
||||
if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 7 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3\"") != 3 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_mean\"") != 1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_median\"") !=
|
||||
1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"") !=
|
||||
1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_cv\"") != 1) {
|
||||
std::cout << "Precondition mismatch. Expected to only find 8 "
|
||||
"occurrences of \"BM_SummaryRepeat/repeats:3\" substring:\n"
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_mean\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_median\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_stddev\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_cv\"\nThe entire "
|
||||
"output:\n";
|
||||
std::cout << output;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "benchmark/macros.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wreturn-type"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#endif
|
||||
BENCHMARK_DISABLE_DEPRECATED_WARNING
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern int ExternInt;
|
||||
extern int ExternInt2;
|
||||
extern int ExternInt3;
|
||||
extern int BigArray[2049];
|
||||
|
||||
const int ConstBigArray[2049]{};
|
||||
|
||||
inline int Add42(int x) { return x + 42; }
|
||||
|
||||
struct NotTriviallyCopyable {
|
||||
NotTriviallyCopyable();
|
||||
explicit NotTriviallyCopyable(int x) : value(x) {}
|
||||
NotTriviallyCopyable(NotTriviallyCopyable const&);
|
||||
int value;
|
||||
};
|
||||
|
||||
struct Large {
|
||||
int value;
|
||||
int data[2];
|
||||
};
|
||||
|
||||
struct ExtraLarge {
|
||||
int arr[2049];
|
||||
};
|
||||
}
|
||||
|
||||
extern ExtraLarge ExtraLargeObj;
|
||||
const ExtraLarge ConstExtraLargeObj{};
|
||||
|
||||
// CHECK-LABEL: test_with_rvalue:
|
||||
extern "C" void test_with_rvalue() {
|
||||
benchmark::DoNotOptimize(Add42(0));
|
||||
// CHECK: movl $42, %eax
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_large_rvalue:
|
||||
extern "C" void test_with_large_rvalue() {
|
||||
benchmark::DoNotOptimize(Large{ExternInt, {ExternInt, ExternInt}});
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]]
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_non_trivial_rvalue:
|
||||
extern "C" void test_with_non_trivial_rvalue() {
|
||||
benchmark::DoNotOptimize(NotTriviallyCopyable(ExternInt));
|
||||
// CHECK: mov{{l|q}} ExternInt(%rip)
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_lvalue:
|
||||
extern "C" void test_with_lvalue() {
|
||||
int x = 101;
|
||||
benchmark::DoNotOptimize(x);
|
||||
// CHECK-GNU: movl $101, %eax
|
||||
// CHECK-CLANG: movl $101, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_large_lvalue:
|
||||
extern "C" void test_with_large_lvalue() {
|
||||
Large L{ExternInt, {ExternInt, ExternInt}};
|
||||
benchmark::DoNotOptimize(L);
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_extra_large_lvalue_with_op:
|
||||
extern "C" void test_with_extra_large_lvalue_with_op() {
|
||||
ExtraLargeObj.arr[16] = 42;
|
||||
benchmark::DoNotOptimize(ExtraLargeObj);
|
||||
// CHECK: movl $42, ExtraLargeObj+64(%rip)
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_big_array_with_op
|
||||
extern "C" void test_with_big_array_with_op() {
|
||||
BigArray[16] = 42;
|
||||
benchmark::DoNotOptimize(BigArray);
|
||||
// CHECK: movl $42, BigArray+64(%rip)
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_non_trivial_lvalue:
|
||||
extern "C" void test_with_non_trivial_lvalue() {
|
||||
NotTriviallyCopyable NTC(ExternInt);
|
||||
benchmark::DoNotOptimize(NTC);
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_const_lvalue:
|
||||
extern "C" void test_with_const_lvalue() {
|
||||
const int x = 123;
|
||||
benchmark::DoNotOptimize(x);
|
||||
// CHECK: movl $123, %eax
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_large_const_lvalue:
|
||||
extern "C" void test_with_large_const_lvalue() {
|
||||
const Large L{ExternInt, {ExternInt, ExternInt}};
|
||||
benchmark::DoNotOptimize(L);
|
||||
// CHECK: ExternInt(%rip)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_const_extra_large_obj:
|
||||
extern "C" void test_with_const_extra_large_obj() {
|
||||
benchmark::DoNotOptimize(ConstExtraLargeObj);
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_const_big_array
|
||||
extern "C" void test_with_const_big_array() {
|
||||
benchmark::DoNotOptimize(ConstBigArray);
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_with_non_trivial_const_lvalue:
|
||||
extern "C" void test_with_non_trivial_const_lvalue() {
|
||||
const NotTriviallyCopyable Obj(ExternInt);
|
||||
benchmark::DoNotOptimize(Obj);
|
||||
// CHECK: mov{{q|l}} ExternInt(%rip)
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_div_by_two:
|
||||
extern "C" int test_div_by_two(int input) {
|
||||
int divisor = 2;
|
||||
benchmark::DoNotOptimize(divisor);
|
||||
return input / divisor;
|
||||
// CHECK: movl $2, [[DEST:.*]]
|
||||
// CHECK: idivl [[DEST]]
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_inc_integer:
|
||||
extern "C" int test_inc_integer() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < 5; ++i) benchmark::DoNotOptimize(++x);
|
||||
// CHECK: movl $1, [[DEST:.*]]
|
||||
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
||||
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
||||
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
||||
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
||||
// CHECK-CLANG: movl [[DEST]], %eax
|
||||
// CHECK: ret
|
||||
return x;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_pointer_rvalue
|
||||
extern "C" void test_pointer_rvalue() {
|
||||
// CHECK: movl $42, [[DEST:.*]]
|
||||
// CHECK: leaq [[DEST]], %rax
|
||||
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: ret
|
||||
int x = 42;
|
||||
benchmark::DoNotOptimize(&x);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_pointer_const_lvalue:
|
||||
extern "C" void test_pointer_const_lvalue() {
|
||||
// CHECK: movl $42, [[DEST:.*]]
|
||||
// CHECK: leaq [[DEST]], %rax
|
||||
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
||||
// CHECK: ret
|
||||
int x = 42;
|
||||
int* const xp = &x;
|
||||
benchmark::DoNotOptimize(xp);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_pointer_lvalue:
|
||||
extern "C" void test_pointer_lvalue() {
|
||||
// CHECK: movl $42, [[DEST:.*]]
|
||||
// CHECK: leaq [[DEST]], %rax
|
||||
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z+]+]])
|
||||
// CHECK: ret
|
||||
int x = 42;
|
||||
int* xp = &x;
|
||||
benchmark::DoNotOptimize(xp);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
namespace {
|
||||
#if defined(__GNUC__)
|
||||
std::int64_t double_up(std::int64_t x) __attribute__((const));
|
||||
#endif
|
||||
std::int64_t double_up(const std::int64_t x) { return x * 2; }
|
||||
} // namespace
|
||||
|
||||
// Using DoNotOptimize on types like BitRef seem to cause a lot of problems
|
||||
// with the inline assembly on both GCC and Clang.
|
||||
struct BitRef {
|
||||
int index;
|
||||
unsigned char& byte;
|
||||
|
||||
public:
|
||||
static BitRef Make() {
|
||||
static unsigned char arr[2] = {};
|
||||
BitRef b(1, arr[0]);
|
||||
return b;
|
||||
}
|
||||
|
||||
private:
|
||||
BitRef(int i, unsigned char& b) : index(i), byte(b) {}
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
// this test verifies compilation of DoNotOptimize() for some types
|
||||
|
||||
char buffer1[1] = "";
|
||||
benchmark::DoNotOptimize(buffer1);
|
||||
|
||||
char buffer2[2] = "";
|
||||
benchmark::DoNotOptimize(buffer2);
|
||||
|
||||
char buffer3[3] = "";
|
||||
benchmark::DoNotOptimize(buffer3);
|
||||
|
||||
char buffer8[8] = "";
|
||||
benchmark::DoNotOptimize(buffer8);
|
||||
|
||||
char buffer20[20] = "";
|
||||
benchmark::DoNotOptimize(buffer20);
|
||||
|
||||
char buffer1024[1024] = "";
|
||||
benchmark::DoNotOptimize(buffer1024);
|
||||
char* bptr = &buffer1024[0];
|
||||
benchmark::DoNotOptimize(bptr);
|
||||
|
||||
int x = 123;
|
||||
benchmark::DoNotOptimize(x);
|
||||
int* xp = &x;
|
||||
benchmark::DoNotOptimize(xp);
|
||||
benchmark::DoNotOptimize(x += 42);
|
||||
|
||||
std::int64_t y = double_up(x);
|
||||
benchmark::DoNotOptimize(y);
|
||||
|
||||
// These tests are to e
|
||||
BitRef lval = BitRef::Make();
|
||||
benchmark::DoNotOptimize(lval);
|
||||
|
||||
// Check that accept rvalue.
|
||||
benchmark::DoNotOptimize(BitRef::Make());
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& context) override {
|
||||
return ConsoleReporter::ReportContext(context);
|
||||
};
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
++count_;
|
||||
max_family_index_ = std::max(max_family_index_, report[0].family_index);
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
};
|
||||
|
||||
TestReporter() : count_(0), max_family_index_(0) {}
|
||||
|
||||
~TestReporter() override {}
|
||||
|
||||
int GetCount() const { return count_; }
|
||||
|
||||
int64_t GetMaxFamilyIndex() const { return max_family_index_; }
|
||||
|
||||
private:
|
||||
mutable int count_;
|
||||
mutable int64_t max_family_index_;
|
||||
};
|
||||
|
||||
void NoPrefix(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(NoPrefix);
|
||||
|
||||
void BM_Foo(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Foo);
|
||||
|
||||
void BM_Bar(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Bar);
|
||||
|
||||
void BM_FooBar(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_FooBar);
|
||||
|
||||
void BM_FooBa(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_FooBa);
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
bool list_only = false;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
list_only |= std::string(argv[i]).find("--benchmark_list_tests") !=
|
||||
std::string::npos;
|
||||
}
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
TestReporter test_reporter;
|
||||
const int64_t returned_count =
|
||||
static_cast<int64_t>(benchmark::RunSpecifiedBenchmarks(&test_reporter));
|
||||
|
||||
if (argc == 2) {
|
||||
// Make sure we ran all of the tests
|
||||
std::stringstream ss(argv[1]);
|
||||
int64_t expected_return = 0;
|
||||
ss >> expected_return;
|
||||
|
||||
if (returned_count != expected_return) {
|
||||
std::cerr << "ERROR: Expected " << expected_return
|
||||
<< " tests to match the filter but returned_count = "
|
||||
<< returned_count << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int64_t expected_reports = list_only ? 0 : expected_return;
|
||||
const int64_t reports_count = test_reporter.GetCount();
|
||||
if (reports_count != expected_reports) {
|
||||
std::cerr << "ERROR: Expected " << expected_reports
|
||||
<< " tests to be run but reported_count = " << reports_count
|
||||
<< '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int64_t max_family_index = test_reporter.GetMaxFamilyIndex();
|
||||
const int64_t num_families = reports_count == 0 ? 0 : 1 + max_family_index;
|
||||
if (num_families != expected_reports) {
|
||||
std::cerr << "ERROR: Expected " << expected_reports
|
||||
<< " test families to be run but num_families = "
|
||||
<< num_families << '\n';
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
#define FIXTURE_BECHMARK_NAME MyFixture
|
||||
|
||||
class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) override {
|
||||
if (state.thread_index() == 0) {
|
||||
assert(data.get() == nullptr);
|
||||
data.reset(new int(42));
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state) override {
|
||||
if (state.thread_index() == 0) {
|
||||
assert(data.get() != nullptr);
|
||||
data.reset();
|
||||
}
|
||||
}
|
||||
|
||||
~FIXTURE_BECHMARK_NAME() override { assert(data == nullptr); }
|
||||
|
||||
std::unique_ptr<int> data;
|
||||
};
|
||||
|
||||
BENCHMARK_F(FIXTURE_BECHMARK_NAME, Foo)(benchmark::State& st) {
|
||||
assert(data.get() != nullptr);
|
||||
assert(*data == 42);
|
||||
for (auto _ : st) {
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FIXTURE_BECHMARK_NAME, Bar)(benchmark::State& st) {
|
||||
if (st.thread_index() == 0) {
|
||||
assert(data.get() != nullptr);
|
||||
assert(*data == 42);
|
||||
}
|
||||
for (auto _ : st) {
|
||||
assert(data.get() != nullptr);
|
||||
assert(*data == 42);
|
||||
}
|
||||
st.SetItemsProcessed(st.range(0));
|
||||
}
|
||||
BENCHMARK_REGISTER_F(FIXTURE_BECHMARK_NAME, Bar)->Arg(42);
|
||||
BENCHMARK_REGISTER_F(FIXTURE_BECHMARK_NAME, Bar)->Arg(42)->ThreadPerCpu();
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "../src/timers.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/counter.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
const std::chrono::duration<double, std::milli> time_frame(50);
|
||||
const double time_frame_in_sec(
|
||||
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>(
|
||||
time_frame)
|
||||
.count());
|
||||
|
||||
void MyBusySpinwait() {
|
||||
const auto start = benchmark::ChronoClockNow();
|
||||
|
||||
while (true) {
|
||||
const auto now = benchmark::ChronoClockNow();
|
||||
const auto elapsed = now - start;
|
||||
|
||||
if (std::chrono::duration<double, std::chrono::seconds::period>(elapsed) >=
|
||||
time_frame) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES BEGIN ---------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// ========================================================================= //
|
||||
// BM_MainThread
|
||||
|
||||
void BM_MainThread(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
MyBusySpinwait();
|
||||
state.SetIterationTime(time_frame_in_sec);
|
||||
}
|
||||
state.counters["invtime"] =
|
||||
benchmark::Counter{1, benchmark::Counter::kIsRate};
|
||||
}
|
||||
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1);
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->UseRealTime();
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->UseManualTime();
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_MainThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2);
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->UseRealTime();
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->UseManualTime();
|
||||
BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_MainThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
// ========================================================================= //
|
||||
// BM_WorkerThread
|
||||
|
||||
void BM_WorkerThread(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
std::thread Worker(&MyBusySpinwait);
|
||||
Worker.join();
|
||||
state.SetIterationTime(time_frame_in_sec);
|
||||
}
|
||||
state.counters["invtime"] =
|
||||
benchmark::Counter{1, benchmark::Counter::kIsRate};
|
||||
}
|
||||
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1);
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->UseRealTime();
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->UseManualTime();
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_WorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_WorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2);
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->UseRealTime();
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->UseManualTime();
|
||||
BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_WorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_WorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
// ========================================================================= //
|
||||
// BM_MainThreadAndWorkerThread
|
||||
|
||||
void BM_MainThreadAndWorkerThread(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
std::thread Worker(&MyBusySpinwait);
|
||||
MyBusySpinwait();
|
||||
Worker.join();
|
||||
state.SetIterationTime(time_frame_in_sec);
|
||||
}
|
||||
state.counters["invtime"] =
|
||||
benchmark::Counter{1, benchmark::Counter::kIsRate};
|
||||
}
|
||||
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)->Iterations(1)->Threads(1);
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->UseManualTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)->Iterations(1)->Threads(2);
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->UseManualTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_MainThreadAndWorkerThread)
|
||||
->Iterations(1)
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------------- TEST CASES END ----------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
namespace {
|
||||
void BM_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty);
|
||||
} // end namespace
|
||||
@@ -0,0 +1,50 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
void BM_ostream(benchmark::State& state) {
|
||||
#if !defined(__GLIBCXX__) || defined(__GLIBC__) || defined(__DragonFly__)
|
||||
// libstdc++ only supports locale manipulations on GNU and
|
||||
// DragonflyBSD platforms at the time of writing, don't run the test
|
||||
// on other platforms when using libstdc++.
|
||||
std::locale::global(std::locale("en_US.UTF-8"));
|
||||
#endif
|
||||
while (state.KeepRunning()) {
|
||||
state.SetIterationTime(1e-6);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ostream)->UseManualTime()->Iterations(1000000);
|
||||
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ostream/iterations:1000000/manual_time"
|
||||
" %console_report$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ostream/iterations:1000000/manual_time\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": "
|
||||
"\"BM_ostream/iterations:1000000/manual_time\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": 1000000,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ostream/iterations:1000000/"
|
||||
"manual_time\",1000000,%float,%float,ns,,,,,$"}});
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
|
||||
#include <memory>
|
||||
#undef NDEBUG
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "../src/timers.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/counter.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const std::chrono::duration<double, std::milli> time_frame(50);
|
||||
const double time_frame_in_sec(
|
||||
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>(
|
||||
time_frame)
|
||||
.count());
|
||||
|
||||
void MyBusySpinwait() {
|
||||
const auto start = benchmark::ChronoClockNow();
|
||||
|
||||
while (true) {
|
||||
const auto now = benchmark::ChronoClockNow();
|
||||
const auto elapsed = now - start;
|
||||
|
||||
if (std::chrono::duration<double, std::chrono::seconds::period>(elapsed) >=
|
||||
time_frame) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int numRunThreadsCalled_ = 0;
|
||||
|
||||
class ManualThreadRunner : public benchmark::ThreadRunnerBase {
|
||||
public:
|
||||
explicit ManualThreadRunner(int num_threads)
|
||||
: pool(static_cast<size_t>(num_threads - 1)) {}
|
||||
|
||||
void RunThreads(const std::function<void(int)>& fn) final {
|
||||
for (std::size_t ti = 0; ti < pool.size(); ++ti) {
|
||||
pool[ti] = std::thread(fn, static_cast<int>(ti + 1));
|
||||
}
|
||||
|
||||
fn(0);
|
||||
|
||||
for (std::thread& thread : pool) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
++numRunThreadsCalled_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::thread> pool;
|
||||
};
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES BEGIN ---------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// ========================================================================= //
|
||||
// BM_ManualThreading
|
||||
// Creation of threads is done before the start of the measurement,
|
||||
// joining after the finish of the measurement.
|
||||
void BM_ManualThreading(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
MyBusySpinwait();
|
||||
state.SetIterationTime(time_frame_in_sec);
|
||||
}
|
||||
state.counters["invtime"] =
|
||||
benchmark::Counter{1, benchmark::Counter::kIsRate};
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1);
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1)
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1)
|
||||
->UseManualTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(1)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2);
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2)
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2)
|
||||
->UseManualTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime();
|
||||
BENCHMARK(BM_ManualThreading)
|
||||
->Iterations(1)
|
||||
->ThreadRunner([](int num_threads) {
|
||||
return std::make_unique<ManualThreadRunner>(num_threads);
|
||||
})
|
||||
->Threads(2)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseManualTime();
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------------- TEST CASES END ----------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
benchmark::Shutdown();
|
||||
assert(numRunThreadsCalled_ > 0);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<int, int> ConstructRandomMap(int size) {
|
||||
std::map<int, int> m;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
m.insert(std::make_pair(std::rand() % size, std::rand() % size));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Basic version.
|
||||
void BM_MapLookup(benchmark::State& state) {
|
||||
const int size = static_cast<int>(state.range(0));
|
||||
std::map<int, int> m;
|
||||
for (auto _ : state) {
|
||||
state.PauseTiming();
|
||||
m = ConstructRandomMap(size);
|
||||
state.ResumeTiming();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
auto it = m.find(std::rand() % size);
|
||||
benchmark::DoNotOptimize(it);
|
||||
}
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * size);
|
||||
}
|
||||
BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12);
|
||||
} // namespace
|
||||
|
||||
// Using fixtures.
|
||||
class MapFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& st) override {
|
||||
m = ConstructRandomMap(static_cast<int>(st.range(0)));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /*unused*/) override { m.clear(); }
|
||||
|
||||
std::map<int, int> m;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) {
|
||||
const int size = static_cast<int>(state.range(0));
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
auto it = m.find(std::rand() % size);
|
||||
benchmark::DoNotOptimize(it);
|
||||
}
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * size);
|
||||
}
|
||||
BENCHMARK_REGISTER_F(MapFixture, Lookup)->Range(1 << 3, 1 << 12);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/managers.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
class TestMemoryManager : public benchmark::MemoryManager {
|
||||
void Start() override {}
|
||||
void Stop(Result& result) override {
|
||||
result.num_allocs = 42;
|
||||
result.max_bytes_used = 42000;
|
||||
}
|
||||
};
|
||||
|
||||
void BM_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty);
|
||||
} // end namespace
|
||||
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_empty %console_report$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_empty\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"allocs_per_iter\": %float,$", MR_Next},
|
||||
{"\"max_bytes_used\": 42000$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}});
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
std::unique_ptr<benchmark::MemoryManager> mm(new TestMemoryManager());
|
||||
|
||||
benchmark::RegisterMemoryManager(mm.get());
|
||||
RunOutputTests(argc, argv);
|
||||
benchmark::RegisterMemoryManager(nullptr);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/managers.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using benchmark::Benchmark;
|
||||
using benchmark::ClearRegisteredBenchmarks;
|
||||
using benchmark::ConsoleReporter;
|
||||
using benchmark::MemoryManager;
|
||||
using benchmark::RegisterBenchmark;
|
||||
using benchmark::RunSpecifiedBenchmarks;
|
||||
using benchmark::State;
|
||||
|
||||
constexpr int N_REPETITIONS = 100;
|
||||
constexpr int N_ITERATIONS = 1;
|
||||
|
||||
int num_allocs = 0;
|
||||
int max_bytes_used = 0;
|
||||
int total_allocated_bytes = 0;
|
||||
int net_heap_growth = 0;
|
||||
|
||||
void reset() {
|
||||
num_allocs = 0;
|
||||
max_bytes_used = 0;
|
||||
total_allocated_bytes = 0;
|
||||
net_heap_growth = 0;
|
||||
}
|
||||
class TestMemoryManager : public MemoryManager {
|
||||
void Start() override {}
|
||||
void Stop(Result& result) override {
|
||||
result.num_allocs = num_allocs;
|
||||
result.net_heap_growth = net_heap_growth;
|
||||
result.max_bytes_used = max_bytes_used;
|
||||
result.total_allocated_bytes = total_allocated_bytes;
|
||||
|
||||
num_allocs += 1;
|
||||
max_bytes_used += 2;
|
||||
net_heap_growth += 4;
|
||||
total_allocated_bytes += 10;
|
||||
}
|
||||
};
|
||||
|
||||
class TestReporter : public ConsoleReporter {
|
||||
public:
|
||||
TestReporter() = default;
|
||||
virtual ~TestReporter() = default;
|
||||
|
||||
bool ReportContext(const Context& /*unused*/) override { return true; }
|
||||
|
||||
void PrintHeader(const Run&) override {}
|
||||
void PrintRunData(const Run& run) override {
|
||||
if (run.repetition_index == -1) return;
|
||||
if (!run.memory_result.memory_iterations) return;
|
||||
|
||||
store.push_back(run.memory_result);
|
||||
}
|
||||
|
||||
std::vector<MemoryManager::Result> store;
|
||||
};
|
||||
|
||||
class MemoryResultsTest : public testing::Test {
|
||||
public:
|
||||
Benchmark* bm;
|
||||
TestReporter reporter;
|
||||
|
||||
void SetUp() override {
|
||||
bm = RegisterBenchmark("BM", [](State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
});
|
||||
bm->Repetitions(N_REPETITIONS);
|
||||
bm->Iterations(N_ITERATIONS);
|
||||
reset();
|
||||
}
|
||||
void TearDown() override { ClearRegisteredBenchmarks(); }
|
||||
};
|
||||
|
||||
TEST_F(MemoryResultsTest, NoMMTest) {
|
||||
RunSpecifiedBenchmarks(&reporter);
|
||||
EXPECT_EQ(reporter.store.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MemoryResultsTest, ResultsTest) {
|
||||
auto mm = std::make_unique<TestMemoryManager>();
|
||||
RegisterMemoryManager(mm.get());
|
||||
|
||||
RunSpecifiedBenchmarks(&reporter);
|
||||
EXPECT_EQ(reporter.store.size(), N_REPETITIONS);
|
||||
|
||||
for (size_t i = 0; i < reporter.store.size(); i++) {
|
||||
EXPECT_EQ(reporter.store[i].num_allocs, static_cast<int64_t>(i));
|
||||
EXPECT_EQ(reporter.store[i].max_bytes_used, static_cast<int64_t>(i) * 2);
|
||||
EXPECT_EQ(reporter.store[i].net_heap_growth, static_cast<int64_t>(i) * 4);
|
||||
EXPECT_EQ(reporter.store[i].total_allocated_bytes,
|
||||
static_cast<int64_t>(i) * 10);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "../src/benchmark_runner.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(ParseMinTimeTest, InvalidInput) {
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
// Tests only runnable in debug mode (when BM_CHECK is enabled).
|
||||
#ifndef NDEBUG
|
||||
#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS
|
||||
ASSERT_DEATH_IF_SUPPORTED(
|
||||
{ benchmark::internal::ParseBenchMinTime("abc"); },
|
||||
"Malformed seconds value passed to --benchmark_min_time: `abc`");
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED(
|
||||
{ benchmark::internal::ParseBenchMinTime("123ms"); },
|
||||
"Malformed seconds value passed to --benchmark_min_time: `123ms`");
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED(
|
||||
{ benchmark::internal::ParseBenchMinTime("1z"); },
|
||||
"Malformed seconds value passed to --benchmark_min_time: `1z`");
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED(
|
||||
{ benchmark::internal::ParseBenchMinTime("1hs"); },
|
||||
"Malformed seconds value passed to --benchmark_min_time: `1hs`");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
namespace {
|
||||
class MultipleRangesFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
MultipleRangesFixture()
|
||||
: expectedValues({{1, 3, 5},
|
||||
{1, 3, 8},
|
||||
{1, 3, 15},
|
||||
{2, 3, 5},
|
||||
{2, 3, 8},
|
||||
{2, 3, 15},
|
||||
{1, 4, 5},
|
||||
{1, 4, 8},
|
||||
{1, 4, 15},
|
||||
{2, 4, 5},
|
||||
{2, 4, 8},
|
||||
{2, 4, 15},
|
||||
{1, 7, 5},
|
||||
{1, 7, 8},
|
||||
{1, 7, 15},
|
||||
{2, 7, 5},
|
||||
{2, 7, 8},
|
||||
{2, 7, 15},
|
||||
{7, 6, 3}}) {}
|
||||
|
||||
void SetUp(const ::benchmark::State& state) override {
|
||||
std::vector<int64_t> ranges = {state.range(0), state.range(1),
|
||||
state.range(2)};
|
||||
|
||||
assert(expectedValues.find(ranges) != expectedValues.end());
|
||||
|
||||
actualValues.insert(ranges);
|
||||
}
|
||||
|
||||
// NOTE: This is not TearDown as we want to check after _all_ runs are
|
||||
// complete.
|
||||
~MultipleRangesFixture() override {
|
||||
if (actualValues != expectedValues) {
|
||||
std::cout << "EXPECTED\n";
|
||||
for (const auto& v : expectedValues) {
|
||||
std::cout << "{";
|
||||
for (int64_t iv : v) {
|
||||
std::cout << iv << ", ";
|
||||
}
|
||||
std::cout << "}\n";
|
||||
}
|
||||
std::cout << "ACTUAL\n";
|
||||
for (const auto& v : actualValues) {
|
||||
std::cout << "{";
|
||||
for (int64_t iv : v) {
|
||||
std::cout << iv << ", ";
|
||||
}
|
||||
std::cout << "}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::vector<int64_t>> expectedValues;
|
||||
std::set<std::vector<int64_t>> actualValues;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(MultipleRangesFixture, Empty)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
int64_t product = state.range(0) * state.range(1) * state.range(2);
|
||||
for (int64_t x = 0; x < product; x++) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(MultipleRangesFixture, Empty)
|
||||
->RangeMultiplier(2)
|
||||
->Ranges({{1, 2}, {3, 7}, {5, 15}})
|
||||
->Args({7, 6, 3});
|
||||
|
||||
void BM_CheckDefaultArgument(benchmark::State& state) {
|
||||
// Test that the 'range()' without an argument is the same as 'range(0)'.
|
||||
assert(state.range() == state.range(0));
|
||||
assert(state.range() != state.range(1));
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CheckDefaultArgument)->Ranges({{1, 5}, {6, 10}});
|
||||
|
||||
void BM_MultipleRanges(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_MultipleRanges)->Ranges({{5, 5}, {6, 6}});
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/types.h"
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
namespace {
|
||||
void BM_basic(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
|
||||
void BM_basic_slow(benchmark::State& state) {
|
||||
std::chrono::milliseconds sleep_duration(state.range(0));
|
||||
for (auto _ : state) {
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(sleep_duration));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_basic);
|
||||
BENCHMARK(BM_basic)->Arg(42);
|
||||
BENCHMARK(BM_basic_slow)->Arg(10)->Unit(benchmark::kNanosecond);
|
||||
BENCHMARK(BM_basic_slow)->Arg(100)->Unit(benchmark::kMicrosecond);
|
||||
BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kMillisecond);
|
||||
BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kSecond);
|
||||
BENCHMARK(BM_basic)->Range(1, 8);
|
||||
BENCHMARK(BM_basic)->RangeMultiplier(2)->Range(1, 8);
|
||||
BENCHMARK(BM_basic)->DenseRange(10, 15);
|
||||
BENCHMARK(BM_basic)->Args({42, 42});
|
||||
BENCHMARK(BM_basic)->Ranges({{64, 512}, {64, 512}});
|
||||
BENCHMARK(BM_basic)->MinTime(0.7);
|
||||
BENCHMARK(BM_basic)->MinWarmUpTime(0.8);
|
||||
BENCHMARK(BM_basic)->MinTime(0.1)->MinWarmUpTime(0.2);
|
||||
BENCHMARK(BM_basic)->UseRealTime();
|
||||
BENCHMARK(BM_basic)->ThreadRange(2, 4);
|
||||
BENCHMARK(BM_basic)->ThreadPerCpu();
|
||||
BENCHMARK(BM_basic)->Repetitions(3);
|
||||
BENCHMARK(BM_basic)
|
||||
->RangeMultiplier(std::numeric_limits<int>::max())
|
||||
->Range(std::numeric_limits<int64_t>::min(),
|
||||
std::numeric_limits<int64_t>::max());
|
||||
|
||||
// Negative ranges
|
||||
BENCHMARK(BM_basic)->Range(-64, -1);
|
||||
BENCHMARK(BM_basic)->RangeMultiplier(4)->Range(-8, 8);
|
||||
BENCHMARK(BM_basic)->DenseRange(-2, 2, 1);
|
||||
BENCHMARK(BM_basic)->Ranges({{-64, 1}, {-8, -1}});
|
||||
|
||||
void CustomArgs(benchmark::Benchmark* b) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
b->Arg(i);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_basic)->Apply(CustomArgs);
|
||||
|
||||
void BM_explicit_iteration_count(benchmark::State& state) {
|
||||
// Test that benchmarks specified with an explicit iteration count are
|
||||
// only run once.
|
||||
static bool invoked_before = false;
|
||||
assert(!invoked_before);
|
||||
invoked_before = true;
|
||||
|
||||
// Test that the requested iteration count is respected.
|
||||
assert(state.max_iterations == 42);
|
||||
for (auto _ : state) {
|
||||
}
|
||||
assert(state.iterations() == state.max_iterations);
|
||||
assert(state.iterations() == 42);
|
||||
}
|
||||
BENCHMARK(BM_explicit_iteration_count)->Iterations(42);
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,213 @@
|
||||
#ifndef TEST_OUTPUT_TEST_H
|
||||
#define TEST_OUTPUT_TEST_H
|
||||
|
||||
#undef NDEBUG
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/re.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
|
||||
#define CONCAT2(x, y) x##y
|
||||
#define CONCAT(x, y) CONCAT2(x, y)
|
||||
|
||||
#define ADD_CASES(...) \
|
||||
const int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__)
|
||||
|
||||
#define SET_SUBSTITUTIONS(...) \
|
||||
const int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__)
|
||||
|
||||
enum MatchRules : uint8_t {
|
||||
MR_Default, // Skip non-matching lines until a match is found.
|
||||
MR_Next, // Match must occur on the next line.
|
||||
MR_Not // No line between the current position and the next match matches
|
||||
// the regex
|
||||
};
|
||||
|
||||
struct TestCase {
|
||||
TestCase(std::string re, int rule = MR_Default);
|
||||
|
||||
std::string regex_str;
|
||||
int match_rule;
|
||||
std::string substituted_regex;
|
||||
std::shared_ptr<benchmark::Regex> regex;
|
||||
};
|
||||
|
||||
enum TestCaseID : uint8_t {
|
||||
TC_ConsoleOut,
|
||||
TC_ConsoleErr,
|
||||
TC_JSONOut,
|
||||
TC_JSONErr,
|
||||
TC_CSVOut,
|
||||
TC_CSVErr,
|
||||
|
||||
TC_NumID // PRIVATE
|
||||
};
|
||||
|
||||
// Add a list of test cases to be run against the output specified by
|
||||
// 'ID'
|
||||
int AddCases(TestCaseID ID, std::initializer_list<TestCase> il);
|
||||
|
||||
// Add or set a list of substitutions to be performed on constructed regex's
|
||||
// See 'output_test_helper.cc' for a list of default substitutions.
|
||||
int SetSubstitutions(
|
||||
std::initializer_list<std::pair<std::string, std::string>> il);
|
||||
|
||||
// Run all output tests.
|
||||
void RunOutputTests(int argc, char* argv[]);
|
||||
|
||||
// Count the number of 'pat' substrings in the 'haystack' string.
|
||||
int SubstrCnt(const std::string& haystack, const std::string& pat);
|
||||
|
||||
// Run registered benchmarks with file reporter enabled, and return the content
|
||||
// outputted by the file reporter.
|
||||
std::string GetFileReporterOutput(int argc, char* argv[]);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Results checking ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
// Call this macro to register a benchmark for checking its results. This
|
||||
// should be all that's needed. It subscribes a function to check the (CSV)
|
||||
// results of a benchmark. This is done only after verifying that the output
|
||||
// strings are really as expected.
|
||||
// bm_name_pattern: a name or a regex pattern which will be matched against
|
||||
// all the benchmark names. Matching benchmarks
|
||||
// will be the subject of a call to checker_function
|
||||
// checker_function: should be of type ResultsCheckFn (see below)
|
||||
#define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \
|
||||
const size_t CONCAT(dummy, __LINE__) = \
|
||||
AddChecker(bm_name_pattern, checker_function)
|
||||
|
||||
struct Results;
|
||||
typedef std::function<void(Results const&)> ResultsCheckFn;
|
||||
|
||||
size_t AddChecker(const std::string& bm_name_pattern, const ResultsCheckFn& fn);
|
||||
|
||||
// Class holding the results of a benchmark.
|
||||
// It is passed in calls to checker functions.
|
||||
struct Results {
|
||||
// the benchmark name
|
||||
std::string name;
|
||||
// the benchmark fields
|
||||
std::map<std::string, std::string> values;
|
||||
|
||||
Results(const std::string& n) : name(n) {}
|
||||
|
||||
int NumThreads() const;
|
||||
|
||||
double NumIterations() const;
|
||||
|
||||
typedef enum : uint8_t { kCpuTime, kRealTime } BenchmarkTime;
|
||||
|
||||
// get cpu_time or real_time in seconds
|
||||
double GetTime(BenchmarkTime which) const;
|
||||
|
||||
// get the real_time duration of the benchmark in seconds.
|
||||
// it is better to use fuzzy float checks for this, as the float
|
||||
// ASCII formatting is lossy.
|
||||
double DurationRealTime() const {
|
||||
return NumIterations() * GetTime(kRealTime);
|
||||
}
|
||||
// get the cpu_time duration of the benchmark in seconds
|
||||
double DurationCPUTime() const { return NumIterations() * GetTime(kCpuTime); }
|
||||
|
||||
// get the string for a result by name, or nullptr if the name
|
||||
// is not found
|
||||
const std::string* Get(const std::string& entry_name) const {
|
||||
auto it = values.find(entry_name);
|
||||
if (it == values.end()) return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
// get a result by name, parsed as a specific type.
|
||||
// NOTE: for counters, use GetCounterAs instead.
|
||||
template <class T>
|
||||
T GetAs(const std::string& entry_name) const;
|
||||
|
||||
// counters are written as doubles, so they have to be read first
|
||||
// as a double, and only then converted to the asked type.
|
||||
template <class T>
|
||||
T GetCounterAs(const std::string& entry_name) const {
|
||||
double dval = GetAs<double>(entry_name);
|
||||
T tval = static_cast<T>(dval);
|
||||
return tval;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T Results::GetAs(const std::string& entry_name) const {
|
||||
auto* sv = Get(entry_name);
|
||||
BM_CHECK(sv != nullptr && !sv->empty());
|
||||
std::stringstream ss;
|
||||
ss << *sv;
|
||||
T out;
|
||||
ss >> out;
|
||||
BM_CHECK(!ss.fail());
|
||||
return out;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// Macros to help in result checking. Do not use them with arguments causing
|
||||
// side-effects.
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define CHECK_RESULT_VALUE_IMPL(entry, getfn, var_type, var_name, relationship, value) \
|
||||
CONCAT(BM_CHECK_, relationship) \
|
||||
(entry.getfn< var_type >(var_name), (value)) << "\n" \
|
||||
<< __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \
|
||||
<< __FILE__ << ":" << __LINE__ << ": " \
|
||||
<< "expected (" << #var_type << ")" << (var_name) \
|
||||
<< "=" << (entry).getfn< var_type >(var_name) \
|
||||
<< " to be " #relationship " to " << (value) << "\n"
|
||||
|
||||
// check with tolerance. eps_factor is the tolerance window, which is
|
||||
// interpreted relative to value (eg, 0.1 means 10% of value).
|
||||
#define CHECK_FLOAT_RESULT_VALUE_IMPL(entry, getfn, var_type, var_name, relationship, value, eps_factor) \
|
||||
CONCAT(BM_CHECK_FLOAT_, relationship) \
|
||||
(entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \
|
||||
<< __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \
|
||||
<< __FILE__ << ":" << __LINE__ << ": " \
|
||||
<< "expected (" << #var_type << ")" << (var_name) \
|
||||
<< "=" << (entry).getfn< var_type >(var_name) \
|
||||
<< " to be " #relationship " to " << (value) << "\n" \
|
||||
<< __FILE__ << ":" << __LINE__ << ": " \
|
||||
<< "with tolerance of " << (eps_factor) * (value) \
|
||||
<< " (" << (eps_factor)*100. << "%), " \
|
||||
<< "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \
|
||||
<< " (" << (((entry).getfn< var_type >(var_name) - (value)) \
|
||||
/ \
|
||||
((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \
|
||||
<< "%)"
|
||||
|
||||
#define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \
|
||||
CHECK_RESULT_VALUE_IMPL(entry, GetAs, var_type, var_name, relationship, value)
|
||||
|
||||
#define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \
|
||||
CHECK_RESULT_VALUE_IMPL(entry, GetCounterAs, var_type, var_name, relationship, value)
|
||||
|
||||
#define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \
|
||||
CHECK_FLOAT_RESULT_VALUE_IMPL(entry, GetAs, double, var_name, relationship, value, eps_factor)
|
||||
|
||||
#define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \
|
||||
CHECK_FLOAT_RESULT_VALUE_IMPL(entry, GetCounterAs, double, var_name, relationship, value, eps_factor)
|
||||
|
||||
// clang-format on
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- Misc Utilities ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
|
||||
const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?";
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif // TEST_OUTPUT_TEST_H
|
||||
@@ -0,0 +1,561 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <streambuf>
|
||||
|
||||
#include "../src/benchmark_api_internal.h"
|
||||
#include "../src/check.h" // NOTE: check.h is for internal use only!
|
||||
#include "../src/log.h" // NOTE: log.h is for internal use only
|
||||
#include "../src/re.h" // NOTE: re.h is for internal use only
|
||||
#include "output_test.h"
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------------ Internals -------------------------------- //
|
||||
// ========================================================================= //
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
using TestCaseList = std::vector<TestCase>;
|
||||
|
||||
// Use a vector because the order elements are added matters during iteration.
|
||||
// std::map/unordered_map don't guarantee that.
|
||||
// For example:
|
||||
// SetSubstitutions({{"%HelloWorld", "Hello"}, {"%Hello", "Hi"}});
|
||||
// Substitute("%HelloWorld") // Always expands to Hello.
|
||||
using SubMap = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
TestCaseList& GetTestCaseList(TestCaseID ID) {
|
||||
// Uses function-local statics to ensure initialization occurs
|
||||
// before first use.
|
||||
static TestCaseList lists[TC_NumID];
|
||||
return lists[ID];
|
||||
}
|
||||
|
||||
SubMap& GetSubstitutions() {
|
||||
// Don't use 'dec_re' from header because it may not yet be initialized.
|
||||
// clang-format off
|
||||
static std::string safe_dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?";
|
||||
static std::string time_re = "([0-9]+[.])?[0-9]+";
|
||||
static std::string percentage_re = "[0-9]+[.][0-9]{2}";
|
||||
static SubMap map = {
|
||||
{"%float", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"},
|
||||
// human-readable float
|
||||
{"%hrfloat", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kKMGTPEZYmunpfazy]?i?"},
|
||||
{"%percentage", percentage_re},
|
||||
{"%int", "[ ]*[0-9]+"},
|
||||
{" %s ", "[ ]+"},
|
||||
{"%time", "[ ]*" + time_re + "[ ]+ns"},
|
||||
{"%console_report", "[ ]*" + time_re + "[ ]+ns [ ]*" + time_re + "[ ]+ns [ ]*[0-9]+"},
|
||||
{"%console_percentage_report", "[ ]*" + percentage_re + "[ ]+% [ ]*" + percentage_re + "[ ]+% [ ]*[0-9]+"},
|
||||
{"%console_us_report", "[ ]*" + time_re + "[ ]+us [ ]*" + time_re + "[ ]+us [ ]*[0-9]+"},
|
||||
{"%console_ms_report", "[ ]*" + time_re + "[ ]+ms [ ]*" + time_re + "[ ]+ms [ ]*[0-9]+"},
|
||||
{"%console_s_report", "[ ]*" + time_re + "[ ]+s [ ]*" + time_re + "[ ]+s [ ]*[0-9]+"},
|
||||
{"%console_time_only_report", "[ ]*" + time_re + "[ ]+ns [ ]*" + time_re + "[ ]+ns"},
|
||||
{"%console_us_report", "[ ]*" + time_re + "[ ]+us [ ]*" + time_re + "[ ]+us [ ]*[0-9]+"},
|
||||
{"%console_us_time_only_report", "[ ]*" + time_re + "[ ]+us [ ]*" + time_re + "[ ]+us"},
|
||||
{"%csv_header",
|
||||
"name,iterations,real_time,cpu_time,time_unit,bytes_per_second,"
|
||||
"items_per_second,label,error_occurred,error_message"},
|
||||
{"%csv_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,,,"},
|
||||
{"%csv_us_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",us,,,,,"},
|
||||
{"%csv_ms_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ms,,,,,"},
|
||||
{"%csv_s_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",s,,,,,"},
|
||||
{"%csv_cv_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",,,,,,"},
|
||||
{"%csv_bytes_report",
|
||||
"[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + ",,,,"},
|
||||
{"%csv_items_report",
|
||||
"[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,," + safe_dec_re + ",,,"},
|
||||
{"%csv_bytes_items_report",
|
||||
"[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re +
|
||||
"," + safe_dec_re + ",,,"},
|
||||
{"%csv_label_report_begin", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,"},
|
||||
{"%csv_label_report_end", ",,"}};
|
||||
// clang-format on
|
||||
return map;
|
||||
}
|
||||
|
||||
std::string PerformSubstitutions(std::string source) {
|
||||
SubMap const& subs = GetSubstitutions();
|
||||
using SizeT = std::string::size_type;
|
||||
for (auto const& KV : subs) {
|
||||
SizeT pos = 0;
|
||||
SizeT next_start = 0;
|
||||
while ((pos = source.find(KV.first, next_start)) != std::string::npos) {
|
||||
next_start = pos + KV.second.size();
|
||||
source.replace(pos, KV.first.size(), KV.second);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
void CheckCase(std::stringstream& remaining_output, TestCase const& TC,
|
||||
TestCaseList const& not_checks) {
|
||||
std::string first_line;
|
||||
bool on_first = true;
|
||||
std::string line;
|
||||
while (!remaining_output.eof()) {
|
||||
BM_CHECK(remaining_output.good());
|
||||
std::getline(remaining_output, line);
|
||||
if (on_first) {
|
||||
first_line = line;
|
||||
on_first = false;
|
||||
}
|
||||
for (const auto& NC : not_checks) {
|
||||
BM_CHECK(!NC.regex->Match(line))
|
||||
<< "Unexpected match for line \"" << line << "\" for MR_Not regex \""
|
||||
<< NC.regex_str << "\""
|
||||
<< "\n actual regex string \"" << TC.substituted_regex << "\""
|
||||
<< "\n started matching near: " << first_line;
|
||||
}
|
||||
if (TC.regex->Match(line)) {
|
||||
return;
|
||||
}
|
||||
BM_CHECK(TC.match_rule != MR_Next)
|
||||
<< "Expected line \"" << line << "\" to match regex \"" << TC.regex_str
|
||||
<< "\""
|
||||
<< "\n actual regex string \"" << TC.substituted_regex << "\""
|
||||
<< "\n started matching near: " << first_line;
|
||||
}
|
||||
BM_CHECK(remaining_output.eof() == false)
|
||||
<< "End of output reached before match for regex \"" << TC.regex_str
|
||||
<< "\" was found"
|
||||
<< "\n actual regex string \"" << TC.substituted_regex << "\""
|
||||
<< "\n started matching near: " << first_line;
|
||||
}
|
||||
|
||||
void CheckCases(TestCaseList const& checks, std::stringstream& output) {
|
||||
std::vector<TestCase> not_checks;
|
||||
for (size_t i = 0; i < checks.size(); ++i) {
|
||||
const auto& TC = checks[i];
|
||||
if (TC.match_rule == MR_Not) {
|
||||
not_checks.push_back(TC);
|
||||
continue;
|
||||
}
|
||||
CheckCase(output, TC, not_checks);
|
||||
not_checks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class TestReporter : public benchmark::BenchmarkReporter {
|
||||
public:
|
||||
TestReporter(std::vector<benchmark::BenchmarkReporter*> reps)
|
||||
: reporters_(std::move(reps)) {}
|
||||
|
||||
bool ReportContext(const Context& context) override {
|
||||
bool last_ret = false;
|
||||
bool first = true;
|
||||
for (auto* rep : reporters_) {
|
||||
bool new_ret = rep->ReportContext(context);
|
||||
BM_CHECK(first || new_ret == last_ret)
|
||||
<< "Reports return different values for ReportContext";
|
||||
first = false;
|
||||
last_ret = new_ret;
|
||||
}
|
||||
(void)first;
|
||||
return last_ret;
|
||||
}
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
for (auto* rep : reporters_) {
|
||||
rep->ReportRuns(report);
|
||||
}
|
||||
}
|
||||
void Finalize() override {
|
||||
for (auto* rep : reporters_) {
|
||||
rep->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<benchmark::BenchmarkReporter*> reporters_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
// ========================================================================= //
|
||||
// -------------------------- Results checking ----------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Utility class to manage subscribers for checking benchmark results.
|
||||
// It works by parsing the CSV output to read the results.
|
||||
class ResultsChecker {
|
||||
public:
|
||||
struct PatternAndFn : public TestCase { // reusing TestCase for its regexes
|
||||
PatternAndFn(const std::string& rx, ResultsCheckFn fn_)
|
||||
: TestCase(rx), fn(std::move(fn_)) {}
|
||||
ResultsCheckFn fn;
|
||||
};
|
||||
|
||||
std::vector<PatternAndFn> check_patterns;
|
||||
std::vector<Results> results;
|
||||
std::vector<std::string> field_names;
|
||||
|
||||
void Add(const std::string& entry_pattern, const ResultsCheckFn& fn);
|
||||
|
||||
void CheckResults(std::stringstream& output);
|
||||
|
||||
private:
|
||||
void SetHeader_(const std::string& csv_header);
|
||||
void SetValues_(const std::string& entry_csv_line);
|
||||
|
||||
std::vector<std::string> SplitCsv_(const std::string& line) const;
|
||||
};
|
||||
|
||||
namespace {
|
||||
// store the static ResultsChecker in a function to prevent initialization
|
||||
// order problems
|
||||
ResultsChecker& GetResultsChecker() {
|
||||
static ResultsChecker rc;
|
||||
return rc;
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
// add a results checker for a benchmark
|
||||
void ResultsChecker::Add(const std::string& entry_pattern,
|
||||
const ResultsCheckFn& fn) {
|
||||
check_patterns.emplace_back(entry_pattern, fn);
|
||||
}
|
||||
|
||||
// check the results of all subscribed benchmarks
|
||||
void ResultsChecker::CheckResults(std::stringstream& output) {
|
||||
// first reset the stream to the start
|
||||
{
|
||||
auto start = std::stringstream::pos_type(0);
|
||||
// clear before calling tellg()
|
||||
output.clear();
|
||||
// seek to zero only when needed
|
||||
if (output.tellg() > start) {
|
||||
output.seekg(start);
|
||||
}
|
||||
// and just in case
|
||||
output.clear();
|
||||
}
|
||||
// now go over every line and publish it to the ResultsChecker
|
||||
std::string line;
|
||||
bool on_first = true;
|
||||
while (!output.eof()) {
|
||||
BM_CHECK(output.good());
|
||||
std::getline(output, line);
|
||||
if (on_first) {
|
||||
SetHeader_(line); // this is important
|
||||
on_first = false;
|
||||
continue;
|
||||
}
|
||||
SetValues_(line);
|
||||
}
|
||||
// finally we can call the subscribed check functions
|
||||
for (const auto& p : check_patterns) {
|
||||
BM_VLOG(2) << "--------------------------------\n";
|
||||
BM_VLOG(2) << "checking for benchmarks matching " << p.regex_str << "...\n";
|
||||
for (const auto& r : results) {
|
||||
if (!p.regex->Match(r.name)) {
|
||||
BM_VLOG(2) << p.regex_str << " is not matched by " << r.name << "\n";
|
||||
continue;
|
||||
}
|
||||
BM_VLOG(2) << p.regex_str << " is matched by " << r.name << "\n";
|
||||
BM_VLOG(1) << "Checking results of " << r.name << ": ... \n";
|
||||
p.fn(r);
|
||||
BM_VLOG(1) << "Checking results of " << r.name << ": OK.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prepare for the names in this header
|
||||
void ResultsChecker::SetHeader_(const std::string& csv_header) {
|
||||
field_names = SplitCsv_(csv_header);
|
||||
}
|
||||
|
||||
// set the values for a benchmark
|
||||
void ResultsChecker::SetValues_(const std::string& entry_csv_line) {
|
||||
if (entry_csv_line.empty()) {
|
||||
return;
|
||||
} // some lines are empty
|
||||
BM_CHECK(!field_names.empty());
|
||||
auto vals = SplitCsv_(entry_csv_line);
|
||||
BM_CHECK_EQ(vals.size(), field_names.size());
|
||||
results.emplace_back(vals[0]); // vals[0] is the benchmark name
|
||||
auto& entry = results.back();
|
||||
for (size_t i = 1, e = vals.size(); i < e; ++i) {
|
||||
entry.values[field_names[i]] = vals[i];
|
||||
}
|
||||
}
|
||||
|
||||
// a quick'n'dirty csv splitter (eliminating quotes)
|
||||
std::vector<std::string> ResultsChecker::SplitCsv_(
|
||||
const std::string& line) const {
|
||||
std::vector<std::string> out;
|
||||
if (line.empty()) {
|
||||
return out;
|
||||
}
|
||||
if (!field_names.empty()) {
|
||||
out.reserve(field_names.size());
|
||||
}
|
||||
size_t prev = 0;
|
||||
size_t pos = line.find_first_of(',');
|
||||
size_t curr = pos;
|
||||
while (pos != std::string::npos) {
|
||||
BM_CHECK(curr > 0);
|
||||
if (line[prev] == '"') {
|
||||
++prev;
|
||||
}
|
||||
if (line[curr - 1] == '"') {
|
||||
--curr;
|
||||
}
|
||||
out.push_back(line.substr(prev, curr - prev));
|
||||
prev = pos + 1;
|
||||
pos = line.find_first_of(',', pos + 1);
|
||||
curr = pos;
|
||||
}
|
||||
curr = line.size();
|
||||
if (line[prev] == '"') {
|
||||
++prev;
|
||||
}
|
||||
if (line[curr - 1] == '"') {
|
||||
--curr;
|
||||
}
|
||||
out.push_back(line.substr(prev, curr - prev));
|
||||
return out;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
size_t AddChecker(const std::string& bm_name, const ResultsCheckFn& fn) {
|
||||
auto& rc = internal::GetResultsChecker();
|
||||
rc.Add(bm_name, fn);
|
||||
return rc.results.size();
|
||||
}
|
||||
|
||||
int Results::NumThreads() const {
|
||||
auto pos = name.find("/threads:");
|
||||
if (pos == std::string::npos) {
|
||||
return 1;
|
||||
}
|
||||
auto end = name.find('/', pos + 9);
|
||||
std::stringstream ss;
|
||||
ss << name.substr(pos + 9, end);
|
||||
int num = 1;
|
||||
ss >> num;
|
||||
BM_CHECK(!ss.fail());
|
||||
return num;
|
||||
}
|
||||
|
||||
double Results::NumIterations() const { return GetAs<double>("iterations"); }
|
||||
|
||||
double Results::GetTime(BenchmarkTime which) const {
|
||||
BM_CHECK(which == kCpuTime || which == kRealTime);
|
||||
const char* which_str = which == kCpuTime ? "cpu_time" : "real_time";
|
||||
double val = GetAs<double>(which_str);
|
||||
const auto* unit = Get("time_unit");
|
||||
BM_CHECK(unit);
|
||||
if (*unit == "ns") {
|
||||
return val * 1.e-9;
|
||||
}
|
||||
if (*unit == "us") {
|
||||
return val * 1.e-6;
|
||||
}
|
||||
if (*unit == "ms") {
|
||||
return val * 1.e-3;
|
||||
}
|
||||
if (*unit == "s") {
|
||||
return val;
|
||||
}
|
||||
BM_CHECK(1 == 0) << "unknown time unit: " << *unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ========================================================================= //
|
||||
// -------------------------- Public API Definitions------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
TestCase::TestCase(std::string re, int rule)
|
||||
: regex_str(std::move(re)),
|
||||
match_rule(rule),
|
||||
substituted_regex(internal::PerformSubstitutions(regex_str)),
|
||||
regex(std::make_shared<benchmark::Regex>()) {
|
||||
std::string err_str;
|
||||
regex->Init(substituted_regex, &err_str);
|
||||
BM_CHECK(err_str.empty())
|
||||
<< "Could not construct regex \"" << substituted_regex << "\""
|
||||
<< "\n originally \"" << regex_str << "\""
|
||||
<< "\n got error: " << err_str;
|
||||
}
|
||||
|
||||
int AddCases(TestCaseID ID, std::initializer_list<TestCase> il) {
|
||||
auto& L = internal::GetTestCaseList(ID);
|
||||
L.insert(L.end(), il);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetSubstitutions(
|
||||
std::initializer_list<std::pair<std::string, std::string>> il) {
|
||||
auto& subs = internal::GetSubstitutions();
|
||||
for (auto KV : il) {
|
||||
bool exists = false;
|
||||
KV.second = internal::PerformSubstitutions(KV.second);
|
||||
for (auto& EKV : subs) {
|
||||
if (EKV.first == KV.first) {
|
||||
EKV.second = std::move(KV.second);
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
subs.push_back(std::move(KV));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Disable deprecated warnings temporarily because we need to reference
|
||||
// CSVReporter but don't want to trigger -Werror=-Wdeprecated-declarations
|
||||
BENCHMARK_DISABLE_DEPRECATED_WARNING
|
||||
|
||||
void RunOutputTests(int argc, char* argv[]) {
|
||||
using internal::GetTestCaseList;
|
||||
benchmark::Initialize(&argc, argv);
|
||||
auto options = benchmark::internal::GetOutputOptions(/*force_no_color*/ true);
|
||||
benchmark::ConsoleReporter CR(options);
|
||||
benchmark::JSONReporter JR;
|
||||
benchmark::CSVReporter CSVR;
|
||||
struct ReporterTest {
|
||||
std::string name;
|
||||
std::vector<TestCase>& output_cases;
|
||||
std::vector<TestCase>& error_cases;
|
||||
benchmark::BenchmarkReporter& reporter;
|
||||
std::stringstream out_stream;
|
||||
std::stringstream err_stream;
|
||||
|
||||
ReporterTest(const std::string& n, std::vector<TestCase>& out_tc,
|
||||
std::vector<TestCase>& err_tc,
|
||||
benchmark::BenchmarkReporter& br)
|
||||
: name(n), output_cases(out_tc), error_cases(err_tc), reporter(br) {
|
||||
reporter.SetOutputStream(&out_stream);
|
||||
reporter.SetErrorStream(&err_stream);
|
||||
}
|
||||
} TestCases[] = {
|
||||
{std::string("ConsoleReporter"), GetTestCaseList(TC_ConsoleOut),
|
||||
GetTestCaseList(TC_ConsoleErr), CR},
|
||||
{std::string("JSONReporter"), GetTestCaseList(TC_JSONOut),
|
||||
GetTestCaseList(TC_JSONErr), JR},
|
||||
{std::string("CSVReporter"), GetTestCaseList(TC_CSVOut),
|
||||
GetTestCaseList(TC_CSVErr), CSVR},
|
||||
};
|
||||
|
||||
// Create the test reporter and run the benchmarks.
|
||||
std::cout << "Running benchmarks...\n";
|
||||
internal::TestReporter test_rep({&CR, &JR, &CSVR});
|
||||
benchmark::RunSpecifiedBenchmarks(&test_rep);
|
||||
|
||||
for (auto& rep_test : TestCases) {
|
||||
std::string msg =
|
||||
std::string("\nTesting ") + rep_test.name + std::string(" Output\n");
|
||||
std::string banner(msg.size() - 1, '-');
|
||||
std::cout << banner << msg << banner << "\n";
|
||||
|
||||
std::cerr << rep_test.err_stream.str();
|
||||
std::cout << rep_test.out_stream.str();
|
||||
|
||||
internal::CheckCases(rep_test.error_cases, rep_test.err_stream);
|
||||
internal::CheckCases(rep_test.output_cases, rep_test.out_stream);
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// now that we know the output is as expected, we can dispatch
|
||||
// the checks to subscribees.
|
||||
auto& csv = TestCases[2];
|
||||
// would use == but gcc spits a warning
|
||||
BM_CHECK(csv.name == std::string("CSVReporter"));
|
||||
internal::GetResultsChecker().CheckResults(csv.out_stream);
|
||||
}
|
||||
|
||||
BENCHMARK_RESTORE_DEPRECATED_WARNING
|
||||
|
||||
int SubstrCnt(const std::string& haystack, const std::string& pat) {
|
||||
if (pat.length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (size_t offset = haystack.find(pat); offset != std::string::npos;
|
||||
offset = haystack.find(pat, offset + pat.length())) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
namespace {
|
||||
char ToHex(int ch) {
|
||||
return ch < 10 ? static_cast<char>('0' + ch)
|
||||
: static_cast<char>('a' + (ch - 10));
|
||||
}
|
||||
|
||||
char RandomHexChar() {
|
||||
static std::mt19937 rd{std::random_device{}()};
|
||||
static std::uniform_int_distribution<int> mrand{0, 15};
|
||||
return ToHex(mrand(rd));
|
||||
}
|
||||
|
||||
std::string GetRandomFileName() {
|
||||
std::string model = "test.%%%%%%";
|
||||
for (auto& ch : model) {
|
||||
if (ch == '%') {
|
||||
ch = RandomHexChar();
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
bool FileExists(std::string const& name) {
|
||||
std::ifstream in(name.c_str());
|
||||
return in.good();
|
||||
}
|
||||
|
||||
std::string GetTempFileName() {
|
||||
// This function attempts to avoid race conditions where two tests
|
||||
// create the same file at the same time. However, it still introduces races
|
||||
// similar to tmpnam.
|
||||
int retries = 3;
|
||||
while (--retries != 0) {
|
||||
std::string name = GetRandomFileName();
|
||||
if (!FileExists(name)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
std::cerr << "Failed to create unique temporary file name\n";
|
||||
std::flush(std::cerr);
|
||||
std::exit(1);
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
std::string GetFileReporterOutput(int argc, char* argv[]) {
|
||||
std::vector<char*> new_argv(argv, argv + argc);
|
||||
assert(static_cast<decltype(new_argv)::size_type>(argc) == new_argv.size());
|
||||
|
||||
std::string tmp_file_name = GetTempFileName();
|
||||
std::cout << "Will be using this as the tmp file: " << tmp_file_name << '\n';
|
||||
|
||||
std::string tmp = "--benchmark_out=";
|
||||
tmp += tmp_file_name;
|
||||
new_argv.emplace_back(const_cast<char*>(tmp.c_str()));
|
||||
|
||||
argc = static_cast<int>(new_argv.size());
|
||||
|
||||
benchmark::Initialize(&argc, new_argv.data());
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
// Read the output back from the file, and delete the file.
|
||||
std::ifstream tmp_stream(tmp_file_name);
|
||||
std::string output = std::string((std::istreambuf_iterator<char>(tmp_stream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
std::remove(tmp_file_name.c_str());
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "benchmark/macros.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
namespace {
|
||||
// Simulate an overloaded function name.
|
||||
// This version does nothing and is just here to create ambiguity for
|
||||
// MyOverloadedBenchmark.
|
||||
BENCHMARK_UNUSED void MyOverloadedBenchmark() {}
|
||||
|
||||
// This is the actual benchmark function we want to register.
|
||||
// It has the signature void(benchmark::State&) required by the library.
|
||||
void MyOverloadedBenchmark(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
|
||||
// This macro invocation should compile correctly if benchmark.h
|
||||
// contains the fix (using static_cast), but would fail to compile
|
||||
// if the benchmark name were ambiguous (e.g., when using + or no cast
|
||||
// with an overloaded function).
|
||||
BENCHMARK(MyOverloadedBenchmark);
|
||||
|
||||
// Also test BENCHMARK_TEMPLATE with an overloaded name.
|
||||
template <int N>
|
||||
void MyTemplatedOverloadedBenchmark() {}
|
||||
|
||||
template <int N>
|
||||
void MyTemplatedOverloadedBenchmark(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(MyTemplatedOverloadedBenchmark, 1);
|
||||
} // end namespace
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,401 @@
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/perf_counters.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#ifndef GTEST_SKIP
|
||||
struct MsgHandler {
|
||||
void operator=(std::ostream&) {}
|
||||
};
|
||||
#define GTEST_SKIP() return MsgHandler() = std::cout
|
||||
#endif
|
||||
|
||||
using benchmark::internal::PerfCounters;
|
||||
using benchmark::internal::PerfCountersMeasurement;
|
||||
using benchmark::internal::PerfCounterValues;
|
||||
using ::testing::AllOf;
|
||||
using ::testing::Gt;
|
||||
using ::testing::Lt;
|
||||
|
||||
namespace {
|
||||
const char kGenericPerfEvent1[] = "CYCLES";
|
||||
const char kGenericPerfEvent2[] = "INSTRUCTIONS";
|
||||
|
||||
std::set<std::string> UniqueCounterNames(const PerfCounters& counters) {
|
||||
return {counters.names().begin(), counters.names().end()};
|
||||
}
|
||||
|
||||
bool HasRequiredPerfCounters(const std::vector<std::string>& names) {
|
||||
if (!PerfCounters::kSupported) {
|
||||
return false;
|
||||
}
|
||||
auto counters = PerfCounters::Create(names);
|
||||
auto actual_names = UniqueCounterNames(counters);
|
||||
for (const auto& name : names) {
|
||||
if (actual_names.find(name) == actual_names.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, Init) {
|
||||
EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported);
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, OneCounter) {
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
auto counter = PerfCounters::Create({kGenericPerfEvent1});
|
||||
EXPECT_EQ(UniqueCounterNames(counter).size(), 1);
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, NegativeTest) {
|
||||
if (!PerfCounters::kSupported) {
|
||||
EXPECT_FALSE(PerfCounters::Initialize());
|
||||
return;
|
||||
}
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent2, kGenericPerfEvent1})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
// Safety checks
|
||||
// Create() will always create a valid object, even if passed no or
|
||||
// wrong arguments as the new behavior is to warn and drop unsupported
|
||||
// counters
|
||||
EXPECT_EQ(PerfCounters::Create({}).num_counters(), 0);
|
||||
EXPECT_EQ(PerfCounters::Create({""}).num_counters(), 0);
|
||||
EXPECT_EQ(PerfCounters::Create({"not a counter name"}).num_counters(), 0);
|
||||
{
|
||||
// Try sneaking in a bad egg to see if it is filtered out. The
|
||||
// number of counters has to be two, not zero
|
||||
auto counter =
|
||||
PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1});
|
||||
auto names = UniqueCounterNames(counter);
|
||||
EXPECT_EQ(names.size(), 2);
|
||||
EXPECT_EQ(names,
|
||||
std::set<std::string>({kGenericPerfEvent2, kGenericPerfEvent1}));
|
||||
}
|
||||
{
|
||||
// Try sneaking in an outrageous counter, like a fat finger mistake
|
||||
auto counter = PerfCounters::Create(
|
||||
{kGenericPerfEvent2, "not a counter name", kGenericPerfEvent1});
|
||||
auto names = UniqueCounterNames(counter);
|
||||
EXPECT_EQ(names.size(), 2);
|
||||
EXPECT_EQ(names,
|
||||
std::set<std::string>({kGenericPerfEvent2, kGenericPerfEvent1}));
|
||||
}
|
||||
{
|
||||
// Finally try a golden input - it should like both of them
|
||||
EXPECT_EQ(UniqueCounterNames(PerfCounters::Create(
|
||||
{kGenericPerfEvent1, kGenericPerfEvent2}))
|
||||
.size(),
|
||||
2);
|
||||
}
|
||||
{
|
||||
// Add a bad apple in the end of the chain to check the edges
|
||||
auto counter = PerfCounters::Create(
|
||||
{kGenericPerfEvent1, kGenericPerfEvent2, "bad event name"});
|
||||
auto names = UniqueCounterNames(counter);
|
||||
EXPECT_EQ(names.size(), 2);
|
||||
EXPECT_EQ(names,
|
||||
std::set<std::string>({kGenericPerfEvent1, kGenericPerfEvent2}));
|
||||
}
|
||||
}
|
||||
|
||||
static std::map<std::string, uint64_t> SnapshotAndCombine(
|
||||
PerfCounters& counters) {
|
||||
PerfCounterValues values(counters.num_counters());
|
||||
std::map<std::string, uint64_t> value_map;
|
||||
|
||||
if (counters.Snapshot(&values)) {
|
||||
for (size_t i = 0; i != counters.num_counters(); ++i) {
|
||||
value_map[counters.names()[i]] += values[i];
|
||||
}
|
||||
}
|
||||
return value_map;
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, Read1Counter) {
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
auto counters = PerfCounters::Create({kGenericPerfEvent1});
|
||||
auto values1 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values1.size(), 1);
|
||||
EXPECT_GT(values1.begin()->second, 0);
|
||||
auto values2 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values2.size(), 1);
|
||||
EXPECT_GT(values2.begin()->second, 0);
|
||||
EXPECT_GT(values2.begin()->second, values1.begin()->second);
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, Read1CounterEachCPU) {
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
#ifdef __linux__
|
||||
cpu_set_t saved_set;
|
||||
if (sched_getaffinity(0, sizeof(saved_set), &saved_set) != 0) {
|
||||
// This can happen e.g. if there are more than CPU_SETSIZE CPUs.
|
||||
GTEST_SKIP() << "Could not save CPU affinity mask.";
|
||||
}
|
||||
|
||||
for (size_t cpu = 0; cpu != CPU_SETSIZE; ++cpu) {
|
||||
cpu_set_t set;
|
||||
CPU_ZERO(&set);
|
||||
CPU_SET(cpu, &set);
|
||||
if (sched_setaffinity(0, sizeof(set), &set) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto counters = PerfCounters::Create({kGenericPerfEvent1});
|
||||
auto values1 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values1.size(), 1);
|
||||
EXPECT_GT(values1.begin()->second, 0);
|
||||
auto values2 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values2.size(), 1);
|
||||
EXPECT_GT(values2.begin()->second, 0);
|
||||
EXPECT_GT(values2.begin()->second, values1.begin()->second);
|
||||
}
|
||||
|
||||
EXPECT_EQ(sched_setaffinity(0, sizeof(saved_set), &saved_set), 0);
|
||||
#else
|
||||
GTEST_SKIP() << "Test skipped on non-Linux.";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, Read2Counters) {
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
auto counters =
|
||||
PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2});
|
||||
auto values1 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values1.size(), 2);
|
||||
for (auto& kv : values1) {
|
||||
EXPECT_GT(kv.second, 0);
|
||||
}
|
||||
auto values2 = SnapshotAndCombine(counters);
|
||||
EXPECT_EQ(values1.size(), 2);
|
||||
for (auto& kv : values2) {
|
||||
EXPECT_GT(kv.second, 0);
|
||||
EXPECT_GT(kv.second, values1[kv.first]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, ReopenExistingCounters) {
|
||||
// This test works in recent and old Intel hardware, Pixel 3, and Pixel 6.
|
||||
// However we cannot make assumptions beyond 2 HW counters due to Pixel 6.
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
std::vector<std::string> kMetrics({kGenericPerfEvent1});
|
||||
std::vector<PerfCounters> counters(2);
|
||||
for (auto& counter : counters) {
|
||||
counter = PerfCounters::Create(kMetrics);
|
||||
}
|
||||
PerfCounterValues values(counters[0].num_counters());
|
||||
EXPECT_TRUE(counters[0].Snapshot(&values));
|
||||
EXPECT_TRUE(counters[1].Snapshot(&values));
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, CreateExistingMeasurements) {
|
||||
// The test works (i.e. causes read to fail) for the assumptions
|
||||
// about hardware capabilities (i.e. small number (2) hardware
|
||||
// counters) at this date,
|
||||
// the same as previous test ReopenExistingCounters.
|
||||
if (!PerfCounters::kSupported) {
|
||||
GTEST_SKIP() << "Test skipped because libpfm is not supported.";
|
||||
}
|
||||
|
||||
// This means we will try 10 counters but we can only guarantee
|
||||
// for sure at this time that only 3 will work. Perhaps in the future
|
||||
// we could use libpfm to query for the hardware limits on this
|
||||
// particular platform.
|
||||
const int kMaxCounters = 10;
|
||||
const int kMinValidCounters = 2;
|
||||
|
||||
// Let's use a ubiquitous counter that is guaranteed to work
|
||||
// on all platforms
|
||||
const std::vector<std::string> kMetrics{"cycles"};
|
||||
if (!HasRequiredPerfCounters(kMetrics)) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
|
||||
// Cannot create a vector of actual objects because the
|
||||
// copy constructor of PerfCounters is deleted - and so is
|
||||
// implicitly deleted on PerfCountersMeasurement too
|
||||
std::vector<std::unique_ptr<PerfCountersMeasurement>>
|
||||
perf_counter_measurements;
|
||||
|
||||
perf_counter_measurements.reserve(kMaxCounters);
|
||||
for (int j = 0; j < kMaxCounters; ++j) {
|
||||
perf_counter_measurements.emplace_back(
|
||||
new PerfCountersMeasurement(kMetrics));
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, double>> measurements;
|
||||
|
||||
// Start all counters together to see if they hold
|
||||
size_t max_counters = kMaxCounters;
|
||||
for (size_t i = 0; i < kMaxCounters; ++i) {
|
||||
auto& counter(*perf_counter_measurements[i]);
|
||||
std::set<std::string> names{counter.names().begin(), counter.names().end()};
|
||||
EXPECT_EQ(names.size(), 1);
|
||||
if (!counter.Start()) {
|
||||
max_counters = i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
ASSERT_GE(max_counters, kMinValidCounters);
|
||||
|
||||
// Start all together
|
||||
for (size_t i = 0; i < max_counters; ++i) {
|
||||
auto& counter(*perf_counter_measurements[i]);
|
||||
EXPECT_TRUE(counter.Stop(measurements) || (i >= kMinValidCounters));
|
||||
}
|
||||
|
||||
// Start/stop individually
|
||||
for (size_t i = 0; i < max_counters; ++i) {
|
||||
auto& counter(*perf_counter_measurements[i]);
|
||||
measurements.clear();
|
||||
counter.Start();
|
||||
EXPECT_TRUE(counter.Stop(measurements) || (i >= kMinValidCounters));
|
||||
}
|
||||
}
|
||||
|
||||
// We try to do some meaningful work here but the compiler
|
||||
// insists in optimizing away our loop so we had to add a
|
||||
// no-optimize macro. In case it fails, we added some entropy
|
||||
// to this pool as well.
|
||||
|
||||
BENCHMARK_DONT_OPTIMIZE size_t do_work() {
|
||||
static std::mt19937 rd{std::random_device{}()};
|
||||
static std::uniform_int_distribution<size_t> mrand(0, 10);
|
||||
const size_t kNumLoops = 1000000;
|
||||
size_t sum = 0;
|
||||
for (size_t j = 0; j < kNumLoops; ++j) {
|
||||
sum += mrand(rd);
|
||||
}
|
||||
benchmark::DoNotOptimize(sum);
|
||||
return sum;
|
||||
}
|
||||
|
||||
void measure(size_t threadcount, std::map<std::string, uint64_t>* before,
|
||||
std::map<std::string, uint64_t>* after) {
|
||||
BM_CHECK_NE(before, nullptr);
|
||||
BM_CHECK_NE(after, nullptr);
|
||||
std::vector<std::thread> threads(threadcount);
|
||||
// Because we do not care whether the threads execute concurrently, but we do
|
||||
// care that they do all of their work between the SnapshotAndCombine calls,
|
||||
// we serialize them with a mutex. See
|
||||
// https://github.com/google/benchmark/issues/2173.
|
||||
std::mutex mutex;
|
||||
auto work = [&mutex]() {
|
||||
mutex.lock();
|
||||
BM_CHECK(do_work() > 1000);
|
||||
mutex.unlock();
|
||||
};
|
||||
|
||||
// We need to first set up the counters, then start the threads, so the
|
||||
// threads would inherit the counters. But later, we need to first destroy
|
||||
// the thread pool (so all the work finishes), then measure the counters. So
|
||||
// the scopes overlap, and we need to explicitly control the scope of the
|
||||
// threadpool.
|
||||
auto counters =
|
||||
PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2});
|
||||
mutex.lock();
|
||||
for (auto& t : threads) {
|
||||
t = std::thread(work);
|
||||
}
|
||||
*before = SnapshotAndCombine(counters);
|
||||
mutex.unlock();
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
*after = SnapshotAndCombine(counters);
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, MultiThreaded) {
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) {
|
||||
GTEST_SKIP() << "Requested performance counters are not available.";
|
||||
}
|
||||
std::map<std::string, uint64_t> before, after;
|
||||
|
||||
// Notice that this test will work even if we taskset it to a single CPU
|
||||
// In this case the threads will run sequentially
|
||||
// Start two threads and measure the number of combined cycles and
|
||||
// instructions
|
||||
measure(2, &before, &after);
|
||||
std::vector<double> Elapsed2Threads{
|
||||
static_cast<double>(after[kGenericPerfEvent1] -
|
||||
before[kGenericPerfEvent1]),
|
||||
static_cast<double>(after[kGenericPerfEvent2] -
|
||||
before[kGenericPerfEvent2])};
|
||||
|
||||
// Start four threads and measure the number of combined cycles and
|
||||
// instructions
|
||||
measure(4, &before, &after);
|
||||
std::vector<double> Elapsed4Threads{
|
||||
static_cast<double>(after[kGenericPerfEvent1] -
|
||||
before[kGenericPerfEvent1]),
|
||||
static_cast<double>(after[kGenericPerfEvent2] -
|
||||
before[kGenericPerfEvent2])};
|
||||
|
||||
// The following expectations fail (at least on a beefy workstation with lots
|
||||
// of cpus) - it seems that in some circumstances the runtime of 4 threads
|
||||
// can even be better than with 2.
|
||||
// So instead of expecting 4 threads to be slower, let's just make sure they
|
||||
// do not differ too much in general (one is not more than 10x than the
|
||||
// other).
|
||||
EXPECT_THAT(Elapsed4Threads[0] / Elapsed2Threads[0], AllOf(Gt(0.1), Lt(10)));
|
||||
EXPECT_THAT(Elapsed4Threads[1] / Elapsed2Threads[1], AllOf(Gt(0.1), Lt(10)));
|
||||
}
|
||||
|
||||
TEST(PerfCountersTest, HardwareLimits) {
|
||||
// The test works (i.e. causes read to fail) for the assumptions
|
||||
// about hardware capabilities (i.e. small number (3-4) hardware
|
||||
// counters) at this date,
|
||||
// the same as previous test ReopenExistingCounters.
|
||||
if (!PerfCounters::kSupported) {
|
||||
GTEST_SKIP() << "Test skipped because libpfm is not supported.";
|
||||
}
|
||||
EXPECT_TRUE(PerfCounters::Initialize());
|
||||
|
||||
// Taken from `perf list`, but focusses only on those HW events that actually
|
||||
// were reported when running `sudo perf stat -a sleep 10`, intersected over
|
||||
// several platforms. All HW events listed in the first command not reported
|
||||
// in the second seem to not work. This is sad as we don't really get to test
|
||||
// the grouping here (groups can contain up to 6 members)...
|
||||
std::vector<std::string> counter_names{
|
||||
"cycles", // leader
|
||||
"instructions", //
|
||||
"branch-misses", //
|
||||
};
|
||||
|
||||
// In the off-chance that some of these values are not supported,
|
||||
// we filter them out so the test will complete without failure
|
||||
// albeit it might not actually test the grouping on that platform
|
||||
std::vector<std::string> valid_names;
|
||||
for (const std::string& name : counter_names) {
|
||||
if (PerfCounters::IsCounterSupported(name)) {
|
||||
valid_names.push_back(name);
|
||||
}
|
||||
}
|
||||
PerfCountersMeasurement counter(valid_names);
|
||||
|
||||
std::vector<std::pair<std::string, double>> measurements;
|
||||
|
||||
counter.Start();
|
||||
EXPECT_TRUE(counter.Stop(measurements));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,123 @@
|
||||
#include <cstdarg>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#undef NDEBUG
|
||||
|
||||
#include "../src/commandlineflags.h"
|
||||
#include "../src/perf_counters.h"
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
BM_DECLARE_string(benchmark_perf_counters);
|
||||
|
||||
} // namespace benchmark
|
||||
namespace {
|
||||
const char kGenericPerfEvent1[] = "CYCLES";
|
||||
const char kGenericPerfEvent2[] = "INSTRUCTIONS";
|
||||
|
||||
std::set<std::string> UniqueCounterNames(
|
||||
const benchmark::internal::PerfCounters& counters) {
|
||||
return {counters.names().begin(), counters.names().end()};
|
||||
}
|
||||
|
||||
bool HasRequiredPerfCounters(const std::vector<std::string>& names) {
|
||||
if (!benchmark::internal::PerfCounters::kSupported) {
|
||||
return false;
|
||||
}
|
||||
auto counters = benchmark::internal::PerfCounters::Create(names);
|
||||
auto actual_names = UniqueCounterNames(counters);
|
||||
for (const auto& name : names) {
|
||||
if (actual_names.find(name) == actual_names.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BM_Simple(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = double(state.iterations()) * double(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Simple);
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Simple\",$"}});
|
||||
|
||||
const int kIters = 1000000;
|
||||
|
||||
void BM_WithoutPauseResume(benchmark::State& state) {
|
||||
int n = 0;
|
||||
|
||||
for (auto _ : state) {
|
||||
for (auto i = 0; i < kIters; ++i) {
|
||||
n = 1 - n;
|
||||
benchmark::DoNotOptimize(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_WithoutPauseResume);
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithoutPauseResume\",$"}});
|
||||
|
||||
void BM_WithPauseResume(benchmark::State& state) {
|
||||
int m = 0, n = 0;
|
||||
|
||||
for (auto _ : state) {
|
||||
for (auto i = 0; i < kIters; ++i) {
|
||||
n = 1 - n;
|
||||
benchmark::DoNotOptimize(n);
|
||||
}
|
||||
|
||||
state.PauseTiming();
|
||||
for (auto j = 0; j < kIters; ++j) {
|
||||
m = 1 - m;
|
||||
benchmark::DoNotOptimize(m);
|
||||
}
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_WithPauseResume);
|
||||
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithPauseResume\",$"}});
|
||||
|
||||
static void CheckSimple(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, double, kGenericPerfEvent1, GT, 0);
|
||||
}
|
||||
|
||||
double withoutPauseResumeInstrCount = 0.0;
|
||||
double withPauseResumeInstrCount = 0.0;
|
||||
|
||||
void SaveInstrCountWithoutResume(Results const& e) {
|
||||
withoutPauseResumeInstrCount = e.GetAs<double>(kGenericPerfEvent2);
|
||||
}
|
||||
|
||||
void SaveInstrCountWithResume(Results const& e) {
|
||||
withPauseResumeInstrCount = e.GetAs<double>(kGenericPerfEvent2);
|
||||
}
|
||||
|
||||
CHECK_BENCHMARK_RESULTS("BM_Simple", &CheckSimple);
|
||||
CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &SaveInstrCountWithoutResume);
|
||||
CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &SaveInstrCountWithResume);
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) {
|
||||
return 0;
|
||||
}
|
||||
benchmark::FLAGS_benchmark_perf_counters =
|
||||
std::string(kGenericPerfEvent1) + "," + kGenericPerfEvent2;
|
||||
benchmark::internal::PerfCounters::Initialize();
|
||||
RunOutputTests(argc, argv);
|
||||
|
||||
BM_CHECK_GT(withPauseResumeInstrCount, kIters);
|
||||
BM_CHECK_GT(withoutPauseResumeInstrCount, kIters);
|
||||
BM_CHECK_LT(withPauseResumeInstrCount, 1.5 * withoutPauseResumeInstrCount);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/managers.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class TestProfilerManager : public benchmark::ProfilerManager {
|
||||
public:
|
||||
void AfterSetupStart() override { ++start_called; }
|
||||
void BeforeTeardownStop() override { ++stop_called; }
|
||||
|
||||
int start_called = 0;
|
||||
int stop_called = 0;
|
||||
};
|
||||
|
||||
void BM_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = state.iterations();
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty);
|
||||
|
||||
TEST(ProfilerManager, ReregisterManager) {
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
// Tests only runnable in debug mode (when BM_CHECK is enabled).
|
||||
#ifndef NDEBUG
|
||||
#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS
|
||||
ASSERT_DEATH_IF_SUPPORTED(
|
||||
{
|
||||
std::unique_ptr<TestProfilerManager> pm(new TestProfilerManager());
|
||||
benchmark::RegisterProfilerManager(pm.get());
|
||||
benchmark::RegisterProfilerManager(pm.get());
|
||||
},
|
||||
"RegisterProfilerManager");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/managers.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
// Tests that we can specify the number of profiler iterations with
|
||||
// --benchmark_min_time=<NUM>x.
|
||||
namespace {
|
||||
|
||||
int iteration_count = 0;
|
||||
int end_profiler_iteration_count = 0;
|
||||
|
||||
class TestProfilerManager : public benchmark::ProfilerManager {
|
||||
void AfterSetupStart() override { iteration_count = 0; }
|
||||
void BeforeTeardownStop() override {
|
||||
end_profiler_iteration_count = iteration_count;
|
||||
}
|
||||
};
|
||||
|
||||
class NullReporter : public benchmark::BenchmarkReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& /*context*/) override { return true; }
|
||||
void ReportRuns(const std::vector<Run>& /* report */) override {}
|
||||
};
|
||||
|
||||
void BM_MyBench(benchmark::State& state) {
|
||||
for (auto s : state) {
|
||||
++iteration_count;
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_MyBench);
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
// Make a fake argv and append the new --benchmark_profiler_iterations=<foo>
|
||||
// to it.
|
||||
int fake_argc = argc + 1;
|
||||
std::vector<const char*> fake_argv(static_cast<size_t>(fake_argc));
|
||||
for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
|
||||
fake_argv[i] = argv[i];
|
||||
}
|
||||
fake_argv[static_cast<size_t>(argc)] = "--benchmark_min_time=4x";
|
||||
|
||||
std::unique_ptr<benchmark::ProfilerManager> pm(new TestProfilerManager());
|
||||
benchmark::RegisterProfilerManager(pm.get());
|
||||
|
||||
benchmark::Initialize(&fake_argc, const_cast<char**>(fake_argv.data()));
|
||||
|
||||
NullReporter null_reporter;
|
||||
const size_t returned_count =
|
||||
benchmark::RunSpecifiedBenchmarks(&null_reporter, "BM_MyBench");
|
||||
assert(returned_count == 1);
|
||||
|
||||
// Check the executed iters.
|
||||
assert(end_profiler_iteration_count == 4);
|
||||
|
||||
benchmark::RegisterProfilerManager(nullptr);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// FIXME: WIP
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/managers.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
class TestProfilerManager : public benchmark::ProfilerManager {
|
||||
public:
|
||||
void AfterSetupStart() override { ++start_called; }
|
||||
void BeforeTeardownStop() override { ++stop_called; }
|
||||
|
||||
int start_called = 0;
|
||||
int stop_called = 0;
|
||||
};
|
||||
|
||||
void BM_empty(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = state.iterations();
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_empty);
|
||||
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_empty %console_report$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_empty\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}});
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
std::unique_ptr<TestProfilerManager> pm(new TestProfilerManager());
|
||||
|
||||
benchmark::RegisterProfilerManager(pm.get());
|
||||
RunOutputTests(argc, argv);
|
||||
benchmark::RegisterProfilerManager(nullptr);
|
||||
|
||||
assert(pm->start_called == 1);
|
||||
assert(pm->stop_called == 1);
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/check.h" // NOTE: check.h is for internal use only!
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
all_runs_.insert(all_runs_.end(), begin(report), end(report));
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
}
|
||||
|
||||
std::vector<Run> all_runs_;
|
||||
};
|
||||
|
||||
struct TestCase {
|
||||
const std::string name;
|
||||
const std::string label;
|
||||
// Note: not explicit as we rely on it being converted through ADD_CASES.
|
||||
TestCase(const std::string& xname) : TestCase(xname, "") {}
|
||||
TestCase(const std::string& xname, const std::string& xlabel)
|
||||
: name(xname), label(xlabel) {}
|
||||
|
||||
typedef benchmark::BenchmarkReporter::Run Run;
|
||||
|
||||
void CheckRun(Run const& run) const {
|
||||
// clang-format off
|
||||
BM_CHECK(name == run.benchmark_name()) << "expected " << name << " got "
|
||||
<< run.benchmark_name();
|
||||
if (!label.empty()) {
|
||||
BM_CHECK(run.report_label == label) << "expected " << label << " got "
|
||||
<< run.report_label;
|
||||
} else {
|
||||
BM_CHECK(run.report_label.empty());
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<TestCase> ExpectedResults;
|
||||
|
||||
int AddCases(std::initializer_list<TestCase> const& v) {
|
||||
for (const auto& N : v) {
|
||||
ExpectedResults.push_back(N);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CONCAT(x, y) CONCAT2(x, y)
|
||||
#define CONCAT2(x, y) x##y
|
||||
#define ADD_CASES(...) \
|
||||
const int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__})
|
||||
|
||||
using ReturnVal = benchmark::Benchmark const* const;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test RegisterBenchmark with no additional arguments
|
||||
//----------------------------------------------------------------------------//
|
||||
void BM_function(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_function);
|
||||
ReturnVal dummy = benchmark::RegisterBenchmark(
|
||||
"BM_function_manual_registration", BM_function);
|
||||
ADD_CASES({"BM_function"}, {"BM_function_manual_registration"});
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test RegisterBenchmark with additional arguments
|
||||
// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they
|
||||
// reject the variadic pack expansion of lambda captures.
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
void BM_extra_args(benchmark::State& st, const char* label) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
st.SetLabel(label);
|
||||
}
|
||||
int RegisterFromFunction() {
|
||||
std::pair<const char*, const char*> cases[] = {
|
||||
{"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}};
|
||||
for (auto const& c : cases) {
|
||||
benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const int dummy2 = RegisterFromFunction();
|
||||
ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"});
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test RegisterBenchmark with DISABLED_ benchmark
|
||||
//----------------------------------------------------------------------------//
|
||||
void DISABLED_BM_function(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(DISABLED_BM_function);
|
||||
ReturnVal dummy3 = benchmark::RegisterBenchmark("DISABLED_BM_function_manual",
|
||||
DISABLED_BM_function);
|
||||
// No need to add cases because we don't expect them to run.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test BENCHMARK_NAMED: verifies name format "func/test_case_name" and that
|
||||
// chaining (e.g. ->Threads()) works, without introducing a lambda.
|
||||
//----------------------------------------------------------------------------//
|
||||
void BM_named(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK_NAMED(BM_named, variant_a);
|
||||
BENCHMARK_NAMED(BM_named, variant_b);
|
||||
BENCHMARK_NAMED(BM_named, variant_c)->Threads(2);
|
||||
ADD_CASES({"BM_named/variant_a"}, {"BM_named/variant_b"},
|
||||
{"BM_named/variant_c/threads:2"});
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test RegisterBenchmark with different callable types
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
struct CustomFixture {
|
||||
void operator()(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void TestRegistrationAtRuntime() {
|
||||
{
|
||||
CustomFixture fx;
|
||||
benchmark::RegisterBenchmark("custom_fixture", fx);
|
||||
AddCases({std::string("custom_fixture")});
|
||||
}
|
||||
{
|
||||
const char* x = "42";
|
||||
auto capturing_lam = [=](benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
}
|
||||
st.SetLabel(x);
|
||||
};
|
||||
benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam);
|
||||
AddCases({{"lambda_benchmark", x}});
|
||||
}
|
||||
}
|
||||
|
||||
// Test that all benchmarks, registered at either during static init or runtime,
|
||||
// are run and the results are passed to the reported.
|
||||
void RunTestOne() {
|
||||
TestRegistrationAtRuntime();
|
||||
|
||||
TestReporter test_reporter;
|
||||
benchmark::RunSpecifiedBenchmarks(&test_reporter);
|
||||
|
||||
typedef benchmark::BenchmarkReporter::Run Run;
|
||||
auto EB = ExpectedResults.begin();
|
||||
|
||||
for (Run const& run : test_reporter.all_runs_) {
|
||||
assert(EB != ExpectedResults.end());
|
||||
EB->CheckRun(run);
|
||||
++EB;
|
||||
}
|
||||
assert(EB == ExpectedResults.end());
|
||||
}
|
||||
|
||||
// Test that ClearRegisteredBenchmarks() clears all previously registered
|
||||
// benchmarks.
|
||||
// Also test that new benchmarks can be registered and ran afterwards.
|
||||
void RunTestTwo() {
|
||||
assert(!ExpectedResults.empty() &&
|
||||
"must have at least one registered benchmark");
|
||||
ExpectedResults.clear();
|
||||
benchmark::ClearRegisteredBenchmarks();
|
||||
|
||||
TestReporter test_reporter;
|
||||
size_t num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter);
|
||||
assert(num_ran == 0);
|
||||
assert(test_reporter.all_runs_.begin() == test_reporter.all_runs_.end());
|
||||
|
||||
TestRegistrationAtRuntime();
|
||||
num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter);
|
||||
assert(num_ran == ExpectedResults.size());
|
||||
|
||||
typedef benchmark::BenchmarkReporter::Run Run;
|
||||
auto EB = ExpectedResults.begin();
|
||||
|
||||
for (Run const& run : test_reporter.all_runs_) {
|
||||
assert(EB != ExpectedResults.end());
|
||||
EB->CheckRun(run);
|
||||
++EB;
|
||||
}
|
||||
assert(EB == ExpectedResults.end());
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
RunTestOne();
|
||||
RunTestTwo();
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
// ========================================================================= //
|
||||
// ------------------------ Testing Basic Output --------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_ExplicitRepetitions(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ExplicitRepetitions)->Repetitions(2);
|
||||
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_ExplicitRepetitions/repeats:2 %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_ExplicitRepetitions/repeats:2 %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_ExplicitRepetitions/repeats:2_mean %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_ExplicitRepetitions/repeats:2_median %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_ExplicitRepetitions/repeats:2_stddev %console_report$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ExplicitRepetitions/repeats:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ExplicitRepetitions/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ExplicitRepetitions/repeats:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ExplicitRepetitions/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 1,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ExplicitRepetitions/repeats:2_mean\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ExplicitRepetitions/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"mean\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ExplicitRepetitions/repeats:2_median\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ExplicitRepetitions/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"median\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_ExplicitRepetitions/repeats:2_stddev\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ExplicitRepetitions/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"stddev\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ExplicitRepetitions/repeats:2\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ExplicitRepetitions/repeats:2\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_ExplicitRepetitions/repeats:2_mean\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_ExplicitRepetitions/repeats:2_median\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_ExplicitRepetitions/repeats:2_stddev\",%csv_report$"}});
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------ Testing Basic Output --------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_ImplicitRepetitions(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ImplicitRepetitions);
|
||||
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions_mean %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions_median %console_report$"}});
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_ImplicitRepetitions_stddev %console_report$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"repetition_index\": 1,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"repetition_index\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions_mean\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"mean\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions_median\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"median\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_ImplicitRepetitions_stddev\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_ImplicitRepetitions\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"stddev\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\"$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_mean\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_median\",%csv_report$"}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_stddev\",%csv_report$"}});
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- Testing Skipped Repetitions ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_SkippedFirstRepetition(benchmark::State& state) {
|
||||
static int repetition_index = 0;
|
||||
if (repetition_index++ == 0) {
|
||||
state.SkipWithError("skipped first repetition");
|
||||
return;
|
||||
}
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SkippedFirstRepetition)->Repetitions(3);
|
||||
|
||||
ADD_CASES(
|
||||
TC_ConsoleOut,
|
||||
{{"^BM_SkippedFirstRepetition/repeats:3[ ]+ERROR OCCURRED: "
|
||||
"'skipped first repetition'$"},
|
||||
{"^BM_SkippedFirstRepetition/repeats:3 %console_report$", MR_Next},
|
||||
{"^BM_SkippedFirstRepetition/repeats:3 %console_report$", MR_Next},
|
||||
{"^BM_SkippedFirstRepetition/repeats:3_mean %console_report$", MR_Next},
|
||||
{"^BM_SkippedFirstRepetition/repeats:3_median %console_report$", MR_Next},
|
||||
{"^BM_SkippedFirstRepetition/repeats:3_stddev %console_report$",
|
||||
MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_SkippedFirstRepetition/repeats:3_mean\",$"},
|
||||
{"\"run_type\": \"aggregate\",$"},
|
||||
{"\"repetitions\": 3,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"mean\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": 2,$", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_SkippedFirstRepetition/repeats:3_mean\",2,%float,%float,"
|
||||
"ns,,,,,$"}});
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
#undef NDEBUG
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
// Ok this test is super ugly. We want to check what happens with the file
|
||||
// reporter in the presence of ReportAggregatesOnly().
|
||||
// We do not care about console output, the normal tests check that already.
|
||||
|
||||
void BM_SummaryRepeat(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly();
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
const std::string output = GetFileReporterOutput(argc, argv);
|
||||
|
||||
if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 4 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_mean\"") != 1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_median\"") !=
|
||||
1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"") !=
|
||||
1 ||
|
||||
SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_cv\"") != 1) {
|
||||
std::cout << "Precondition mismatch. Expected to only find four "
|
||||
"occurrences of \"BM_SummaryRepeat/repeats:3\" substring:\n"
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_mean\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_median\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_stddev\", "
|
||||
"\"name\": \"BM_SummaryRepeat/repeats:3_cv\"\nThe entire "
|
||||
"output:\n";
|
||||
std::cout << output;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "output_test.h"
|
||||
|
||||
// BM_ScopedPause sleeps for 10ms in a ScopedPauseTiming block.
|
||||
// The reported time should be much less than 10ms.
|
||||
void BM_ScopedPause(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
benchmark::ScopedPauseTiming pause(state);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
state.SetIterationTime(0.0);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ScopedPause)->UseManualTime()->Iterations(1);
|
||||
|
||||
void CheckResults(Results const& results) {
|
||||
// Check that the real time is much less than the 10ms sleep time.
|
||||
// Allow for up to 1ms of timing noise/overhead.
|
||||
CHECK_FLOAT_RESULT_VALUE(results, "real_time", LT, 1e6, 0.0);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_ScopedPause", &CheckResults);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "../src/check.h" // NOTE: check.h is for internal use only!
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& context) override {
|
||||
return ConsoleReporter::ReportContext(context);
|
||||
};
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
all_runs_.insert(all_runs_.end(), begin(report), end(report));
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
}
|
||||
|
||||
TestReporter() {}
|
||||
~TestReporter() override {}
|
||||
|
||||
mutable std::vector<Run> all_runs_;
|
||||
};
|
||||
|
||||
struct TestCase {
|
||||
std::string name;
|
||||
bool error_occurred;
|
||||
std::string error_message;
|
||||
|
||||
typedef benchmark::BenchmarkReporter::Run Run;
|
||||
|
||||
void CheckRun(Run const& run) const {
|
||||
BM_CHECK(name == run.benchmark_name())
|
||||
<< "expected " << name << " got " << run.benchmark_name();
|
||||
BM_CHECK_EQ(error_occurred,
|
||||
benchmark::internal::SkippedWithError == run.skipped);
|
||||
BM_CHECK(error_message == run.skip_message);
|
||||
if (error_occurred) {
|
||||
// BM_CHECK(run.iterations == 0);
|
||||
} else {
|
||||
BM_CHECK(run.iterations != 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::vector<TestCase> ExpectedResults;
|
||||
|
||||
int AddCases(const std::string& base_name,
|
||||
std::initializer_list<TestCase> const& v) {
|
||||
for (auto TC : v) {
|
||||
TC.name = base_name + TC.name;
|
||||
ExpectedResults.push_back(std::move(TC));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CONCAT(x, y) CONCAT2(x, y)
|
||||
#define CONCAT2(x, y) x##y
|
||||
#define ADD_CASES(...) const int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__)
|
||||
|
||||
void BM_error_no_running(benchmark::State& state) {
|
||||
state.SkipWithError("error message");
|
||||
}
|
||||
BENCHMARK(BM_error_no_running);
|
||||
ADD_CASES("BM_error_no_running", {{"", true, "error message"}});
|
||||
|
||||
void BM_error_before_running(benchmark::State& state) {
|
||||
state.SkipWithError("error message");
|
||||
while (state.KeepRunning()) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_before_running);
|
||||
ADD_CASES("BM_error_before_running", {{"", true, "error message"}});
|
||||
|
||||
void BM_error_before_running_batch(benchmark::State& state) {
|
||||
state.SkipWithError("error message");
|
||||
while (state.KeepRunningBatch(17)) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_before_running_batch);
|
||||
ADD_CASES("BM_error_before_running_batch", {{"", true, "error message"}});
|
||||
|
||||
void BM_error_before_running_range_for(benchmark::State& state) {
|
||||
state.SkipWithError("error message");
|
||||
for (auto _ : state) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_before_running_range_for);
|
||||
ADD_CASES("BM_error_before_running_range_for", {{"", true, "error message"}});
|
||||
|
||||
void BM_error_during_running(benchmark::State& state) {
|
||||
int first_iter = 1;
|
||||
while (state.KeepRunning()) {
|
||||
if (state.range(0) == 1 && state.thread_index() <= (state.threads() / 2)) {
|
||||
assert(first_iter);
|
||||
first_iter = 0;
|
||||
state.SkipWithError("error message");
|
||||
} else {
|
||||
state.PauseTiming();
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_during_running)->Arg(1)->Arg(2)->ThreadRange(1, 8);
|
||||
ADD_CASES("BM_error_during_running", {{"/1/threads:1", true, "error message"},
|
||||
{"/1/threads:2", true, "error message"},
|
||||
{"/1/threads:4", true, "error message"},
|
||||
{"/1/threads:8", true, "error message"},
|
||||
{"/2/threads:1", false, ""},
|
||||
{"/2/threads:2", false, ""},
|
||||
{"/2/threads:4", false, ""},
|
||||
{"/2/threads:8", false, ""}});
|
||||
|
||||
void BM_error_during_running_ranged_for(benchmark::State& state) {
|
||||
assert(state.max_iterations > 3 && "test requires at least a few iterations");
|
||||
bool first_iter = true;
|
||||
// NOTE: Users should not write the for loop explicitly.
|
||||
for (auto It = state.begin(), End = state.end(); It != End; ++It) {
|
||||
if (state.range(0) == 1) {
|
||||
assert(first_iter);
|
||||
first_iter = false;
|
||||
(void)first_iter;
|
||||
state.SkipWithError("error message");
|
||||
// Test the unfortunate but documented behavior that the ranged-for loop
|
||||
// doesn't automatically terminate when SkipWithError is set.
|
||||
assert(++It != End);
|
||||
break; // Required behavior
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_during_running_ranged_for)->Arg(1)->Arg(2)->Iterations(5);
|
||||
ADD_CASES("BM_error_during_running_ranged_for",
|
||||
{{"/1/iterations:5", true, "error message"},
|
||||
{"/2/iterations:5", false, ""}});
|
||||
|
||||
void BM_error_after_running(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
if (state.thread_index() <= (state.threads() / 2)) {
|
||||
state.SkipWithError("error message");
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_after_running)->ThreadRange(1, 8);
|
||||
ADD_CASES("BM_error_after_running", {{"/threads:1", true, "error message"},
|
||||
{"/threads:2", true, "error message"},
|
||||
{"/threads:4", true, "error message"},
|
||||
{"/threads:8", true, "error message"}});
|
||||
|
||||
void BM_error_while_paused(benchmark::State& state) {
|
||||
bool first_iter = true;
|
||||
while (state.KeepRunning()) {
|
||||
if (state.range(0) == 1 && state.thread_index() <= (state.threads() / 2)) {
|
||||
assert(first_iter);
|
||||
first_iter = false;
|
||||
state.PauseTiming();
|
||||
state.SkipWithError("error message");
|
||||
} else {
|
||||
state.PauseTiming();
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_error_while_paused)->Arg(1)->Arg(2)->ThreadRange(1, 8);
|
||||
ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"},
|
||||
{"/1/threads:2", true, "error message"},
|
||||
{"/1/threads:4", true, "error message"},
|
||||
{"/1/threads:8", true, "error message"},
|
||||
{"/2/threads:1", false, ""},
|
||||
{"/2/threads:2", false, ""},
|
||||
{"/2/threads:4", false, ""},
|
||||
{"/2/threads:8", false, ""}});
|
||||
|
||||
void BM_malformed(benchmark::State& /*unused*/) {
|
||||
// NOTE: empty body wanted. No thing else.
|
||||
}
|
||||
BENCHMARK(BM_malformed);
|
||||
ADD_CASES("BM_malformed",
|
||||
{{"", true,
|
||||
"The benchmark didn't run, nor was it explicitly skipped. Please "
|
||||
"call 'SkipWithXXX` in your benchmark as appropriate."}});
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
TestReporter test_reporter;
|
||||
benchmark::RunSpecifiedBenchmarks(&test_reporter);
|
||||
|
||||
typedef benchmark::BenchmarkReporter::Run Run;
|
||||
auto EB = ExpectedResults.begin();
|
||||
|
||||
for (Run const& run : test_reporter.all_runs_) {
|
||||
assert(EB != ExpectedResults.end());
|
||||
EB->CheckRun(run);
|
||||
++EB;
|
||||
}
|
||||
assert(EB == ExpectedResults.end());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/reporter.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
// Tests that we can override benchmark-spec value from FLAGS_benchmark_filter
|
||||
// with argument to RunSpecifiedBenchmarks(...).
|
||||
|
||||
namespace {
|
||||
|
||||
class TestReporter : public benchmark::ConsoleReporter {
|
||||
public:
|
||||
bool ReportContext(const Context& context) override {
|
||||
return ConsoleReporter::ReportContext(context);
|
||||
};
|
||||
|
||||
void ReportRuns(const std::vector<Run>& report) override {
|
||||
assert(report.size() == 1);
|
||||
matched_functions.push_back(report[0].run_name.function_name);
|
||||
ConsoleReporter::ReportRuns(report);
|
||||
};
|
||||
|
||||
TestReporter() {}
|
||||
|
||||
~TestReporter() override {}
|
||||
|
||||
const std::vector<std::string>& GetMatchedFunctions() const {
|
||||
return matched_functions;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> matched_functions;
|
||||
};
|
||||
|
||||
void BM_NotChosen(benchmark::State& state) {
|
||||
assert(false && "SHOULD NOT BE CALLED");
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_NotChosen);
|
||||
|
||||
void BM_Chosen(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Chosen);
|
||||
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
const std::string flag = "BM_NotChosen";
|
||||
|
||||
// Verify that argv specify --benchmark_filter=BM_NotChosen.
|
||||
bool found = false;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp("--benchmark_filter=BM_NotChosen", argv[i]) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found);
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
// Check that the current flag value is reported accurately via the
|
||||
// GetBenchmarkFilter() function.
|
||||
if (flag != benchmark::GetBenchmarkFilter()) {
|
||||
std::cerr
|
||||
<< "Seeing different value for flags. GetBenchmarkFilter() returns ["
|
||||
<< benchmark::GetBenchmarkFilter() << "] expected flag=[" << flag
|
||||
<< "]\n";
|
||||
return 1;
|
||||
}
|
||||
TestReporter test_reporter;
|
||||
const char* const spec = "BM_Chosen";
|
||||
const size_t returned_count =
|
||||
benchmark::RunSpecifiedBenchmarks(&test_reporter, spec);
|
||||
assert(returned_count == 1);
|
||||
const std::vector<std::string> matched_functions =
|
||||
test_reporter.GetMatchedFunctions();
|
||||
assert(matched_functions.size() == 1);
|
||||
if (strcmp(spec, matched_functions.front().c_str()) != 0) {
|
||||
std::cerr << "Expected benchmark [" << spec << "] to run, but got ["
|
||||
<< matched_functions.front() << "]\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Test that SetBenchmarkFilter works.
|
||||
const std::string golden_value = "golden_value";
|
||||
benchmark::SetBenchmarkFilter(golden_value);
|
||||
std::string current_value = benchmark::GetBenchmarkFilter();
|
||||
if (golden_value != current_value) {
|
||||
std::cerr << "Expected [" << golden_value
|
||||
<< "] for --benchmark_filter but got [" << current_value << "]\n";
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
namespace {
|
||||
// Tests that the user specified verbosity level can be get.
|
||||
void BM_Verbosity(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Verbosity);
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
|
||||
const int32_t flagv = 42;
|
||||
|
||||
// Verify that argv specify --v=42.
|
||||
bool found = false;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp("--v=42", argv[i]) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
std::cerr << "This test requires '--v=42' to be passed as a command-line "
|
||||
<< "argument.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
||||
// Check that the current flag value is reported accurately via the
|
||||
// GetBenchmarkVerbosity() function.
|
||||
if (flagv != benchmark::GetBenchmarkVerbosity()) {
|
||||
std::cerr
|
||||
<< "Seeing different value for flags. GetBenchmarkVerbosity() returns ["
|
||||
<< benchmark::GetBenchmarkVerbosity() << "] expected flag=[" << flagv
|
||||
<< "]\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wreturn-type"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
extern "C" {
|
||||
extern int ExternInt;
|
||||
benchmark::State& GetState();
|
||||
void Fn();
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
using benchmark::State;
|
||||
|
||||
// CHECK-LABEL: test_for_auto_loop:
|
||||
extern "C" int test_for_auto_loop() {
|
||||
State& S = GetState();
|
||||
int x = 42;
|
||||
// CHECK: [[CALL:call(q)*]] _ZN9benchmark5State16StartKeepRunningEv
|
||||
// CHECK-NEXT: testq %rbx, %rbx
|
||||
// CHECK-NEXT: je [[LOOP_END:.*]]
|
||||
|
||||
for (auto _ : S) {
|
||||
// CHECK: .L[[LOOP_HEAD:[a-zA-Z0-9_]+]]:
|
||||
// CHECK-GNU-NEXT: subq $1, %rbx
|
||||
// CHECK-CLANG-NEXT: {{(addq \$1, %rax|incq %rax|addq \$-1, %rbx)}}
|
||||
// CHECK-NEXT: jne .L[[LOOP_HEAD]]
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
// CHECK: [[LOOP_END]]:
|
||||
// CHECK: [[CALL]] _ZN9benchmark5State17FinishKeepRunningEv
|
||||
|
||||
// CHECK: movl $101, %eax
|
||||
// CHECK: ret
|
||||
return 101;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_while_loop:
|
||||
extern "C" int test_while_loop() {
|
||||
State& S = GetState();
|
||||
int x = 42;
|
||||
|
||||
// CHECK: j{{(e|mp)}} .L[[LOOP_HEADER:[a-zA-Z0-9_]+]]
|
||||
// CHECK-NEXT: .L[[LOOP_BODY:[a-zA-Z0-9_]+]]:
|
||||
while (S.KeepRunning()) {
|
||||
// CHECK-GNU-NEXT: subq $1, %[[IREG:[a-z]+]]
|
||||
// CHECK-CLANG-NEXT: {{(addq \$-1,|decq)}} %[[IREG:[a-z]+]]
|
||||
// CHECK: movq %[[IREG]], [[DEST:.*]]
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
// CHECK-DAG: movq [[DEST]], %[[IREG]]
|
||||
// CHECK-DAG: testq %[[IREG]], %[[IREG]]
|
||||
// CHECK-DAG: jne .L[[LOOP_BODY]]
|
||||
// CHECK-DAG: .L[[LOOP_HEADER]]:
|
||||
|
||||
// CHECK: cmpb $0
|
||||
// CHECK-NEXT: jne .L[[LOOP_END:[a-zA-Z0-9_]+]]
|
||||
// CHECK: [[CALL:call(q)*]] _ZN9benchmark5State16StartKeepRunningEv
|
||||
|
||||
// CHECK: .L[[LOOP_END]]:
|
||||
// CHECK: [[CALL]] _ZN9benchmark5State17FinishKeepRunningEv
|
||||
|
||||
// CHECK: movl $101, %eax
|
||||
// CHECK: ret
|
||||
return 101;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// statistics_test - Unit tests for src/statistics.cc
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include "../src/statistics.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
TEST(StatisticsTest, Mean) {
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({42, 42, 42, 42}), 42.0);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({1, 2, 3, 4}), 2.5);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({1, 2, 5, 10, 10, 14}), 7.0);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, Median) {
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({42, 42, 42, 42}), 42.0);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({1, 2, 3, 4}), 2.5);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({1, 2, 5, 10, 10}), 5.0);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, StdDev) {
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({101, 101, 101, 101}), 0.0);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({1, 2, 3}), 1.0);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({2.5, 2.4, 3.3, 4.2, 5.1}),
|
||||
1.151086443322134);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, CV) {
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsCV({101, 101, 101, 101}), 0.0);
|
||||
EXPECT_DOUBLE_EQ(benchmark::StatisticsCV({1, 2, 3}), 1. / 2.);
|
||||
ASSERT_NEAR(benchmark::StatisticsCV({2.5, 2.4, 3.3, 4.2, 5.1}),
|
||||
0.32888184094918121, 1e-15);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
@@ -0,0 +1,203 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// string_util_test - Unit tests for src/string_util.cc
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "../src/internal_macros.h"
|
||||
#include "../src/string_util.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
TEST(StringUtilTest, stoul) {
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0UL, benchmark::stoul("0", &pos));
|
||||
EXPECT_EQ(1UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(7UL, benchmark::stoul("7", &pos));
|
||||
EXPECT_EQ(1UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(135UL, benchmark::stoul("135", &pos));
|
||||
EXPECT_EQ(3UL, pos);
|
||||
}
|
||||
#if ULONG_MAX == 0xFFFFFFFFul
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0xFFFFFFFFul, benchmark::stoul("4294967295", &pos));
|
||||
EXPECT_EQ(10ul, pos);
|
||||
}
|
||||
#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFFul
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0xFFFFFFFFFFFFFFFFUL,
|
||||
benchmark::stoul("18446744073709551615", &pos));
|
||||
EXPECT_EQ(20UL, pos);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(10UL, benchmark::stoul("1010", &pos, 2));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(520UL, benchmark::stoul("1010", &pos, 8));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(1010UL, benchmark::stoul("1010", &pos, 10));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(4112UL, benchmark::stoul("1010", &pos, 16));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0xBEEFUL, benchmark::stoul("BEEF", &pos, 16));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
{
|
||||
ASSERT_THROW(std::ignore = benchmark::stoul("this is a test"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StringUtilTest, stoi) {
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0, benchmark::stoi("0", &pos));
|
||||
EXPECT_EQ(1UL, pos);
|
||||
} // namespace
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(-17, benchmark::stoi("-17", &pos));
|
||||
EXPECT_EQ(3UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(1357, benchmark::stoi("1357", &pos));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(10, benchmark::stoi("1010", &pos, 2));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(520, benchmark::stoi("1010", &pos, 8));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(1010, benchmark::stoi("1010", &pos, 10));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(4112, benchmark::stoi("1010", &pos, 16));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0xBEEF, benchmark::stoi("BEEF", &pos, 16));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
{
|
||||
ASSERT_THROW(std::ignore = benchmark::stoi("this is a test"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StringUtilTest, stod) {
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(0.0, benchmark::stod("0", &pos));
|
||||
EXPECT_EQ(1UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(-84.0, benchmark::stod("-84", &pos));
|
||||
EXPECT_EQ(3UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(1234.0, benchmark::stod("1234", &pos));
|
||||
EXPECT_EQ(4UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
EXPECT_EQ(1.5, benchmark::stod("1.5", &pos));
|
||||
EXPECT_EQ(3UL, pos);
|
||||
}
|
||||
{
|
||||
size_t pos = 0;
|
||||
/* Note: exactly representable as double */
|
||||
EXPECT_EQ(-1.25e+9, benchmark::stod("-1.25e+9", &pos));
|
||||
EXPECT_EQ(8UL, pos);
|
||||
}
|
||||
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
|
||||
{
|
||||
ASSERT_THROW(std::ignore = benchmark::stod("this is a test"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StringUtilTest, StrSplit) {
|
||||
EXPECT_EQ(benchmark::StrSplit("", ','), std::vector<std::string>{});
|
||||
EXPECT_EQ(benchmark::StrSplit("hello", ','),
|
||||
std::vector<std::string>({"hello"}));
|
||||
EXPECT_EQ(benchmark::StrSplit("hello,there,is,more", ','),
|
||||
std::vector<std::string>({"hello", "there", "is", "more"}));
|
||||
}
|
||||
|
||||
using HumanReadableFixture = ::testing::TestWithParam<
|
||||
std::tuple<double, benchmark::Counter::OneK, std::string>>;
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
HumanReadableTests, HumanReadableFixture,
|
||||
::testing::Values(
|
||||
std::make_tuple(0.0, benchmark::Counter::kIs1024, "0"),
|
||||
std::make_tuple(999.0, benchmark::Counter::kIs1024, "999"),
|
||||
std::make_tuple(1000.0, benchmark::Counter::kIs1024, "1000"),
|
||||
std::make_tuple(1024.0, benchmark::Counter::kIs1024, "1Ki"),
|
||||
std::make_tuple(1000 * 1000.0, benchmark::Counter::kIs1024,
|
||||
"976\\.56.Ki"),
|
||||
std::make_tuple(1024 * 1024.0, benchmark::Counter::kIs1024, "1Mi"),
|
||||
std::make_tuple(1000 * 1000 * 1000.0, benchmark::Counter::kIs1024,
|
||||
"953\\.674Mi"),
|
||||
std::make_tuple(1024 * 1024 * 1024.0, benchmark::Counter::kIs1024,
|
||||
"1Gi"),
|
||||
std::make_tuple(0.0, benchmark::Counter::kIs1000, "0"),
|
||||
std::make_tuple(999.0, benchmark::Counter::kIs1000, "999"),
|
||||
std::make_tuple(1000.0, benchmark::Counter::kIs1000, "1k"),
|
||||
std::make_tuple(1024.0, benchmark::Counter::kIs1000, "1.024k"),
|
||||
std::make_tuple(1000 * 1000.0, benchmark::Counter::kIs1000, "1M"),
|
||||
std::make_tuple(1024 * 1024.0, benchmark::Counter::kIs1000,
|
||||
"1\\.04858M"),
|
||||
std::make_tuple(1000 * 1000 * 1000.0, benchmark::Counter::kIs1000,
|
||||
"1G"),
|
||||
std::make_tuple(1024 * 1024 * 1024.0, benchmark::Counter::kIs1000,
|
||||
"1\\.07374G")));
|
||||
|
||||
TEST_P(HumanReadableFixture, HumanReadableNumber) {
|
||||
std::string str = benchmark::HumanReadableNumber(std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
ASSERT_THAT(str, ::testing::MatchesRegex(std::get<2>(GetParam())));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
template <typename T>
|
||||
class MyFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
MyFixture() : data(0) {}
|
||||
|
||||
T data;
|
||||
|
||||
using type = T;
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE_METHOD_F(MyFixture, Foo)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
this->data += typename Base::type(1);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, int);
|
||||
BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, double);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
|
||||
template <typename T>
|
||||
class MyFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
MyFixture() : data(0) {}
|
||||
|
||||
T data;
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE_F(MyFixture, Foo, int)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
data += 1;
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, Bar, double)(benchmark::State& st) {
|
||||
for (auto _ : st) {
|
||||
data += 1.0;
|
||||
}
|
||||
}
|
||||
BENCHMARK_REGISTER_F(MyFixture, Bar);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
class DummyBenchmark : public benchmark::Benchmark {
|
||||
public:
|
||||
DummyBenchmark() : Benchmark("dummy") {}
|
||||
void Run(State& /*state*/) override {}
|
||||
};
|
||||
|
||||
TEST(DefaultTimeUnitTest, TimeUnitIsNotSet) {
|
||||
DummyBenchmark benchmark;
|
||||
EXPECT_EQ(benchmark.GetTimeUnit(), kNanosecond);
|
||||
}
|
||||
|
||||
TEST(DefaultTimeUnitTest, DefaultIsSet) {
|
||||
DummyBenchmark benchmark;
|
||||
EXPECT_EQ(benchmark.GetTimeUnit(), kNanosecond);
|
||||
SetDefaultTimeUnit(kMillisecond);
|
||||
EXPECT_EQ(benchmark.GetTimeUnit(), kMillisecond);
|
||||
}
|
||||
|
||||
TEST(DefaultTimeUnitTest, DefaultAndExplicitUnitIsSet) {
|
||||
DummyBenchmark benchmark;
|
||||
benchmark.Unit(kMillisecond);
|
||||
SetDefaultTimeUnit(kMicrosecond);
|
||||
|
||||
EXPECT_EQ(benchmark.GetTimeUnit(), kMillisecond);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
||||
@@ -0,0 +1,572 @@
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/counter.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
// @todo: <jpmag> this checks the full output at once; the rule for
|
||||
// CounterSet1 was failing because it was not matching "^[-]+$".
|
||||
// @todo: <jpmag> check that the counters are vertically aligned.
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{
|
||||
// keeping these lines long improves readability, so:
|
||||
// clang-format off
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Bat %s Baz %s Foo %s Frob %s Lob$", MR_Next},
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1 %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1 %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1_mean %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1_median %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1_stddev %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:1_cv %console_percentage_report [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*%$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2 %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2 %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2_mean %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2_median %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2_stddev %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_Counters_Tabular/repeats:2/threads:2_cv %console_percentage_report [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*% [ ]*%percentage[ ]*%$", MR_Next},
|
||||
{"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next},
|
||||
{"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next},
|
||||
{"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next},
|
||||
{"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next},
|
||||
{"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next},
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Baz %s Foo$", MR_Next},
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^Benchmark %s Time %s CPU %s Iterations %s Bat %s Baz %s Foo$", MR_Next},
|
||||
{"^[-]+$", MR_Next},
|
||||
{"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next},
|
||||
{"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$"},
|
||||
// clang-format on
|
||||
});
|
||||
ADD_CASES(TC_CSVOut, {{"%csv_header,"
|
||||
"\"Bar\",\"Bat\",\"Baz\",\"Foo\",\"Frob\",\"Lob\""}});
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Tabular Counters Output ----------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Counters_Tabular(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"Foo", {1, bm::Counter::kAvgThreads}},
|
||||
{"Bar", {2, bm::Counter::kAvgThreads}},
|
||||
{"Baz", {4, bm::Counter::kAvgThreads}},
|
||||
{"Bat", {8, bm::Counter::kAvgThreads}},
|
||||
{"Frob", {16, bm::Counter::kAvgThreads}},
|
||||
{"Lob", {32, bm::Counter::kAvgThreads}},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_Counters_Tabular)->ThreadRange(1, 2)->Repetitions(2);
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 1,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1_mean\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"mean\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1_median\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"median\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1_stddev\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"stddev\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:1_cv\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:1\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"cv\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"percentage\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 1,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 2,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 1,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 1,$", MR_Next},
|
||||
{"\"threads\": 2,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:2_median\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 1,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 2,$", MR_Next},
|
||||
{"\"aggregate_name\": \"median\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:2_stddev\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 1,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 2,$", MR_Next},
|
||||
{"\"aggregate_name\": \"stddev\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Tabular/repeats:2/threads:2_cv\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 1,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Tabular/repeats:2/threads:2\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 2,$", MR_Next},
|
||||
{"\"aggregate_name\": \"cv\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"percentage\",$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1_mean\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1_median\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1_stddev\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:1_cv\",%csv_cv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2_mean\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2_median\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2_stddev\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Tabular/repeats:2/threads:2_cv\",%csv_cv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckTabular(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 1);
|
||||
CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 2);
|
||||
CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 4);
|
||||
CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 8);
|
||||
CHECK_COUNTER_VALUE(e, int, "Frob", EQ, 16);
|
||||
CHECK_COUNTER_VALUE(e, int, "Lob", EQ, 32);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/repeats:2/threads:1$",
|
||||
&CheckTabular);
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/repeats:2/threads:2$",
|
||||
&CheckTabular);
|
||||
|
||||
// ========================================================================= //
|
||||
// -------------------- Tabular+Rate Counters Output ----------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_CounterRates_Tabular(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"Foo", {1, bm::Counter::kAvgThreadsRate}},
|
||||
{"Bar", {2, bm::Counter::kAvgThreadsRate}},
|
||||
{"Baz", {4, bm::Counter::kAvgThreadsRate}},
|
||||
{"Bat", {8, bm::Counter::kAvgThreadsRate}},
|
||||
{"Frob", {16, bm::Counter::kAvgThreadsRate}},
|
||||
{"Lob", {32, bm::Counter::kAvgThreadsRate}},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_CounterRates_Tabular)->ThreadRange(1, 16);
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_CounterRates_Tabular/threads:%int\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_CounterRates_Tabular/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float,$", MR_Next},
|
||||
{"\"Frob\": %float,$", MR_Next},
|
||||
{"\"Lob\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_CounterRates_Tabular/threads:%int\",%csv_report,"
|
||||
"%float,%float,%float,%float,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckTabularRate(Results const& e) {
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Foo", EQ, 1. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Bar", EQ, 2. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Baz", EQ, 4. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Bat", EQ, 8. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Frob", EQ, 16. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "Lob", EQ, 32. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_CounterRates_Tabular/threads:%int",
|
||||
&CheckTabularRate);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Tabular Counters Output ----------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// set only some of the counters
|
||||
void BM_CounterSet0_Tabular(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"Foo", {10, bm::Counter::kAvgThreads}},
|
||||
{"Bar", {20, bm::Counter::kAvgThreads}},
|
||||
{"Baz", {40, bm::Counter::kAvgThreads}},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_CounterSet0_Tabular)->ThreadRange(1, 16);
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_CounterSet0_Tabular/threads:%int\",$"},
|
||||
{"\"family_index\": 2,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_CounterSet0_Tabular/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet0_Tabular/threads:%int\",%csv_report,"
|
||||
"%float,,%float,%float,,"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckSet0(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10);
|
||||
CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 20);
|
||||
CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_CounterSet0_Tabular", &CheckSet0);
|
||||
|
||||
// again.
|
||||
void BM_CounterSet1_Tabular(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"Foo", {15, bm::Counter::kAvgThreads}},
|
||||
{"Bar", {25, bm::Counter::kAvgThreads}},
|
||||
{"Baz", {45, bm::Counter::kAvgThreads}},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_CounterSet1_Tabular)->ThreadRange(1, 16);
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_CounterSet1_Tabular/threads:%int\",$"},
|
||||
{"\"family_index\": 3,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_CounterSet1_Tabular/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bar\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet1_Tabular/threads:%int\",%csv_report,"
|
||||
"%float,,%float,%float,,"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckSet1(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 15);
|
||||
CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 25);
|
||||
CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 45);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_CounterSet1_Tabular/threads:%int", &CheckSet1);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Tabular Counters Output ----------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// set only some of the counters, different set now.
|
||||
void BM_CounterSet2_Tabular(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"Foo", {10, bm::Counter::kAvgThreads}},
|
||||
{"Bat", {30, bm::Counter::kAvgThreads}},
|
||||
{"Baz", {40, bm::Counter::kAvgThreads}},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_CounterSet2_Tabular)->ThreadRange(1, 16);
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_CounterSet2_Tabular/threads:%int\",$"},
|
||||
{"\"family_index\": 4,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_CounterSet2_Tabular/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"Bat\": %float,$", MR_Next},
|
||||
{"\"Baz\": %float,$", MR_Next},
|
||||
{"\"Foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet2_Tabular/threads:%int\",%csv_report,"
|
||||
",%float,%float,%float,,"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckSet2(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10);
|
||||
CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 30);
|
||||
CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_CounterSet2_Tabular", &CheckSet2);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/counter.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- Testing Prologue Output -------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// clang-format off
|
||||
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^[-]+$", MR_Next},
|
||||
{"^Benchmark %s Time %s CPU %s Iterations UserCounters...$", MR_Next},
|
||||
{"^[-]+$", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}});
|
||||
|
||||
// clang-format on
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Simple Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
namespace {
|
||||
void BM_Counters_Simple(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.counters["bar"] = 2 * static_cast<double>(state.iterations());
|
||||
}
|
||||
BENCHMARK(BM_Counters_Simple);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_Simple %console_report bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Simple\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Simple\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Simple\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckSimple(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1);
|
||||
// check that the value of bar is within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Simple", &CheckSimple);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- Counters+Items+Bytes/s Output --------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
int num_calls1 = 0;
|
||||
void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.counters["bar"] = ++num_calls1;
|
||||
state.SetBytesProcessed(364);
|
||||
state.SetItemsProcessed(150);
|
||||
}
|
||||
BENCHMARK(BM_Counters_WithBytesAndItemsPSec);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_WithBytesAndItemsPSec %console_report "
|
||||
"bar=%hrfloat bytes_per_second=%hrfloat/s "
|
||||
"foo=%hrfloat items_per_second=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_WithBytesAndItemsPSec\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_WithBytesAndItemsPSec\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"bytes_per_second\": %float,$", MR_Next},
|
||||
{"\"foo\": %float,$", MR_Next},
|
||||
{"\"items_per_second\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec\","
|
||||
"%csv_bytes_items_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckBytesAndItemsPSec(Results const& e) {
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1);
|
||||
CHECK_COUNTER_VALUE(e, int, "bar", EQ, num_calls1);
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ, 364. / t, 0.001);
|
||||
CHECK_FLOAT_RESULT_VALUE(e, "items_per_second", EQ, 150. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec",
|
||||
&CheckBytesAndItemsPSec);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Rate Counters Output -------------------------- //
|
||||
// ========================================================================= //
|
||||
namespace {
|
||||
void BM_Counters_Rate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kIsRate};
|
||||
}
|
||||
BENCHMARK(BM_Counters_Rate);
|
||||
ADD_CASES(
|
||||
TC_ConsoleOut,
|
||||
{{"^BM_Counters_Rate %console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Rate\",$"},
|
||||
{"\"family_index\": 2,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Rate\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Rate\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckRate(Results const& e) {
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ----------------------- Inverted Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Invert(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert};
|
||||
state.counters["bar"] = bm::Counter{10000, bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Invert);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Invert %console_report bar=%hrfloatu foo=%hrfloatk$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Invert\",$"},
|
||||
{"\"family_index\": 3,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Invert\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Invert\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvert(Results const& e) {
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 10000, 0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 0.0001, 0.0001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- InvertedRate Counters Output ---------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_InvertedRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] =
|
||||
bm::Counter{1, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{8192, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Counters_InvertedRate);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_InvertedRate %console_report "
|
||||
"bar=%hrfloats foo=%hrfloats$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_InvertedRate\",$"},
|
||||
{"\"family_index\": 4,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_InvertedRate\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_InvertedRate\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvertedRate(Results const& e) {
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / 8192.0, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate", &CheckInvertedRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Thread Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_Threads(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.counters["bar"] = 2;
|
||||
}
|
||||
BENCHMARK(BM_Counters_Threads)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Threads/threads:%int %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Threads/threads:%int\",$"},
|
||||
{"\"family_index\": 5,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Threads/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_Threads/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckThreads(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, e.NumThreads());
|
||||
CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads());
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- ThreadAvg Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgThreads(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreads};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreads};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgThreads)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreads/threads:%int "
|
||||
"%console_report bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgThreads/threads:%int\",$"},
|
||||
{"\"family_index\": 6,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgThreads/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_AvgThreads/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgThreads(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1);
|
||||
CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int",
|
||||
&CheckAvgThreads);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- ThreadAvg Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgThreadsRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreadsRate};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgThreadsRate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreadsRate/threads:%int "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$"},
|
||||
{"\"family_index\": 7,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/"
|
||||
"threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgThreadsRate(Results const& e) {
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int",
|
||||
&CheckAvgThreadsRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------- IterationInvariant Counters Output ------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_IterationInvariant(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kIsIterationInvariant};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kIsIterationInvariant};
|
||||
}
|
||||
BENCHMARK(BM_Counters_IterationInvariant);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_IterationInvariant %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_IterationInvariant\",$"},
|
||||
{"\"family_index\": 8,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_IterationInvariant\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_IterationInvariant\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckIterationInvariant(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// check that the values are within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant",
|
||||
&CheckIterationInvariant);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ----------------- IterationInvariantRate Counters Output ---------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] =
|
||||
bm::Counter{1, bm::Counter::kIsIterationInvariantRate};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kIsIterationInvariant};
|
||||
}
|
||||
BENCHMARK(BM_Counters_kIsIterationInvariantRate);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kIsIterationInvariantRate "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_kIsIterationInvariantRate\",$"},
|
||||
{"\"family_index\": 9,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_kIsIterationInvariantRate\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_kIsIterationInvariantRate\",%csv_report,"
|
||||
"%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckIsIterationInvariantRate(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate",
|
||||
&CheckIsIterationInvariantRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- AvgIterations Counters Output --------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgIterations(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterations};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgIterations};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgIterations);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgIterations %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgIterations\",$"},
|
||||
{"\"family_index\": 10,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgIterations\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_AvgIterations\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgIterations(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// check that the values are within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / its, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / its, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------- AvgIterationsRate Counters Output ------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_kAvgIterationsRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterationsRate};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kAvgIterations};
|
||||
}
|
||||
BENCHMARK(BM_Counters_kAvgIterationsRate);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kAvgIterationsRate "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_kAvgIterationsRate\",$"},
|
||||
{"\"family_index\": 11,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_kAvgIterationsRate\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_kAvgIterationsRate\",%csv_report,"
|
||||
"%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgIterationsRate(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / its / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / its / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate",
|
||||
&CheckAvgIterationsRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/counter.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "output_test.h"
|
||||
|
||||
namespace {
|
||||
// ========================================================================= //
|
||||
// ------------------------ Thousands Customisation ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Counters_Thousands(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters.insert({
|
||||
{"t0_1000000DefaultBase",
|
||||
bm::Counter(1000 * 1000, bm::Counter::kDefaults)},
|
||||
{"t1_1000000Base1000", bm::Counter(1000 * 1000, bm::Counter::kDefaults,
|
||||
bm::Counter::OneK::kIs1000)},
|
||||
{"t2_1000000Base1024", bm::Counter(1000 * 1000, bm::Counter::kDefaults,
|
||||
bm::Counter::OneK::kIs1024)},
|
||||
{"t3_1048576Base1000", bm::Counter(1024 * 1024, bm::Counter::kDefaults,
|
||||
bm::Counter::OneK::kIs1000)},
|
||||
{"t4_1048576Base1024", bm::Counter(1024 * 1024, bm::Counter::kDefaults,
|
||||
bm::Counter::OneK::kIs1024)},
|
||||
});
|
||||
}
|
||||
BENCHMARK(BM_Counters_Thousands)->Repetitions(2);
|
||||
ADD_CASES(
|
||||
TC_ConsoleOut,
|
||||
{
|
||||
{"^BM_Counters_Thousands/repeats:2 %console_report "
|
||||
"t0_1000000DefaultBase=1M "
|
||||
"t1_1000000Base1000=1M t2_1000000Base1024=976.56[23]Ki "
|
||||
"t3_1048576Base1000=1.04858M t4_1048576Base1024=1Mi$"},
|
||||
{"^BM_Counters_Thousands/repeats:2 %console_report "
|
||||
"t0_1000000DefaultBase=1M "
|
||||
"t1_1000000Base1000=1M t2_1000000Base1024=976.56[23]Ki "
|
||||
"t3_1048576Base1000=1.04858M t4_1048576Base1024=1Mi$"},
|
||||
{"^BM_Counters_Thousands/repeats:2_mean %console_report "
|
||||
"t0_1000000DefaultBase=1M t1_1000000Base1000=1M "
|
||||
"t2_1000000Base1024=976.56[23]Ki t3_1048576Base1000=1.04858M "
|
||||
"t4_1048576Base1024=1Mi$"},
|
||||
{"^BM_Counters_Thousands/repeats:2_median %console_report "
|
||||
"t0_1000000DefaultBase=1M t1_1000000Base1000=1M "
|
||||
"t2_1000000Base1024=976.56[23]Ki t3_1048576Base1000=1.04858M "
|
||||
"t4_1048576Base1024=1Mi$"},
|
||||
{"^BM_Counters_Thousands/repeats:2_stddev %console_time_only_report [ "
|
||||
"]*2 t0_1000000DefaultBase=0 t1_1000000Base1000=0 "
|
||||
"t2_1000000Base1024=0 t3_1048576Base1000=0 t4_1048576Base1024=0$"},
|
||||
});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Thousands/repeats:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Thousands/repeats:2\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"repetition_index\": 1,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Thousands/repeats:2_mean\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"mean\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": 2,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Thousands/repeats:2_median\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"median\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": 2,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next},
|
||||
{"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Thousands/repeats:2_stddev\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next},
|
||||
{"\"run_type\": \"aggregate\",$", MR_Next},
|
||||
{"\"repetitions\": 2,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"aggregate_name\": \"stddev\",$", MR_Next},
|
||||
{"\"aggregate_unit\": \"time\",$", MR_Next},
|
||||
{"\"iterations\": 2,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"t0_1000000DefaultBase\": 0\\.(0)*e\\+(0)*,$", MR_Next},
|
||||
{"\"t1_1000000Base1000\": 0\\.(0)*e\\+(0)*,$", MR_Next},
|
||||
{"\"t2_1000000Base1024\": 0\\.(0)*e\\+(0)*,$", MR_Next},
|
||||
{"\"t3_1048576Base1000\": 0\\.(0)*e\\+(0)*,$", MR_Next},
|
||||
{"\"t4_1048576Base1024\": 0\\.(0)*e\\+(0)*$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_Thousands/"
|
||||
"repeats:2\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\.04858e\\+("
|
||||
"0)*6,1\\.04858e\\+(0)*6$"},
|
||||
{"^\"BM_Counters_Thousands/"
|
||||
"repeats:2\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\.04858e\\+("
|
||||
"0)*6,1\\.04858e\\+(0)*6$"},
|
||||
{"^\"BM_Counters_Thousands/"
|
||||
"repeats:2_mean\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\."
|
||||
"04858e\\+(0)*6,1\\.04858e\\+(0)*6$"},
|
||||
{"^\"BM_Counters_Thousands/"
|
||||
"repeats:2_median\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\."
|
||||
"04858e\\+(0)*6,1\\.04858e\\+(0)*6$"},
|
||||
{"^\"BM_Counters_Thousands/repeats:2_stddev\",%csv_report,0,0,0,0,0$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckThousands(Results const& e) {
|
||||
if (e.name != "BM_Counters_Thousands/repeats:2") {
|
||||
return; // Do not check the aggregates!
|
||||
}
|
||||
|
||||
// check that the values are within 0.01% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "t0_1000000DefaultBase", EQ, 1000 * 1000,
|
||||
0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "t1_1000000Base1000", EQ, 1000 * 1000, 0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "t2_1000000Base1024", EQ, 1000 * 1000, 0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "t3_1048576Base1000", EQ, 1024 * 1024, 0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "t4_1048576Base1024", EQ, 1024 * 1024, 0.0001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Thousands", &CheckThousands);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,625 @@
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "benchmark/registration.h"
|
||||
#include "benchmark/state.h"
|
||||
#include "benchmark/utils.h"
|
||||
#include "output_test.h"
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- Testing Prologue Output -------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
// clang-format off
|
||||
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^[-]+$", MR_Next},
|
||||
{"^Benchmark %s Time %s CPU %s Iterations UserCounters...$", MR_Next},
|
||||
{"^[-]+$", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}});
|
||||
|
||||
// clang-format on
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Simple Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_Simple(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.counters["bar"] = 2 * static_cast<double>(state.iterations());
|
||||
}
|
||||
BENCHMARK(BM_Counters_Simple)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Simple/threads:%int %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Simple/threads:%int\",$"},
|
||||
{"\"family_index\": 0,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Simple/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_Simple/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckSimple(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads());
|
||||
// check that the value of bar is within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Simple/threads:%int", &CheckSimple);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- Counters+Items+Bytes/s Output --------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.SetBytesProcessed(364);
|
||||
state.SetItemsProcessed(150);
|
||||
}
|
||||
BENCHMARK(BM_Counters_WithBytesAndItemsPSec)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_WithBytesAndItemsPSec/threads:%int %console_report "
|
||||
"bytes_per_second=%hrfloat/s "
|
||||
"foo=%hrfloat items_per_second=%hrfloat/s$"}});
|
||||
ADD_CASES(
|
||||
TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_WithBytesAndItemsPSec/threads:%int\",$"},
|
||||
{"\"family_index\": 1,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_WithBytesAndItemsPSec/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bytes_per_second\": %float,$", MR_Next},
|
||||
{"\"foo\": %float,$", MR_Next},
|
||||
{"\"items_per_second\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec/threads:%int\","
|
||||
"%csv_bytes_items_report,,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckBytesAndItemsPSec(Results const& e) {
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads());
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ,
|
||||
(364. * e.NumThreads()) / t, 0.001);
|
||||
CHECK_FLOAT_RESULT_VALUE(e, "items_per_second", EQ,
|
||||
(150. * e.NumThreads()) / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec/threads:%int",
|
||||
&CheckBytesAndItemsPSec);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Rate Counters Output -------------------------- //
|
||||
// ========================================================================= //
|
||||
namespace {
|
||||
void BM_Counters_Rate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kIsRate};
|
||||
}
|
||||
BENCHMARK(BM_Counters_Rate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Rate/threads:%int %console_report "
|
||||
"bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Rate/threads:%int\",$"},
|
||||
{"\"family_index\": 2,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Rate/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_Rate/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckRate(Results const& e) {
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, (1. * e.NumThreads()) / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, (2. * e.NumThreads()) / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Rate/threads:%int", &CheckRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ----------------------- Inverted Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Invert(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert};
|
||||
state.counters["bar"] = bm::Counter{10000, bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Invert)->ThreadRange(1, 8);
|
||||
ADD_CASES(
|
||||
TC_ConsoleOut,
|
||||
{{"^BM_Invert/threads:%int %console_report bar=%hrfloatu foo=%hrfloatk$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Invert/threads:%int\",$"},
|
||||
{"\"family_index\": 3,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Invert/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Invert/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvert(Results const& e) {
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / (0.0001 * e.NumThreads()),
|
||||
0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 1. / (10000 * e.NumThreads()),
|
||||
0.0001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Invert/threads:%int", &CheckInvert);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- InvertedRate Counters Output ---------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_InvertedRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] =
|
||||
bm::Counter{1, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{8192, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Counters_InvertedRate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_InvertedRate/threads:%int %console_report "
|
||||
"bar=%hrfloats foo=%hrfloats$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_InvertedRate/threads:%int\",$"},
|
||||
{"\"family_index\": 4,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_InvertedRate/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_InvertedRate/"
|
||||
"threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvertedRate(Results const& e) {
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t / (e.NumThreads()), 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / (8192.0 * e.NumThreads()), 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate/threads:%int",
|
||||
&CheckInvertedRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Thread Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_Threads(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
state.counters["foo"] = 1;
|
||||
state.counters["bar"] = 2;
|
||||
}
|
||||
BENCHMARK(BM_Counters_Threads)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Threads/threads:%int %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_Threads/threads:%int\",$"},
|
||||
{"\"family_index\": 5,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_Threads/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_Threads/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckThreads(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, e.NumThreads());
|
||||
CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads());
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- ThreadAvg Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgThreads(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreads};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreads};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgThreads)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreads/threads:%int "
|
||||
"%console_report bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgThreads/threads:%int\",$"},
|
||||
{"\"family_index\": 6,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgThreads/threads:%int\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_AvgThreads/threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgThreads(Results const& e) {
|
||||
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1);
|
||||
CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int",
|
||||
&CheckAvgThreads);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ---------------------- ThreadAvg Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgThreadsRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreadsRate};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgThreadsRate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreadsRate/threads:%int "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$"},
|
||||
{"\"family_index\": 7,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/"
|
||||
"threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgThreadsRate(Results const& e) {
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int",
|
||||
&CheckAvgThreadsRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------- IterationInvariant Counters Output ------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_IterationInvariant(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kIsIterationInvariant};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kIsIterationInvariant};
|
||||
}
|
||||
BENCHMARK(BM_Counters_IterationInvariant)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_IterationInvariant/threads:%int %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_IterationInvariant/threads:%int\",$"},
|
||||
{"\"family_index\": 8,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_IterationInvariant/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_IterationInvariant/"
|
||||
"threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckIterationInvariant(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// check that the values are within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * e.NumThreads(), 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its * e.NumThreads(), 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant/threads:%int",
|
||||
&CheckIterationInvariant);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ----------------- IterationInvariantRate Counters Output ---------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] =
|
||||
bm::Counter{1, bm::Counter::kIsIterationInvariantRate};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kIsIterationInvariant};
|
||||
}
|
||||
BENCHMARK(BM_Counters_kIsIterationInvariantRate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_kIsIterationInvariantRate/threads:%int "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(
|
||||
TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_kIsIterationInvariantRate/threads:%int\",$"},
|
||||
{"\"family_index\": 9,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_kIsIterationInvariantRate/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(
|
||||
TC_CSVOut,
|
||||
{{"^\"BM_Counters_kIsIterationInvariantRate/threads:%int\",%csv_report,"
|
||||
"%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckIsIterationInvariantRate(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. * e.NumThreads() / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. * e.NumThreads() / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate/threads:%int",
|
||||
&CheckIsIterationInvariantRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------- AvgIterations Counters Output --------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_AvgIterations(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterations};
|
||||
state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgIterations};
|
||||
}
|
||||
BENCHMARK(BM_Counters_AvgIterations)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Counters_AvgIterations/threads:%int %console_report "
|
||||
"bar=%hrfloat foo=%hrfloat$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_AvgIterations/threads:%int\",$"},
|
||||
{"\"family_index\": 10,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_AvgIterations/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgIterations/"
|
||||
"threads:%int\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgIterations(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// check that the values are within 0.1% of the expected value
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations/threads:%int",
|
||||
&CheckAvgIterations);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------- AvgIterationsRate Counters Output ------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
namespace {
|
||||
void BM_Counters_kAvgIterationsRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
auto iterations = static_cast<double>(state.iterations()) *
|
||||
static_cast<double>(state.iterations());
|
||||
benchmark::DoNotOptimize(iterations);
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterationsRate};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kAvgIterations};
|
||||
}
|
||||
BENCHMARK(BM_Counters_kAvgIterationsRate)->ThreadRange(1, 8);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kAvgIterationsRate/threads:%int "
|
||||
"%console_report bar=%hrfloat/s foo=%hrfloat/s$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_kAvgIterationsRate/threads:%int\",$"},
|
||||
{"\"family_index\": 11,$", MR_Next},
|
||||
{"\"per_family_instance_index\": 0,$", MR_Next},
|
||||
{"\"run_name\": \"BM_Counters_kAvgIterationsRate/threads:%int\",$",
|
||||
MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 1,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": %int,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_kAvgIterationsRate/threads:%int\",%csv_report,"
|
||||
"%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckAvgIterationsRate(Results const& e) {
|
||||
double its = e.NumIterations();
|
||||
// this (and not real time) is the time used
|
||||
double t = e.DurationCPUTime() / e.NumThreads();
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its / t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its / t, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate/threads:%int",
|
||||
&CheckAvgIterationsRate);
|
||||
} // end namespace
|
||||
|
||||
// ========================================================================= //
|
||||
// --------------------------- TEST CASES END ------------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
benchmark::MaybeReenterWithoutASLR(argc, argv);
|
||||
RunOutputTests(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user