| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #include <unordered_set> | ||
| #include <vector> | ||
| #include <cstdint> | ||
|
|
||
| #include "benchmark/benchmark_api.h" | ||
| #include "GenerateInput.hpp" | ||
|
|
||
| constexpr std::size_t TestNumInputs = 1024; | ||
|
|
||
| template <class GenInputs> | ||
| void BM_Sort(benchmark::State& st, GenInputs gen) { | ||
| using ValueType = typename decltype(gen(0))::value_type; | ||
| const auto in = gen(st.range_x()); | ||
| std::vector<ValueType> inputs[5]; | ||
| auto reset_inputs = [&]() { | ||
| for (auto& C : inputs) { | ||
| C = in; | ||
| benchmark::DoNotOptimize(C.data()); | ||
| } | ||
| }; | ||
| reset_inputs(); | ||
| while (st.KeepRunning()) { | ||
| for (auto& I : inputs) { | ||
| std::sort(I.data(), I.data() + I.size()); | ||
| benchmark::DoNotOptimize(I.data()); | ||
| } | ||
| st.PauseTiming(); | ||
| reset_inputs(); | ||
| benchmark::ClobberMemory(); | ||
| st.ResumeTiming(); | ||
| } | ||
| } | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, random_uint32, | ||
| getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, sorted_ascending_uint32, | ||
| getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, sorted_descending_uint32, | ||
| getReverseSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, single_element_uint32, | ||
| getDuplicateIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, pipe_organ_uint32, | ||
| getPipeOrganIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, random_strings, | ||
| getRandomStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, sorted_ascending_strings, | ||
| getSortedStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, sorted_descending_strings, | ||
| getReverseSortedStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Sort, single_element_strings, | ||
| getDuplicateStringInputs)->Arg(TestNumInputs); | ||
|
|
||
|
|
||
| BENCHMARK_MAIN() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,268 @@ | ||
| #include <unordered_set> | ||
| #include <vector> | ||
| #include <functional> | ||
| #include <cstdint> | ||
| #include <cstdlib> | ||
| #include <cstring> | ||
|
|
||
| #include "benchmark/benchmark_api.h" | ||
|
|
||
| #include "ContainerBenchmarks.hpp" | ||
| #include "GenerateInput.hpp" | ||
|
|
||
| using namespace ContainerBenchmarks; | ||
|
|
||
| constexpr std::size_t TestNumInputs = 1024; | ||
|
|
||
| template <class _Size> | ||
| inline __attribute__((__always_inline__)) | ||
| _Size loadword(const void* __p) { | ||
| _Size __r; | ||
| std::memcpy(&__r, __p, sizeof(__r)); | ||
| return __r; | ||
| } | ||
|
|
||
| inline __attribute__((__always_inline__)) | ||
| std::size_t rotate_by_at_least_1(std::size_t __val, int __shift) { | ||
| return (__val >> __shift) | (__val << (64 - __shift)); | ||
| } | ||
|
|
||
| inline __attribute__((__always_inline__)) | ||
| std::size_t hash_len_16(std::size_t __u, std::size_t __v) { | ||
| const std::size_t __mul = 0x9ddfea08eb382d69ULL; | ||
| std::size_t __a = (__u ^ __v) * __mul; | ||
| __a ^= (__a >> 47); | ||
| std::size_t __b = (__v ^ __a) * __mul; | ||
| __b ^= (__b >> 47); | ||
| __b *= __mul; | ||
| return __b; | ||
| } | ||
|
|
||
|
|
||
| template <std::size_t _Len> | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t hash_len_0_to_8(const char* __s) { | ||
| static_assert(_Len == 4 || _Len == 8, ""); | ||
| const uint64_t __a = loadword<uint32_t>(__s); | ||
| const uint64_t __b = loadword<uint32_t>(__s + _Len - 4); | ||
| return hash_len_16(_Len + (__a << 3), __b); | ||
| } | ||
|
|
||
| struct UInt32Hash { | ||
| UInt32Hash() = default; | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t operator()(uint32_t data) const { | ||
| return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data)); | ||
| } | ||
| }; | ||
|
|
||
| struct UInt64Hash { | ||
| UInt64Hash() = default; | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t operator()(uint64_t data) const { | ||
| return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data)); | ||
| } | ||
| }; | ||
|
|
||
| struct UInt128Hash { | ||
| UInt128Hash() = default; | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t operator()(__uint128_t data) const { | ||
| const __uint128_t __mask = static_cast<std::size_t>(-1); | ||
| const std::size_t __a = (std::size_t)(data & __mask); | ||
| const std::size_t __b = (std::size_t)((data & (__mask << 64)) >> 64); | ||
| return hash_len_16(__a, rotate_by_at_least_1(__b + 16, 16)) ^ __b; | ||
| } | ||
| }; | ||
|
|
||
| struct UInt32Hash2 { | ||
| UInt32Hash2() = default; | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t operator()(uint32_t data) const { | ||
| const uint32_t __m = 0x5bd1e995; | ||
| const uint32_t __r = 24; | ||
| uint32_t __h = 4; | ||
| uint32_t __k = data; | ||
| __k *= __m; | ||
| __k ^= __k >> __r; | ||
| __k *= __m; | ||
| __h *= __m; | ||
| __h ^= __k; | ||
| __h ^= __h >> 13; | ||
| __h *= __m; | ||
| __h ^= __h >> 15; | ||
| return __h; | ||
| } | ||
| }; | ||
|
|
||
| struct UInt64Hash2 { | ||
| UInt64Hash2() = default; | ||
| inline __attribute__((__always_inline__)) | ||
| std::size_t operator()(uint64_t data) const { | ||
| return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data)); | ||
| } | ||
| }; | ||
|
|
||
| //----------------------------------------------------------------------------// | ||
| // BM_Hash | ||
| // ---------------------------------------------------------------------------// | ||
|
|
||
| template <class HashFn, class GenInputs> | ||
| void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) { | ||
| auto in = gen(st.range_x()); | ||
| const auto end = in.data() + in.size(); | ||
| std::size_t last_hash = 0; | ||
| benchmark::DoNotOptimize(&last_hash); | ||
| while (st.KeepRunning()) { | ||
| for (auto it = in.data(); it != end; ++it) { | ||
| benchmark::DoNotOptimize(last_hash += fn(*it)); | ||
| } | ||
| benchmark::ClobberMemory(); | ||
| } | ||
| } | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Hash, | ||
| uint32_random_std_hash, | ||
| std::hash<uint32_t>{}, | ||
| getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Hash, | ||
| uint32_random_custom_hash, | ||
| UInt32Hash{}, | ||
| getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Hash, | ||
| uint32_top_std_hash, | ||
| std::hash<uint32_t>{}, | ||
| getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_Hash, | ||
| uint32_top_custom_hash, | ||
| UInt32Hash{}, | ||
| getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs); | ||
|
|
||
|
|
||
| //----------------------------------------------------------------------------// | ||
| // BM_InsertValue | ||
| // ---------------------------------------------------------------------------// | ||
|
|
||
|
|
||
| // Sorted Assending // | ||
| BENCHMARK_CAPTURE(BM_InsertValue, | ||
| unordered_set_uint32, | ||
| std::unordered_set<uint32_t>{}, | ||
| getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_InsertValue, | ||
| unordered_set_uint32_sorted, | ||
| std::unordered_set<uint32_t>{}, | ||
| getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| // Top Bytes // | ||
| BENCHMARK_CAPTURE(BM_InsertValue, | ||
| unordered_set_top_bits_uint32, | ||
| std::unordered_set<uint32_t>{}, | ||
| getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_InsertValueRehash, | ||
| unordered_set_top_bits_uint32, | ||
| std::unordered_set<uint32_t, UInt32Hash>{}, | ||
| getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| // String // | ||
| BENCHMARK_CAPTURE(BM_InsertValue, | ||
| unordered_set_string, | ||
| std::unordered_set<std::string>{}, | ||
| getRandomStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_InsertValueRehash, | ||
| unordered_set_string, | ||
| std::unordered_set<std::string>{}, | ||
| getRandomStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| //----------------------------------------------------------------------------// | ||
| // BM_Find | ||
| // ---------------------------------------------------------------------------// | ||
|
|
||
| // Random // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_random_uint64, | ||
| std::unordered_set<uint64_t>{}, | ||
| getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_random_uint64, | ||
| std::unordered_set<uint64_t, UInt64Hash>{}, | ||
| getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| // Sorted // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_sorted_uint64, | ||
| std::unordered_set<uint64_t>{}, | ||
| getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_sorted_uint64, | ||
| std::unordered_set<uint64_t, UInt64Hash>{}, | ||
| getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
|
|
||
| // Sorted // | ||
| #if 1 | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_sorted_uint128, | ||
| std::unordered_set<__uint128_t, UInt128Hash>{}, | ||
| getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_sorted_uint128, | ||
| std::unordered_set<__uint128_t, UInt128Hash>{}, | ||
| getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs); | ||
| #endif | ||
|
|
||
| // Sorted // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_sorted_uint32, | ||
| std::unordered_set<uint32_t>{}, | ||
| getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_sorted_uint32, | ||
| std::unordered_set<uint32_t, UInt32Hash2>{}, | ||
| getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs); | ||
|
|
||
| // Sorted Ascending // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_sorted_large_uint64, | ||
| std::unordered_set<uint64_t>{}, | ||
| getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_sorted_large_uint64, | ||
| std::unordered_set<uint64_t, UInt64Hash>{}, | ||
| getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
|
|
||
| // Top Bits // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_top_bits_uint64, | ||
| std::unordered_set<uint64_t>{}, | ||
| getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_top_bits_uint64, | ||
| std::unordered_set<uint64_t, UInt64Hash>{}, | ||
| getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs); | ||
|
|
||
| // String // | ||
| BENCHMARK_CAPTURE(BM_Find, | ||
| unordered_set_string, | ||
| std::unordered_set<std::string>{}, | ||
| getRandomStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_CAPTURE(BM_FindRehash, | ||
| unordered_set_string, | ||
| std::unordered_set<std::string>{}, | ||
| getRandomStringInputs)->Arg(TestNumInputs); | ||
|
|
||
| BENCHMARK_MAIN() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| *.a | ||
| *.so | ||
| *.so.?* | ||
| *.dll | ||
| *.exe | ||
| *.dylib | ||
| *.cmake | ||
| !/cmake/*.cmake | ||
| *~ | ||
| *.pyc | ||
| __pycache__ | ||
|
|
||
| # lcov | ||
| *.lcov | ||
| /lcov | ||
|
|
||
| # cmake files. | ||
| /Testing | ||
| CMakeCache.txt | ||
| CMakeFiles/ | ||
| cmake_install.cmake | ||
|
|
||
| # makefiles. | ||
| Makefile | ||
|
|
||
| # in-source build. | ||
| bin/ | ||
| lib/ | ||
| /test/*_test | ||
|
|
||
| # exuberant ctags. | ||
| tags | ||
|
|
||
| # YouCompleteMe configuration. | ||
| .ycm_extra_conf.pyc | ||
|
|
||
| # ninja generated files. | ||
| .ninja_deps | ||
| .ninja_log | ||
| build.ninja | ||
| install_manifest.txt | ||
| rules.ninja | ||
|
|
||
| # out-of-source build top-level folders. | ||
| build/ | ||
| _build/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # This is the official list of benchmark authors for copyright purposes. | ||
| # This file is distinct from the CONTRIBUTORS files. | ||
| # See the latter for an explanation. | ||
| # | ||
| # Names should be added to this file as: | ||
| # Name or Organization <email address> | ||
| # The email address is not required for organizations. | ||
| # | ||
| # Please keep the list sorted. | ||
|
|
||
| Albert Pretorius <pretoalb@gmail.com> | ||
| Arne Beer <arne@twobeer.de> | ||
| Christopher Seymour <chris.j.seymour@hotmail.com> | ||
| David Coeurjolly <david.coeurjolly@liris.cnrs.fr> | ||
| Dominic Hamon <dma@stripysock.com> | ||
| Eugene Zhuk <eugene.zhuk@gmail.com> | ||
| Evgeny Safronov <division494@gmail.com> | ||
| Felix Homann <linuxaudio@showlabor.de> | ||
| Google Inc. | ||
| Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com> | ||
| JianXiong Zhou <zhoujianxiong2@gmail.com> | ||
| Jussi Knuuttila <jussi.knuuttila@gmail.com> | ||
| Kaito Udagawa <umireon@gmail.com> | ||
| Lei Xu <eddyxu@gmail.com> | ||
| Matt Clarkson <mattyclarkson@gmail.com> | ||
| Oleksandr Sochka <sasha.sochka@gmail.com> | ||
| Paul Redmond <paul.redmond@gmail.com> | ||
| Radoslav Yovchev <radoslav.tm@gmail.com> | ||
| Shuo Chen <chenshuo@chenshuo.com> | ||
| Yusuke Suzuki <utatane.tea@gmail.com> | ||
| Dirac Research | ||
| Zbigniew Skowron <zbychs@gmail.com> | ||
| Dominik Czarnota <dominik.b.czarnota@gmail.com> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| cmake_minimum_required (VERSION 2.8.11) | ||
| project (benchmark) | ||
|
|
||
| foreach(p | ||
| CMP0054 # CMake 3.1 | ||
| CMP0056 # export EXE_LINKER_FLAGS to try_run | ||
| ) | ||
| if(POLICY ${p}) | ||
| cmake_policy(SET ${p} NEW) | ||
| endif() | ||
| endforeach() | ||
|
|
||
| option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) | ||
| option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF) | ||
| # Make sure we can import out CMake functions | ||
| list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") | ||
|
|
||
| # Read the git tags to determine the project version | ||
| include(GetGitVersion) | ||
| get_git_version(GIT_VERSION) | ||
|
|
||
| # Tell the user what versions we are using | ||
| string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_VERSION}) | ||
| message("-- Version: ${VERSION}") | ||
|
|
||
| # The version of the libraries | ||
| set(GENERIC_LIB_VERSION ${VERSION}) | ||
| string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION) | ||
|
|
||
| # Import our CMake modules | ||
| include(CheckCXXCompilerFlag) | ||
| include(AddCXXCompilerFlag) | ||
| include(CXXFeatureCheck) | ||
|
|
||
| if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") | ||
| # Turn compiler warnings up to 11 | ||
| string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") | ||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") | ||
| add_definitions(-D_CRT_SECURE_NO_WARNINGS) | ||
|
|
||
| # Link time optimisation | ||
| if (BENCHMARK_ENABLE_LTO) | ||
| set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") | ||
| set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") | ||
| set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") | ||
| set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") | ||
|
|
||
| set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL") | ||
| string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}") | ||
| set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") | ||
| string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") | ||
| set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") | ||
| string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") | ||
| set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") | ||
|
|
||
| set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL") | ||
| set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG") | ||
| set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG") | ||
| set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG") | ||
| endif() | ||
| else() | ||
| # Try and enable C++11. Don't use C++14 because it doesn't work in some | ||
| # configurations. | ||
| add_cxx_compiler_flag(-std=c++11) | ||
| if (NOT HAVE_CXX_FLAG_STD_CXX11) | ||
| add_cxx_compiler_flag(-std=c++0x) | ||
| endif() | ||
|
|
||
| # Turn compiler warnings up to 11 | ||
| add_cxx_compiler_flag(-Wall) | ||
|
|
||
| add_cxx_compiler_flag(-Wextra) | ||
| add_cxx_compiler_flag(-Wshadow) | ||
| add_cxx_compiler_flag(-Werror RELEASE) | ||
| add_cxx_compiler_flag(-Werror RELWITHDEBINFO) | ||
| add_cxx_compiler_flag(-Werror MINSIZEREL) | ||
| add_cxx_compiler_flag(-pedantic) | ||
| add_cxx_compiler_flag(-pedantic-errors) | ||
| add_cxx_compiler_flag(-Wshorten-64-to-32) | ||
| add_cxx_compiler_flag(-Wfloat-equal) | ||
| add_cxx_compiler_flag(-Wzero-as-null-pointer-constant) | ||
| add_cxx_compiler_flag(-fstrict-aliasing) | ||
| if (HAVE_CXX_FLAG_FSTRICT_ALIASING) | ||
| add_cxx_compiler_flag(-Wstrict-aliasing) | ||
| endif() | ||
| add_cxx_compiler_flag(-Wthread-safety) | ||
| if (HAVE_WTHREAD_SAFETY) | ||
| add_definitions(-DHAVE_WTHREAD_SAFETY) | ||
| cxx_feature_check(THREAD_SAFETY_ATTRIBUTES) | ||
| endif() | ||
|
|
||
| # Link time optimisation | ||
| if (BENCHMARK_ENABLE_LTO) | ||
| add_cxx_compiler_flag(-flto) | ||
| if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") | ||
| find_program(GCC_AR gcc-ar) | ||
| if (GCC_AR) | ||
| set(CMAKE_AR ${GCC_AR}) | ||
| endif() | ||
| find_program(GCC_RANLIB gcc-ranlib) | ||
| if (GCC_RANLIB) | ||
| set(CMAKE_RANLIB ${GCC_RANLIB}) | ||
| endif() | ||
| endif() | ||
| endif() | ||
|
|
||
| # Coverage build type | ||
| set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING | ||
| "Flags used by the C++ compiler during coverage builds." | ||
| FORCE) | ||
| set(CMAKE_EXE_LINKER_FLAGS_COVERAGE | ||
| "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING | ||
| "Flags used for linking binaries during coverage builds." | ||
| FORCE) | ||
| set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE | ||
| "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING | ||
| "Flags used by the shared libraries linker during coverage builds." | ||
| FORCE) | ||
| mark_as_advanced( | ||
| CMAKE_CXX_FLAGS_COVERAGE | ||
| CMAKE_EXE_LINKER_FLAGS_COVERAGE | ||
| CMAKE_SHARED_LINKER_FLAGS_COVERAGE) | ||
| set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING | ||
| "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." | ||
| FORCE) | ||
| add_cxx_compiler_flag(--coverage COVERAGE) | ||
| endif() | ||
|
|
||
| # C++ feature checks | ||
| cxx_feature_check(STD_REGEX) | ||
| cxx_feature_check(GNU_POSIX_REGEX) | ||
| cxx_feature_check(POSIX_REGEX) | ||
| cxx_feature_check(STEADY_CLOCK) | ||
|
|
||
| # Ensure we have pthreads | ||
| find_package(Threads REQUIRED) | ||
|
|
||
| # Set up directories | ||
| include_directories(${PROJECT_SOURCE_DIR}/include) | ||
|
|
||
| # Build the targets | ||
| add_subdirectory(src) | ||
|
|
||
| if (BENCHMARK_ENABLE_TESTING) | ||
| enable_testing() | ||
| add_subdirectory(test) | ||
| endif() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # How to contribute # | ||
|
|
||
| We'd love to accept your patches and contributions to this project. There are | ||
| a just a few small guidelines you need to follow. | ||
|
|
||
|
|
||
| ## Contributor License Agreement ## | ||
|
|
||
| Contributions to any Google project must be accompanied by a Contributor | ||
| License Agreement. This is not a copyright **assignment**, it simply gives | ||
| Google permission to use and redistribute your contributions as part of the | ||
| project. | ||
|
|
||
| * If you are an individual writing original source code and you're sure you | ||
| own the intellectual property, then you'll need to sign an [individual | ||
| CLA][]. | ||
|
|
||
| * If you work for a company that wants to allow you to contribute your work, | ||
| then you'll need to sign a [corporate CLA][]. | ||
|
|
||
| You generally only need to submit a CLA once, so if you've already submitted | ||
| one (even if it was for a different project), you probably don't need to do it | ||
| again. | ||
|
|
||
| [individual CLA]: https://developers.google.com/open-source/cla/individual | ||
| [corporate CLA]: https://developers.google.com/open-source/cla/corporate | ||
|
|
||
| Once your CLA is submitted (or if you already submitted one for | ||
| another Google project), make a commit adding yourself to the | ||
| [AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part | ||
| of your first [pull request][]. | ||
|
|
||
| [AUTHORS]: AUTHORS | ||
| [CONTRIBUTORS]: CONTRIBUTORS | ||
|
|
||
|
|
||
| ## Submitting a patch ## | ||
|
|
||
| 1. It's generally best to start by opening a new issue describing the bug or | ||
| feature you're intending to fix. Even if you think it's relatively minor, | ||
| it's helpful to know what people are working on. Mention in the initial | ||
| issue that you are planning to work on that bug or feature so that it can | ||
| be assigned to you. | ||
|
|
||
| 1. Follow the normal process of [forking][] the project, and setup a new | ||
| branch to work in. It's important that each group of changes be done in | ||
| separate branches in order to ensure that a pull request only includes the | ||
| commits related to that bug or feature. | ||
|
|
||
| 1. Do your best to have [well-formed commit messages][] for each change. | ||
| This provides consistency throughout the project, and ensures that commit | ||
| messages are able to be formatted properly by various git tools. | ||
|
|
||
| 1. Finally, push the commits to your fork and submit a [pull request][]. | ||
|
|
||
| [forking]: https://help.github.com/articles/fork-a-repo | ||
| [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html | ||
| [pull request]: https://help.github.com/articles/creating-a-pull-request |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # People who have agreed to one of the CLAs and can contribute patches. | ||
| # The AUTHORS file lists the copyright holders; this file | ||
| # lists people. For example, Google employees are listed here | ||
| # but not in AUTHORS, because Google holds the copyright. | ||
| # | ||
| # Names should be added to this file only after verifying that | ||
| # the individual or the individual's organization has agreed to | ||
| # the appropriate Contributor License Agreement, found here: | ||
| # | ||
| # https://developers.google.com/open-source/cla/individual | ||
| # https://developers.google.com/open-source/cla/corporate | ||
| # | ||
| # The agreement for individuals can be filled out on the web. | ||
| # | ||
| # When adding J Random Contributor's name to this file, | ||
| # either J's name or J's organization's name should be | ||
| # added to the AUTHORS file, depending on whether the | ||
| # individual or corporate CLA was used. | ||
| # | ||
| # Names should be added to this file as: | ||
| # Name <email address> | ||
| # | ||
| # Please keep the list sorted. | ||
|
|
||
| Albert Pretorius <pretoalb@gmail.com> | ||
| Arne Beer <arne@twobeer.de> | ||
| Billy Robert O'Neal III <billy.oneal@gmail.com> <bion@microsoft.com> | ||
| Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com> | ||
| Christopher Seymour <chris.j.seymour@hotmail.com> | ||
| David Coeurjolly <david.coeurjolly@liris.cnrs.fr> | ||
| Dominic Hamon <dma@stripysock.com> | ||
| Eric Fiselier <eric@efcs.ca> | ||
| Eugene Zhuk <eugene.zhuk@gmail.com> | ||
| Evgeny Safronov <division494@gmail.com> | ||
| Felix Homann <linuxaudio@showlabor.de> | ||
| Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com> | ||
| JianXiong Zhou <zhoujianxiong2@gmail.com> | ||
| Jussi Knuuttila <jussi.knuuttila@gmail.com> | ||
| Kaito Udagawa <umireon@gmail.com> | ||
| Kai Wolf <kai.wolf@gmail.com> | ||
| Lei Xu <eddyxu@gmail.com> | ||
| Matt Clarkson <mattyclarkson@gmail.com> | ||
| Oleksandr Sochka <sasha.sochka@gmail.com> | ||
| Pascal Leroy <phl@google.com> | ||
| Paul Redmond <paul.redmond@gmail.com> | ||
| Pierre Phaneuf <pphaneuf@google.com> | ||
| Radoslav Yovchev <radoslav.tm@gmail.com> | ||
| Shuo Chen <chenshuo@chenshuo.com> | ||
| Yusuke Suzuki <utatane.tea@gmail.com> | ||
| Tobias Ulvgård <tobias.ulvgard@dirac.se> | ||
| Zbigniew Skowron <zbychs@gmail.com> | ||
| Dominik Czarnota <dominik.b.czarnota@gmail.com> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
|
|
||
| Apache License | ||
| Version 2.0, January 2004 | ||
| http://www.apache.org/licenses/ | ||
|
|
||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
|
|
||
| 1. Definitions. | ||
|
|
||
| "License" shall mean the terms and conditions for use, reproduction, | ||
| and distribution as defined by Sections 1 through 9 of this document. | ||
|
|
||
| "Licensor" shall mean the copyright owner or entity authorized by | ||
| the copyright owner that is granting the License. | ||
|
|
||
| "Legal Entity" shall mean the union of the acting entity and all | ||
| other entities that control, are controlled by, or are under common | ||
| control with that entity. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
|
|
||
| "You" (or "Your") shall mean an individual or Legal Entity | ||
| exercising permissions granted by this License. | ||
|
|
||
| "Source" form shall mean the preferred form for making modifications, | ||
| including but not limited to software source code, documentation | ||
| source, and configuration files. | ||
|
|
||
| "Object" form shall mean any form resulting from mechanical | ||
| transformation or translation of a Source form, including but | ||
| not limited to compiled object code, generated documentation, | ||
| and conversions to other media types. | ||
|
|
||
| "Work" shall mean the work of authorship, whether in Source or | ||
| Object form, made available under the License, as indicated by a | ||
| copyright notice that is included in or attached to the work | ||
| (an example is provided in the Appendix below). | ||
|
|
||
| "Derivative Works" shall mean any work, whether in Source or Object | ||
| form, that is based on (or derived from) the Work and for which the | ||
| editorial revisions, annotations, elaborations, or other modifications | ||
| represent, as a whole, an original work of authorship. For the purposes | ||
| of this License, Derivative Works shall not include works that remain | ||
| separable from, or merely link (or bind by name) to the interfaces of, | ||
| the Work and Derivative Works thereof. | ||
|
|
||
| "Contribution" shall mean any work of authorship, including | ||
| the original version of the Work and any modifications or additions | ||
| to that Work or Derivative Works thereof, that is intentionally | ||
| submitted to Licensor for inclusion in the Work by the copyright owner | ||
| or by an individual or Legal Entity authorized to submit on behalf of | ||
| the copyright owner. For the purposes of this definition, "submitted" | ||
| means any form of electronic, verbal, or written communication sent | ||
| to the Licensor or its representatives, including but not limited to | ||
| communication on electronic mailing lists, source code control systems, | ||
| and issue tracking systems that are managed by, or on behalf of, the | ||
| Licensor for the purpose of discussing and improving the Work, but | ||
| excluding communication that is conspicuously marked or otherwise | ||
| designated in writing by the copyright owner as "Not a Contribution." | ||
|
|
||
| "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| on behalf of whom a Contribution has been received by Licensor and | ||
| subsequently incorporated within the Work. | ||
|
|
||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare Derivative Works of, | ||
| publicly display, publicly perform, sublicense, and distribute the | ||
| Work and such Derivative Works in Source or Object form. | ||
|
|
||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have made, | ||
| use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| where such license applies only to those patent claims licensable | ||
| by such Contributor that are necessarily infringed by their | ||
| Contribution(s) alone or by combination of their Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If You | ||
| institute patent litigation against any entity (including a | ||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| or a Contribution incorporated within the Work constitutes direct | ||
| or contributory patent infringement, then any patent licenses | ||
| granted to You under this License for that Work shall terminate | ||
| as of the date such litigation is filed. | ||
|
|
||
| 4. Redistribution. You may reproduce and distribute copies of the | ||
| Work or Derivative Works thereof in any medium, with or without | ||
| modifications, and in Source or Object form, provided that You | ||
| meet the following conditions: | ||
|
|
||
| (a) You must give any other recipients of the Work or | ||
| Derivative Works a copy of this License; and | ||
|
|
||
| (b) You must cause any modified files to carry prominent notices | ||
| stating that You changed the files; and | ||
|
|
||
| (c) You must retain, in the Source form of any Derivative Works | ||
| that You distribute, all copyright, patent, trademark, and | ||
| attribution notices from the Source form of the Work, | ||
| excluding those notices that do not pertain to any part of | ||
| the Derivative Works; and | ||
|
|
||
| (d) If the Work includes a "NOTICE" text file as part of its | ||
| distribution, then any Derivative Works that You distribute must | ||
| include a readable copy of the attribution notices contained | ||
| within such NOTICE file, excluding those notices that do not | ||
| pertain to any part of the Derivative Works, in at least one | ||
| of the following places: within a NOTICE text file distributed | ||
| as part of the Derivative Works; within the Source form or | ||
| documentation, if provided along with the Derivative Works; or, | ||
| within a display generated by the Derivative Works, if and | ||
| wherever such third-party notices normally appear. The contents | ||
| of the NOTICE file are for informational purposes only and | ||
| do not modify the License. You may add Your own attribution | ||
| notices within Derivative Works that You distribute, alongside | ||
| or as an addendum to the NOTICE text from the Work, provided | ||
| that such additional attribution notices cannot be construed | ||
| as modifying the License. | ||
|
|
||
| You may add Your own copyright statement to Your modifications and | ||
| may provide additional or different license terms and conditions | ||
| for use, reproduction, or distribution of Your modifications, or | ||
| for any such Derivative Works as a whole, provided Your use, | ||
| reproduction, and distribution of the Work otherwise complies with | ||
| the conditions stated in this License. | ||
|
|
||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| any Contribution intentionally submitted for inclusion in the Work | ||
| by You to the Licensor shall be under the terms and conditions of | ||
| this License, without any additional terms or conditions. | ||
| Notwithstanding the above, nothing herein shall supersede or modify | ||
| the terms of any separate license agreement you may have executed | ||
| with Licensor regarding such Contributions. | ||
|
|
||
| 6. Trademarks. This License does not grant permission to use the trade | ||
| names, trademarks, service marks, or product names of the Licensor, | ||
| except as required for reasonable and customary use in describing the | ||
| origin of the Work and reproducing the content of the NOTICE file. | ||
|
|
||
| 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| agreed to in writing, Licensor provides the Work (and each | ||
| Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied, including, without limitation, any warranties or conditions | ||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| appropriateness of using or redistributing the Work and assume any | ||
| risks associated with Your exercise of permissions under this License. | ||
|
|
||
| 8. Limitation of Liability. In no event and under no legal theory, | ||
| whether in tort (including negligence), contract, or otherwise, | ||
| unless required by applicable law (such as deliberate and grossly | ||
| negligent acts) or agreed to in writing, shall any Contributor be | ||
| liable to You for damages, including any direct, indirect, special, | ||
| incidental, or consequential damages of any character arising as a | ||
| result of this License or out of the use or inability to use the | ||
| Work (including but not limited to damages for loss of goodwill, | ||
| work stoppage, computer failure or malfunction, or any and all | ||
| other commercial damages or losses), even if such Contributor | ||
| has been advised of the possibility of such damages. | ||
|
|
||
| 9. Accepting Warranty or Additional Liability. While redistributing | ||
| the Work or Derivative Works thereof, You may choose to offer, | ||
| and charge a fee for, acceptance of support, warranty, indemnity, | ||
| or other liability obligations and/or rights consistent with this | ||
| License. However, in accepting such obligations, You may act only | ||
| on Your own behalf and on Your sole responsibility, not on behalf | ||
| of any other Contributor, and only if You agree to indemnify, | ||
| defend, and hold each Contributor harmless for any liability | ||
| incurred by, or claims asserted against, such Contributor by reason | ||
| of your accepting any such warranty or additional liability. | ||
|
|
||
| END OF TERMS AND CONDITIONS | ||
|
|
||
| APPENDIX: How to apply the Apache License to your work. | ||
|
|
||
| To apply the Apache License to your work, attach the following | ||
| boilerplate notice, with the fields enclosed by brackets "[]" | ||
| replaced with your own identifying information. (Don't include | ||
| the brackets!) The text should be enclosed in the appropriate | ||
| comment syntax for the file format. We also recommend that a | ||
| file or class name and description of purpose be included on the | ||
| same "printed page" as the copyright notice for easier | ||
| identification within third-party archives. | ||
|
|
||
| Copyright [yyyy] [name of copyright owner] | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| LLVM notes | ||
| ---------- | ||
|
|
||
| This directory contains the Google Benchmark source code with some unnecessary | ||
| files removed. Note that this directory is under a different license than | ||
| libc++. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # - Adds a compiler flag if it is supported by the compiler | ||
| # | ||
| # This function checks that the supplied compiler flag is supported and then | ||
| # adds it to the corresponding compiler flags | ||
| # | ||
| # add_cxx_compiler_flag(<FLAG> [<VARIANT>]) | ||
| # | ||
| # - Example | ||
| # | ||
| # include(AddCXXCompilerFlag) | ||
| # add_cxx_compiler_flag(-Wall) | ||
| # add_cxx_compiler_flag(-no-strict-aliasing RELEASE) | ||
| # Requires CMake 2.6+ | ||
|
|
||
| if(__add_cxx_compiler_flag) | ||
| return() | ||
| endif() | ||
| set(__add_cxx_compiler_flag INCLUDED) | ||
|
|
||
| include(CheckCXXCompilerFlag) | ||
|
|
||
| function(add_cxx_compiler_flag FLAG) | ||
| string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG) | ||
| string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG}) | ||
| string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) | ||
| string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) | ||
| set(CMAKE_REQUIRED_FLAGS "${FLAG}") | ||
| check_cxx_compiler_flag("" ${SANITIZED_FLAG}) | ||
| if(${SANITIZED_FLAG}) | ||
| set(VARIANT ${ARGV1}) | ||
| if(ARGV1) | ||
| string(TOUPPER "_${VARIANT}" VARIANT) | ||
| endif() | ||
| set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) | ||
| endif() | ||
| endfunction() | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # - Compile and run code to check for C++ features | ||
| # | ||
| # This functions compiles a source file under the `cmake` folder | ||
| # and adds the corresponding `HAVE_[FILENAME]` flag to the CMake | ||
| # environment | ||
| # | ||
| # cxx_feature_check(<FLAG> [<VARIANT>]) | ||
| # | ||
| # - Example | ||
| # | ||
| # include(CXXFeatureCheck) | ||
| # cxx_feature_check(STD_REGEX) | ||
| # Requires CMake 2.6+ | ||
|
|
||
| if(__cxx_feature_check) | ||
| return() | ||
| endif() | ||
| set(__cxx_feature_check INCLUDED) | ||
|
|
||
| function(cxx_feature_check FILE) | ||
| string(TOLOWER ${FILE} FILE) | ||
| string(TOUPPER ${FILE} VAR) | ||
| string(TOUPPER "HAVE_${VAR}" FEATURE) | ||
| if (DEFINED HAVE_${VAR}) | ||
| return() | ||
| endif() | ||
| message("-- Performing Test ${FEATURE}") | ||
| try_run(RUN_${FEATURE} COMPILE_${FEATURE} | ||
| ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp) | ||
| if(RUN_${FEATURE} EQUAL 0) | ||
| message("-- Performing Test ${FEATURE} -- success") | ||
| set(HAVE_${VAR} 1 CACHE INTERNAL "Feature test for ${FILE}" PARENT_SCOPE) | ||
| add_definitions(-DHAVE_${VAR}) | ||
| else() | ||
| if(NOT COMPILE_${FEATURE}) | ||
| message("-- Performing Test ${FEATURE} -- failed to compile") | ||
| else() | ||
| message("-- Performing Test ${FEATURE} -- compiled but failed to run") | ||
| endif() | ||
| endif() | ||
| endfunction() | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # - Returns a version string from Git tags | ||
| # | ||
| # This function inspects the annotated git tags for the project and returns a string | ||
| # into a CMake variable | ||
| # | ||
| # get_git_version(<var>) | ||
| # | ||
| # - Example | ||
| # | ||
| # include(GetGitVersion) | ||
| # get_git_version(GIT_VERSION) | ||
| # | ||
| # Requires CMake 2.8.11+ | ||
| find_package(Git) | ||
|
|
||
| if(__get_git_version) | ||
| return() | ||
| endif() | ||
| set(__get_git_version INCLUDED) | ||
|
|
||
| function(get_git_version var) | ||
| if(GIT_EXECUTABLE) | ||
| execute_process(COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 | ||
| RESULT_VARIABLE status | ||
| OUTPUT_VARIABLE GIT_VERSION | ||
| ERROR_QUIET) | ||
| if(${status}) | ||
| set(GIT_VERSION "v0.0.0") | ||
| else() | ||
| string(STRIP ${GIT_VERSION} GIT_VERSION) | ||
| string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION}) | ||
| endif() | ||
|
|
||
| # Work out if the repository is dirty | ||
| execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh | ||
| OUTPUT_QUIET | ||
| ERROR_QUIET) | ||
| execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- | ||
| OUTPUT_VARIABLE GIT_DIFF_INDEX | ||
| ERROR_QUIET) | ||
| string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY) | ||
| if (${GIT_DIRTY}) | ||
| set(GIT_VERSION "${GIT_VERSION}-dirty") | ||
| endif() | ||
| else() | ||
| set(GIT_VERSION "v0.0.0") | ||
| endif() | ||
|
|
||
| message("-- git Version: ${GIT_VERSION}") | ||
| set(${var} ${GIT_VERSION} PARENT_SCOPE) | ||
| endfunction() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #include <gnuregex.h> | ||
| #include <string> | ||
| int main() { | ||
| std::string str = "test0159"; | ||
| regex_t re; | ||
| int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); | ||
| if (ec != 0) { | ||
| return ec; | ||
| } | ||
| return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #include <regex.h> | ||
| #include <string> | ||
| int main() { | ||
| std::string str = "test0159"; | ||
| regex_t re; | ||
| int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); | ||
| if (ec != 0) { | ||
| return ec; | ||
| } | ||
| int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; | ||
| regfree(&re); | ||
| return ret; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #include <regex> | ||
| #include <string> | ||
| int main() { | ||
| const std::string str = "test0159"; | ||
| std::regex re; | ||
| re = std::regex("^[a-z]+[0-9]+$", | ||
| std::regex_constants::extended | std::regex_constants::nosubs); | ||
| return std::regex_search(str, re) ? 0 : -1; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #include <chrono> | ||
|
|
||
| int main() { | ||
| typedef std::chrono::steady_clock Clock; | ||
| Clock::time_point tp = Clock::now(); | ||
| ((void)tp); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #define HAVE_THREAD_SAFETY_ATTRIBUTES | ||
| #include "../src/mutex.h" | ||
|
|
||
| int main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| #ifndef BENCHMARK_BENCHMARK_H_ | ||
| #define BENCHMARK_BENCHMARK_H_ | ||
|
|
||
| #include "macros.h" | ||
| #include "benchmark_api.h" | ||
| #include "reporter.h" | ||
|
|
||
| #endif // BENCHMARK_BENCHMARK_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| #ifndef BENCHMARK_MACROS_H_ | ||
| #define BENCHMARK_MACROS_H_ | ||
|
|
||
| #if __cplusplus < 201103L | ||
| # define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ | ||
| TypeName(const TypeName&); \ | ||
| TypeName& operator=(const TypeName&) | ||
| #else | ||
| # define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ | ||
| TypeName(const TypeName&) = delete; \ | ||
| TypeName& operator=(const TypeName&) = delete | ||
| #endif | ||
|
|
||
| #if defined(__GNUC__) | ||
| # define BENCHMARK_UNUSED __attribute__((unused)) | ||
| # define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) | ||
| # define BENCHMARK_NOEXCEPT noexcept | ||
| # define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) | ||
| #elif defined(_MSC_VER) && !defined(__clang__) | ||
| # define BENCHMARK_UNUSED | ||
| # define BENCHMARK_ALWAYS_INLINE __forceinline | ||
| # if _MSC_VER >= 1900 | ||
| # define BENCHMARK_NOEXCEPT noexcept | ||
| # define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) | ||
| # else | ||
| # define BENCHMARK_NOEXCEPT | ||
| # define BENCHMARK_NOEXCEPT_OP(x) | ||
| # endif | ||
| # define __func__ __FUNCTION__ | ||
| #else | ||
| # define BENCHMARK_UNUSED | ||
| # define BENCHMARK_ALWAYS_INLINE | ||
| # define BENCHMARK_NOEXCEPT | ||
| # define BENCHMARK_NOEXCEPT_OP(x) | ||
| #endif | ||
|
|
||
| #if defined(__GNUC__) | ||
| # define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) | ||
| #else | ||
| # define BENCHMARK_BUILTIN_EXPECT(x, y) x | ||
| #endif | ||
|
|
||
| #endif // BENCHMARK_MACROS_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| #ifndef BENCHMARK_REPORTER_H_ | ||
| #define BENCHMARK_REPORTER_H_ | ||
|
|
||
| #include <cassert> | ||
| #include <iosfwd> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include "benchmark_api.h" // For forward declaration of BenchmarkReporter | ||
|
|
||
| namespace benchmark { | ||
|
|
||
| // Interface for custom benchmark result printers. | ||
| // By default, benchmark reports are printed to stdout. However an application | ||
| // can control the destination of the reports by calling | ||
| // RunSpecifiedBenchmarks and passing it a custom reporter object. | ||
| // The reporter object must implement the following interface. | ||
| class BenchmarkReporter { | ||
| public: | ||
| struct Context { | ||
| int num_cpus; | ||
| double mhz_per_cpu; | ||
| bool cpu_scaling_enabled; | ||
|
|
||
| // The number of chars in the longest benchmark name. | ||
| size_t name_field_width; | ||
| }; | ||
|
|
||
| struct Run { | ||
| Run() : | ||
| error_occurred(false), | ||
| iterations(1), | ||
| time_unit(kNanosecond), | ||
| real_accumulated_time(0), | ||
| cpu_accumulated_time(0), | ||
| bytes_per_second(0), | ||
| items_per_second(0), | ||
| max_heapbytes_used(0), | ||
| complexity(oNone), | ||
| complexity_n(0), | ||
| report_big_o(false), | ||
| report_rms(false) {} | ||
|
|
||
| std::string benchmark_name; | ||
| std::string report_label; // Empty if not set by benchmark. | ||
| bool error_occurred; | ||
| std::string error_message; | ||
|
|
||
| int64_t iterations; | ||
| TimeUnit time_unit; | ||
| double real_accumulated_time; | ||
| double cpu_accumulated_time; | ||
|
|
||
| // Return a value representing the real time per iteration in the unit | ||
| // specified by 'time_unit'. | ||
| // NOTE: If 'iterations' is zero the returned value represents the | ||
| // accumulated time. | ||
| double GetAdjustedRealTime() const; | ||
|
|
||
| // Return a value representing the cpu time per iteration in the unit | ||
| // specified by 'time_unit'. | ||
| // NOTE: If 'iterations' is zero the returned value represents the | ||
| // accumulated time. | ||
| double GetAdjustedCPUTime() const; | ||
|
|
||
| // Zero if not set by benchmark. | ||
| double bytes_per_second; | ||
| double items_per_second; | ||
|
|
||
| // This is set to 0.0 if memory tracing is not enabled. | ||
| double max_heapbytes_used; | ||
|
|
||
| // Keep track of arguments to compute asymptotic complexity | ||
| BigO complexity; | ||
| BigOFunc* complexity_lambda; | ||
| int complexity_n; | ||
|
|
||
| // Inform print function whether the current run is a complexity report | ||
| bool report_big_o; | ||
| bool report_rms; | ||
| }; | ||
|
|
||
| // Construct a BenchmarkReporter with the output stream set to 'std::cout' | ||
| // and the error stream set to 'std::cerr' | ||
| BenchmarkReporter(); | ||
|
|
||
| // Called once for every suite of benchmarks run. | ||
| // The parameter "context" contains information that the | ||
| // reporter may wish to use when generating its report, for example the | ||
| // platform under which the benchmarks are running. The benchmark run is | ||
| // never started if this function returns false, allowing the reporter | ||
| // to skip runs based on the context information. | ||
| virtual bool ReportContext(const Context& context) = 0; | ||
|
|
||
| // Called once for each group of benchmark runs, gives information about | ||
| // cpu-time and heap memory usage during the benchmark run. If the group | ||
| // of runs contained more than two entries then 'report' contains additional | ||
| // elements representing the mean and standard deviation of those runs. | ||
| // Additionally if this group of runs was the last in a family of benchmarks | ||
| // 'reports' contains additional entries representing the asymptotic | ||
| // complexity and RMS of that benchmark family. | ||
| virtual void ReportRuns(const std::vector<Run>& report) = 0; | ||
|
|
||
| // Called once and only once after ever group of benchmarks is run and | ||
| // reported. | ||
| virtual void Finalize() {} | ||
|
|
||
| // REQUIRES: The object referenced by 'out' is valid for the lifetime | ||
| // of the reporter. | ||
| void SetOutputStream(std::ostream* out) { | ||
| assert(out); | ||
| output_stream_ = out; | ||
| } | ||
|
|
||
| // REQUIRES: The object referenced by 'err' is valid for the lifetime | ||
| // of the reporter. | ||
| void SetErrorStream(std::ostream* err) { | ||
| assert(err); | ||
| error_stream_ = err; | ||
| } | ||
|
|
||
| std::ostream& GetOutputStream() const { | ||
| return *output_stream_; | ||
| } | ||
|
|
||
| std::ostream& GetErrorStream() const { | ||
| return *error_stream_; | ||
| } | ||
|
|
||
| virtual ~BenchmarkReporter(); | ||
|
|
||
| // Write a human readable string to 'out' representing the specified | ||
| // 'context'. | ||
| // REQUIRES: 'out' is non-null. | ||
| static void PrintBasicContext(std::ostream* out, Context const& context); | ||
|
|
||
| private: | ||
| std::ostream* output_stream_; | ||
| std::ostream* error_stream_; | ||
| }; | ||
|
|
||
| // Simple reporter that outputs benchmark data to the console. This is the | ||
| // default reporter used by RunSpecifiedBenchmarks(). | ||
| class ConsoleReporter : public BenchmarkReporter { | ||
| public: | ||
| virtual bool ReportContext(const Context& context); | ||
| virtual void ReportRuns(const std::vector<Run>& reports); | ||
|
|
||
| protected: | ||
| virtual void PrintRunData(const Run& report); | ||
|
|
||
| size_t name_field_width_; | ||
| }; | ||
|
|
||
| class JSONReporter : public BenchmarkReporter { | ||
| public: | ||
| JSONReporter() : first_report_(true) {} | ||
| virtual bool ReportContext(const Context& context); | ||
| virtual void ReportRuns(const std::vector<Run>& reports); | ||
| virtual void Finalize(); | ||
|
|
||
| private: | ||
| void PrintRunData(const Run& report); | ||
|
|
||
| bool first_report_; | ||
| }; | ||
|
|
||
| class CSVReporter : public BenchmarkReporter { | ||
| public: | ||
| virtual bool ReportContext(const Context& context); | ||
| virtual void ReportRuns(const std::vector<Run>& reports); | ||
|
|
||
| private: | ||
| void PrintRunData(const Run& report); | ||
| }; | ||
|
|
||
| inline const char* GetTimeUnitString(TimeUnit unit) { | ||
| switch (unit) { | ||
| case kMillisecond: | ||
| return "ms"; | ||
| case kMicrosecond: | ||
| return "us"; | ||
| case kNanosecond: | ||
| default: | ||
| return "ns"; | ||
| } | ||
| } | ||
|
|
||
| inline double GetTimeUnitMultiplier(TimeUnit unit) { | ||
| switch (unit) { | ||
| case kMillisecond: | ||
| return 1e3; | ||
| case kMicrosecond: | ||
| return 1e6; | ||
| case kNanosecond: | ||
| default: | ||
| return 1e9; | ||
| } | ||
| } | ||
|
|
||
| } // end namespace benchmark | ||
| #endif // BENCHMARK_REPORTER_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,320 @@ | ||
| #! /usr/bin/env python | ||
| # encoding: utf-8 | ||
|
|
||
| import argparse | ||
| import errno | ||
| import logging | ||
| import os | ||
| import platform | ||
| import re | ||
| import sys | ||
| import subprocess | ||
| import tempfile | ||
|
|
||
| try: | ||
| import winreg | ||
| except ImportError: | ||
| import _winreg as winreg | ||
| try: | ||
| import urllib.request as request | ||
| except ImportError: | ||
| import urllib as request | ||
| try: | ||
| import urllib.parse as parse | ||
| except ImportError: | ||
| import urlparse as parse | ||
|
|
||
| class EmptyLogger(object): | ||
| ''' | ||
| Provides an implementation that performs no logging | ||
| ''' | ||
| def debug(self, *k, **kw): | ||
| pass | ||
| def info(self, *k, **kw): | ||
| pass | ||
| def warn(self, *k, **kw): | ||
| pass | ||
| def error(self, *k, **kw): | ||
| pass | ||
| def critical(self, *k, **kw): | ||
| pass | ||
| def setLevel(self, *k, **kw): | ||
| pass | ||
|
|
||
| urls = ( | ||
| 'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20' | ||
| 'targetting%20Win32/Personal%20Builds/mingw-builds/installer/' | ||
| 'repository.txt', | ||
| 'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/' | ||
| 'repository.txt' | ||
| ) | ||
| ''' | ||
| A list of mingw-build repositories | ||
| ''' | ||
|
|
||
| def repository(urls = urls, log = EmptyLogger()): | ||
| ''' | ||
| Downloads and parse mingw-build repository files and parses them | ||
| ''' | ||
| log.info('getting mingw-builds repository') | ||
| versions = {} | ||
| re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files') | ||
| re_sub = r'http://downloads.sourceforge.net/project/\1' | ||
| for url in urls: | ||
| log.debug(' - requesting: %s', url) | ||
| socket = request.urlopen(url) | ||
| repo = socket.read() | ||
| if not isinstance(repo, str): | ||
| repo = repo.decode(); | ||
| socket.close() | ||
| for entry in repo.split('\n')[:-1]: | ||
| value = entry.split('|') | ||
| version = tuple([int(n) for n in value[0].strip().split('.')]) | ||
| version = versions.setdefault(version, {}) | ||
| arch = value[1].strip() | ||
| if arch == 'x32': | ||
| arch = 'i686' | ||
| elif arch == 'x64': | ||
| arch = 'x86_64' | ||
| arch = version.setdefault(arch, {}) | ||
| threading = arch.setdefault(value[2].strip(), {}) | ||
| exceptions = threading.setdefault(value[3].strip(), {}) | ||
| revision = exceptions.setdefault(int(value[4].strip()[3:]), | ||
| re_sourceforge.sub(re_sub, value[5].strip())) | ||
| return versions | ||
|
|
||
| def find_in_path(file, path=None): | ||
| ''' | ||
| Attempts to find an executable in the path | ||
| ''' | ||
| if platform.system() == 'Windows': | ||
| file += '.exe' | ||
| if path is None: | ||
| path = os.environ.get('PATH', '') | ||
| if type(path) is type(''): | ||
| path = path.split(os.pathsep) | ||
| return list(filter(os.path.exists, | ||
| map(lambda dir, file=file: os.path.join(dir, file), path))) | ||
|
|
||
| def find_7zip(log = EmptyLogger()): | ||
| ''' | ||
| Attempts to find 7zip for unpacking the mingw-build archives | ||
| ''' | ||
| log.info('finding 7zip') | ||
| path = find_in_path('7z') | ||
| if not path: | ||
| key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip') | ||
| path, _ = winreg.QueryValueEx(key, 'Path') | ||
| path = [os.path.join(path, '7z.exe')] | ||
| log.debug('found \'%s\'', path[0]) | ||
| return path[0] | ||
|
|
||
| find_7zip() | ||
|
|
||
| def unpack(archive, location, log = EmptyLogger()): | ||
| ''' | ||
| Unpacks a mingw-builds archive | ||
| ''' | ||
| sevenzip = find_7zip(log) | ||
| log.info('unpacking %s', os.path.basename(archive)) | ||
| cmd = [sevenzip, 'x', archive, '-o' + location, '-y'] | ||
| log.debug(' - %r', cmd) | ||
| with open(os.devnull, 'w') as devnull: | ||
| subprocess.check_call(cmd, stdout = devnull) | ||
|
|
||
| def download(url, location, log = EmptyLogger()): | ||
| ''' | ||
| Downloads and unpacks a mingw-builds archive | ||
| ''' | ||
| log.info('downloading MinGW') | ||
| log.debug(' - url: %s', url) | ||
| log.debug(' - location: %s', location) | ||
|
|
||
| re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*') | ||
|
|
||
| stream = request.urlopen(url) | ||
| try: | ||
| content = stream.getheader('Content-Disposition') or '' | ||
| except AttributeError: | ||
| content = stream.headers.getheader('Content-Disposition') or '' | ||
| matches = re_content.match(content) | ||
| if matches: | ||
| filename = matches.group(2) | ||
| else: | ||
| parsed = parse.urlparse(stream.geturl()) | ||
| filename = os.path.basename(parsed.path) | ||
|
|
||
| try: | ||
| os.makedirs(location) | ||
| except OSError as e: | ||
| if e.errno == errno.EEXIST and os.path.isdir(location): | ||
| pass | ||
| else: | ||
| raise | ||
|
|
||
| archive = os.path.join(location, filename) | ||
| with open(archive, 'wb') as out: | ||
| while True: | ||
| buf = stream.read(1024) | ||
| if not buf: | ||
| break | ||
| out.write(buf) | ||
| unpack(archive, location, log = log) | ||
| os.remove(archive) | ||
|
|
||
| possible = os.path.join(location, 'mingw64') | ||
| if not os.path.exists(possible): | ||
| possible = os.path.join(location, 'mingw32') | ||
| if not os.path.exists(possible): | ||
| raise ValueError('Failed to find unpacked MinGW: ' + possible) | ||
| return possible | ||
|
|
||
| def root(location = None, arch = None, version = None, threading = None, | ||
| exceptions = None, revision = None, log = EmptyLogger()): | ||
| ''' | ||
| Returns the root folder of a specific version of the mingw-builds variant | ||
| of gcc. Will download the compiler if needed | ||
| ''' | ||
|
|
||
| # Get the repository if we don't have all the information | ||
| if not (arch and version and threading and exceptions and revision): | ||
| versions = repository(log = log) | ||
|
|
||
| # Determine some defaults | ||
| version = version or max(versions.keys()) | ||
| if not arch: | ||
| arch = platform.machine().lower() | ||
| if arch == 'x86': | ||
| arch = 'i686' | ||
| elif arch == 'amd64': | ||
| arch = 'x86_64' | ||
| if not threading: | ||
| keys = versions[version][arch].keys() | ||
| if 'posix' in keys: | ||
| threading = 'posix' | ||
| elif 'win32' in keys: | ||
| threading = 'win32' | ||
| else: | ||
| threading = keys[0] | ||
| if not exceptions: | ||
| keys = versions[version][arch][threading].keys() | ||
| if 'seh' in keys: | ||
| exceptions = 'seh' | ||
| elif 'sjlj' in keys: | ||
| exceptions = 'sjlj' | ||
| else: | ||
| exceptions = keys[0] | ||
| if revision == None: | ||
| revision = max(versions[version][arch][threading][exceptions].keys()) | ||
| if not location: | ||
| location = os.path.join(tempfile.gettempdir(), 'mingw-builds') | ||
|
|
||
| # Get the download url | ||
| url = versions[version][arch][threading][exceptions][revision] | ||
|
|
||
| # Tell the user whatzzup | ||
| log.info('finding MinGW %s', '.'.join(str(v) for v in version)) | ||
| log.debug(' - arch: %s', arch) | ||
| log.debug(' - threading: %s', threading) | ||
| log.debug(' - exceptions: %s', exceptions) | ||
| log.debug(' - revision: %s', revision) | ||
| log.debug(' - url: %s', url) | ||
|
|
||
| # Store each specific revision differently | ||
| slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}' | ||
| slug = slug.format( | ||
| version = '.'.join(str(v) for v in version), | ||
| arch = arch, | ||
| threading = threading, | ||
| exceptions = exceptions, | ||
| revision = revision | ||
| ) | ||
| if arch == 'x86_64': | ||
| root_dir = os.path.join(location, slug, 'mingw64') | ||
| elif arch == 'i686': | ||
| root_dir = os.path.join(location, slug, 'mingw32') | ||
| else: | ||
| raise ValueError('Unknown MinGW arch: ' + arch) | ||
|
|
||
| # Download if needed | ||
| if not os.path.exists(root_dir): | ||
| downloaded = download(url, os.path.join(location, slug), log = log) | ||
| if downloaded != root_dir: | ||
| raise ValueError('The location of mingw did not match\n%s\n%s' | ||
| % (downloaded, root_dir)) | ||
|
|
||
| return root_dir | ||
|
|
||
| def str2ver(string): | ||
| ''' | ||
| Converts a version string into a tuple | ||
| ''' | ||
| try: | ||
| version = tuple(int(v) for v in string.split('.')) | ||
| if len(version) is not 3: | ||
| raise ValueError() | ||
| except ValueError: | ||
| raise argparse.ArgumentTypeError( | ||
| 'please provide a three digit version string') | ||
| return version | ||
|
|
||
| def main(): | ||
| ''' | ||
| Invoked when the script is run directly by the python interpreter | ||
| ''' | ||
| parser = argparse.ArgumentParser( | ||
| description = 'Downloads a specific version of MinGW', | ||
| formatter_class = argparse.ArgumentDefaultsHelpFormatter | ||
| ) | ||
| parser.add_argument('--location', | ||
| help = 'the location to download the compiler to', | ||
| default = os.path.join(tempfile.gettempdir(), 'mingw-builds')) | ||
| parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'], | ||
| help = 'the target MinGW architecture string') | ||
| parser.add_argument('--version', type = str2ver, | ||
| help = 'the version of GCC to download') | ||
| parser.add_argument('--threading', choices = ['posix', 'win32'], | ||
| help = 'the threading type of the compiler') | ||
| parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'], | ||
| help = 'the method to throw exceptions') | ||
| parser.add_argument('--revision', type=int, | ||
| help = 'the revision of the MinGW release') | ||
| group = parser.add_mutually_exclusive_group() | ||
| group.add_argument('-v', '--verbose', action='store_true', | ||
| help='increase the script output verbosity') | ||
| group.add_argument('-q', '--quiet', action='store_true', | ||
| help='only print errors and warning') | ||
| args = parser.parse_args() | ||
|
|
||
| # Create the logger | ||
| logger = logging.getLogger('mingw') | ||
| handler = logging.StreamHandler() | ||
| formatter = logging.Formatter('%(message)s') | ||
| handler.setFormatter(formatter) | ||
| logger.addHandler(handler) | ||
| logger.setLevel(logging.INFO) | ||
| if args.quiet: | ||
| logger.setLevel(logging.WARN) | ||
| if args.verbose: | ||
| logger.setLevel(logging.DEBUG) | ||
|
|
||
| # Get MinGW | ||
| root_dir = root(location = args.location, arch = args.arch, | ||
| version = args.version, threading = args.threading, | ||
| exceptions = args.exceptions, revision = args.revision, | ||
| log = logger) | ||
|
|
||
| sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin')) | ||
|
|
||
| if __name__ == '__main__': | ||
| try: | ||
| main() | ||
| except IOError as e: | ||
| sys.stderr.write('IO error: %s\n' % e) | ||
| sys.exit(1) | ||
| except OSError as e: | ||
| sys.stderr.write('OS error: %s\n' % e) | ||
| sys.exit(1) | ||
| except KeyboardInterrupt as e: | ||
| sys.stderr.write('Killed\n') | ||
| sys.exit(1) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # Allow the source files to find headers in src/ | ||
| include_directories(${PROJECT_SOURCE_DIR}/src) | ||
|
|
||
| # Define the source files | ||
| set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc" | ||
| "console_reporter.cc" "csv_reporter.cc" "json_reporter.cc" | ||
| "log.cc" "reporter.cc" "sleep.cc" "string_util.cc" | ||
| "sysinfo.cc" "walltime.cc" "complexity.cc") | ||
| # Determine the correct regular expression engine to use | ||
| if(HAVE_STD_REGEX) | ||
| set(RE_FILES "re_std.cc") | ||
| elseif(HAVE_GNU_POSIX_REGEX) | ||
| set(RE_FILES "re_posix.cc") | ||
| elseif(HAVE_POSIX_REGEX) | ||
| set(RE_FILES "re_posix.cc") | ||
| else() | ||
| message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") | ||
| endif() | ||
|
|
||
| add_library(benchmark ${SOURCE_FILES} ${RE_FILES}) | ||
|
|
||
|
|
||
| set_target_properties(benchmark PROPERTIES | ||
| OUTPUT_NAME "benchmark" | ||
| VERSION ${GENERIC_LIB_VERSION} | ||
| SOVERSION ${GENERIC_LIB_SOVERSION} | ||
| ) | ||
|
|
||
| # Link threads. | ||
| target_link_libraries(benchmark ${CMAKE_THREAD_LIBS_INIT}) | ||
|
|
||
| # We need extra libraries on Windows | ||
| if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") | ||
| target_link_libraries(benchmark Shlwapi) | ||
| endif() | ||
|
|
||
| # Expose public API | ||
| target_include_directories(benchmark PUBLIC ${PROJECT_SOURCE_DIR}/include) | ||
|
|
||
| # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable) | ||
| install( | ||
| TARGETS benchmark | ||
| ARCHIVE DESTINATION lib | ||
| LIBRARY DESTINATION lib | ||
| RUNTIME DESTINATION bin | ||
| COMPONENT library) | ||
|
|
||
| install( | ||
| DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark" | ||
| DESTINATION include | ||
| FILES_MATCHING PATTERN "*.*h") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #ifndef BENCHMARK_ARRAYSIZE_H_ | ||
| #define BENCHMARK_ARRAYSIZE_H_ | ||
|
|
||
| #include "internal_macros.h" | ||
|
|
||
| namespace benchmark { | ||
| namespace internal { | ||
| // The arraysize(arr) macro returns the # of elements in an array arr. | ||
| // The expression is a compile-time constant, and therefore can be | ||
| // used in defining new arrays, for example. If you use arraysize on | ||
| // a pointer by mistake, you will get a compile-time error. | ||
| // | ||
|
|
||
|
|
||
| // This template function declaration is used in defining arraysize. | ||
| // Note that the function doesn't need an implementation, as we only | ||
| // use its type. | ||
| template <typename T, size_t N> | ||
| char (&ArraySizeHelper(T (&array)[N]))[N]; | ||
|
|
||
| // That gcc wants both of these prototypes seems mysterious. VC, for | ||
| // its part, can't decide which to use (another mystery). Matching of | ||
| // template overloads: the final frontier. | ||
| #ifndef COMPILER_MSVC | ||
| template <typename T, size_t N> | ||
| char (&ArraySizeHelper(const T (&array)[N]))[N]; | ||
| #endif | ||
|
|
||
| #define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array))) | ||
|
|
||
| } // end namespace internal | ||
| } // end namespace benchmark | ||
|
|
||
| #endif // BENCHMARK_ARRAYSIZE_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| #ifndef CHECK_H_ | ||
| #define CHECK_H_ | ||
|
|
||
| #include <cstdlib> | ||
| #include <ostream> | ||
|
|
||
| #include "internal_macros.h" | ||
| #include "log.h" | ||
|
|
||
| namespace benchmark { | ||
| namespace internal { | ||
|
|
||
| typedef void(AbortHandlerT)(); | ||
|
|
||
| inline AbortHandlerT*& GetAbortHandler() { | ||
| static AbortHandlerT* handler = &std::abort; | ||
| return handler; | ||
| } | ||
|
|
||
| BENCHMARK_NORETURN inline void CallAbortHandler() { | ||
| GetAbortHandler()(); | ||
| std::abort(); // fallback to enforce noreturn | ||
| } | ||
|
|
||
| // CheckHandler is the class constructed by failing CHECK macros. CheckHandler | ||
| // will log information about the failures and abort when it is destructed. | ||
| class CheckHandler { | ||
| public: | ||
| CheckHandler(const char* check, const char* file, const char* func, int line) | ||
| : log_(GetErrorLogInstance()) | ||
| { | ||
| log_ << file << ":" << line << ": " << func << ": Check `" | ||
| << check << "' failed. "; | ||
| } | ||
|
|
||
| std::ostream& GetLog() { | ||
| return log_; | ||
| } | ||
|
|
||
| BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) { | ||
| log_ << std::endl; | ||
| CallAbortHandler(); | ||
| } | ||
|
|
||
| CheckHandler & operator=(const CheckHandler&) = delete; | ||
| CheckHandler(const CheckHandler&) = delete; | ||
| CheckHandler() = delete; | ||
| private: | ||
| std::ostream& log_; | ||
| }; | ||
|
|
||
| } // end namespace internal | ||
| } // end namespace benchmark | ||
|
|
||
| // The CHECK macro returns a std::ostream object that can have extra information | ||
| // written to it. | ||
| #ifndef NDEBUG | ||
| # define CHECK(b) (b ? ::benchmark::internal::GetNullLogInstance() \ | ||
| : ::benchmark::internal::CheckHandler( \ | ||
| #b, __FILE__, __func__, __LINE__).GetLog()) | ||
| #else | ||
| # define CHECK(b) ::benchmark::internal::GetNullLogInstance() | ||
| #endif | ||
|
|
||
| #define CHECK_EQ(a, b) CHECK((a) == (b)) | ||
| #define CHECK_NE(a, b) CHECK((a) != (b)) | ||
| #define CHECK_GE(a, b) CHECK((a) >= (b)) | ||
| #define CHECK_LE(a, b) CHECK((a) <= (b)) | ||
| #define CHECK_GT(a, b) CHECK((a) > (b)) | ||
| #define CHECK_LT(a, b) CHECK((a) < (b)) | ||
|
|
||
| #endif // CHECK_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #include "colorprint.h" | ||
|
|
||
| #include <cstdarg> | ||
| #include <cstdio> | ||
| #include <cstdarg> | ||
| #include <string> | ||
| #include <memory> | ||
|
|
||
| #include "commandlineflags.h" | ||
| #include "check.h" | ||
| #include "internal_macros.h" | ||
|
|
||
| #ifdef BENCHMARK_OS_WINDOWS | ||
| #include <Windows.h> | ||
| #endif | ||
|
|
||
| DECLARE_bool(color_print); | ||
|
|
||
| namespace benchmark { | ||
| namespace { | ||
| #ifdef BENCHMARK_OS_WINDOWS | ||
| typedef WORD PlatformColorCode; | ||
| #else | ||
| typedef const char* PlatformColorCode; | ||
| #endif | ||
|
|
||
| PlatformColorCode GetPlatformColorCode(LogColor color) { | ||
| #ifdef BENCHMARK_OS_WINDOWS | ||
| switch (color) { | ||
| case COLOR_RED: | ||
| return FOREGROUND_RED; | ||
| case COLOR_GREEN: | ||
| return FOREGROUND_GREEN; | ||
| case COLOR_YELLOW: | ||
| return FOREGROUND_RED | FOREGROUND_GREEN; | ||
| case COLOR_BLUE: | ||
| return FOREGROUND_BLUE; | ||
| case COLOR_MAGENTA: | ||
| return FOREGROUND_BLUE | FOREGROUND_RED; | ||
| case COLOR_CYAN: | ||
| return FOREGROUND_BLUE | FOREGROUND_GREEN; | ||
| case COLOR_WHITE: // fall through to default | ||
| default: | ||
| return 0; | ||
| } | ||
| #else | ||
| switch (color) { | ||
| case COLOR_RED: | ||
| return "1"; | ||
| case COLOR_GREEN: | ||
| return "2"; | ||
| case COLOR_YELLOW: | ||
| return "3"; | ||
| case COLOR_BLUE: | ||
| return "4"; | ||
| case COLOR_MAGENTA: | ||
| return "5"; | ||
| case COLOR_CYAN: | ||
| return "6"; | ||
| case COLOR_WHITE: | ||
| return "7"; | ||
| default: | ||
| return nullptr; | ||
| }; | ||
| #endif | ||
| } | ||
|
|
||
| } // end namespace | ||
|
|
||
| std::string FormatString(const char *msg, va_list args) { | ||
| // we might need a second shot at this, so pre-emptivly make a copy | ||
| va_list args_cp; | ||
| va_copy(args_cp, args); | ||
|
|
||
| std::size_t size = 256; | ||
| char local_buff[256]; | ||
| auto ret = std::vsnprintf(local_buff, size, msg, args_cp); | ||
|
|
||
| va_end(args_cp); | ||
|
|
||
| // currently there is no error handling for failure, so this is hack. | ||
| CHECK(ret >= 0); | ||
|
|
||
| if (ret == 0) // handle empty expansion | ||
| return {}; | ||
| else if (static_cast<size_t>(ret) < size) | ||
| return local_buff; | ||
| else { | ||
| // we did not provide a long enough buffer on our first attempt. | ||
| size = (size_t)ret + 1; // + 1 for the null byte | ||
| std::unique_ptr<char[]> buff(new char[size]); | ||
| ret = std::vsnprintf(buff.get(), size, msg, args); | ||
| CHECK(ret > 0 && ((size_t)ret) < size); | ||
| return buff.get(); | ||
| } | ||
| } | ||
|
|
||
| std::string FormatString(const char *msg, ...) { | ||
| va_list args; | ||
| va_start(args, msg); | ||
| auto tmp = FormatString(msg, args); | ||
| va_end(args); | ||
| return tmp; | ||
| } | ||
|
|
||
| void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { | ||
| va_list args; | ||
| va_start(args, fmt); | ||
|
|
||
| if (!FLAGS_color_print) { | ||
| out << FormatString(fmt, args); | ||
| va_end(args); | ||
| return; | ||
| } | ||
|
|
||
| #ifdef BENCHMARK_OS_WINDOWS | ||
| const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); | ||
|
|
||
| // Gets the current text color. | ||
| CONSOLE_SCREEN_BUFFER_INFO buffer_info; | ||
| GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); | ||
| const WORD old_color_attrs = buffer_info.wAttributes; | ||
|
|
||
| // We need to flush the stream buffers into the console before each | ||
| // SetConsoleTextAttribute call lest it affect the text that is already | ||
| // printed but has not yet reached the console. | ||
| fflush(stdout); | ||
| SetConsoleTextAttribute(stdout_handle, | ||
| GetPlatformColorCode(color) | FOREGROUND_INTENSITY); | ||
| vprintf(fmt, args); | ||
|
|
||
| fflush(stdout); | ||
| // Restores the text color. | ||
| SetConsoleTextAttribute(stdout_handle, old_color_attrs); | ||
| #else | ||
| const char* color_code = GetPlatformColorCode(color); | ||
| if (color_code) out << FormatString("\033[0;3%sm", color_code); | ||
| out << FormatString(fmt, args) << "\033[m"; | ||
| #endif | ||
|
|
||
| va_end(args); | ||
| } | ||
|
|
||
| } // end namespace benchmark |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #ifndef BENCHMARK_COLORPRINT_H_ | ||
| #define BENCHMARK_COLORPRINT_H_ | ||
|
|
||
| #include <cstdarg> | ||
| #include <string> | ||
| #include <iostream> | ||
|
|
||
| namespace benchmark { | ||
| enum LogColor { | ||
| COLOR_DEFAULT, | ||
| COLOR_RED, | ||
| COLOR_GREEN, | ||
| COLOR_YELLOW, | ||
| COLOR_BLUE, | ||
| COLOR_MAGENTA, | ||
| COLOR_CYAN, | ||
| COLOR_WHITE | ||
| }; | ||
|
|
||
| std::string FormatString(const char* msg, va_list args); | ||
| std::string FormatString(const char* msg, ...); | ||
|
|
||
| void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...); | ||
|
|
||
| } // end namespace benchmark | ||
|
|
||
| #endif // BENCHMARK_COLORPRINT_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #include "commandlineflags.h" | ||
|
|
||
| #include <cstdlib> | ||
| #include <cstring> | ||
| #include <iostream> | ||
| #include <limits> | ||
|
|
||
| namespace benchmark { | ||
| // Parses 'str' for a 32-bit signed integer. If successful, writes | ||
| // the result to *value and returns true; otherwise leaves *value | ||
| // unchanged and returns false. | ||
| bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { | ||
| // Parses the environment variable as a decimal integer. | ||
| char* end = nullptr; | ||
| const long long_value = strtol(str, &end, 10); // NOLINT | ||
|
|
||
| // Has strtol() consumed all characters in the string? | ||
| if (*end != '\0') { | ||
| // No - an invalid character was encountered. | ||
| std::cerr << src_text << " is expected to be a 32-bit integer, " | ||
| << "but actually has value \"" << str << "\".\n"; | ||
| return false; | ||
| } | ||
|
|
||
| // Is the parsed value in the range of an Int32? | ||
| const int32_t result = static_cast<int32_t>(long_value); | ||
| if (long_value == std::numeric_limits<long>::max() || | ||
| long_value == std::numeric_limits<long>::min() || | ||
| // The parsed value overflows as a long. (strtol() returns | ||
| // LONG_MAX or LONG_MIN when the input overflows.) | ||
| result != long_value | ||
| // The parsed value overflows as an Int32. | ||
| ) { | ||
| std::cerr << src_text << " is expected to be a 32-bit integer, " | ||
| << "but actually has value \"" << str << "\", " | ||
| << "which overflows.\n"; | ||
| return false; | ||
| } | ||
|
|
||
| *value = result; | ||
| return true; | ||
| } | ||
|
|
||
| // Parses 'str' for a double. If successful, writes the result to *value and | ||
| // returns true; otherwise leaves *value unchanged and returns false. | ||
| bool ParseDouble(const std::string& src_text, const char* str, double* value) { | ||
| // Parses the environment variable as a decimal integer. | ||
| char* end = nullptr; | ||
| const double double_value = strtod(str, &end); // NOLINT | ||
|
|
||
| // Has strtol() consumed all characters in the string? | ||
| if (*end != '\0') { | ||
| // No - an invalid character was encountered. | ||
| std::cerr << src_text << " is expected to be a double, " | ||
| << "but actually has value \"" << str << "\".\n"; | ||
| return false; | ||
| } | ||
|
|
||
| *value = double_value; | ||
| return true; | ||
| } | ||
|
|
||
| inline const char* GetEnv(const char* name) { | ||
| #if defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) | ||
| // Environment variables which we programmatically clear will be set to the | ||
| // empty string rather than unset (nullptr). Handle that case. | ||
| const char* const env = getenv(name); | ||
| return (env != nullptr && env[0] != '\0') ? env : nullptr; | ||
| #else | ||
| return getenv(name); | ||
| #endif | ||
| } | ||
|
|
||
| // Returns the name of the environment variable corresponding to the | ||
| // given flag. For example, FlagToEnvVar("foo") will return | ||
| // "BENCHMARK_FOO" in the open-source version. | ||
| static std::string FlagToEnvVar(const char* flag) { | ||
| const std::string flag_str(flag); | ||
|
|
||
| std::string env_var; | ||
| for (size_t i = 0; i != flag_str.length(); ++i) | ||
| env_var += static_cast<char>(::toupper(flag_str.c_str()[i])); | ||
|
|
||
| return "BENCHMARK_" + env_var; | ||
| } | ||
|
|
||
| // Reads and returns the Boolean environment variable corresponding to | ||
| // the given flag; if it's not set, returns default_value. | ||
| // | ||
| // The value is considered true iff it's not "0". | ||
| bool BoolFromEnv(const char* flag, bool default_value) { | ||
| const std::string env_var = FlagToEnvVar(flag); | ||
| const char* const string_value = GetEnv(env_var.c_str()); | ||
| return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0; | ||
| } | ||
|
|
||
| // Reads and returns a 32-bit integer stored in the environment | ||
| // variable corresponding to the given flag; if it isn't set or | ||
| // doesn't represent a valid 32-bit integer, returns default_value. | ||
| int32_t Int32FromEnv(const char* flag, int32_t default_value) { | ||
| const std::string env_var = FlagToEnvVar(flag); | ||
| const char* const string_value = GetEnv(env_var.c_str()); | ||
| if (string_value == nullptr) { | ||
| // The environment variable is not set. | ||
| return default_value; | ||
| } | ||
|
|
||
| int32_t result = default_value; | ||
| if (!ParseInt32(std::string("Environment variable ") + env_var, string_value, | ||
| &result)) { | ||
| std::cout << "The default value " << default_value << " is used.\n"; | ||
| return default_value; | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| // Reads and returns the string environment variable corresponding to | ||
| // the given flag; if it's not set, returns default_value. | ||
| const char* StringFromEnv(const char* flag, const char* default_value) { | ||
| const std::string env_var = FlagToEnvVar(flag); | ||
| const char* const value = GetEnv(env_var.c_str()); | ||
| return value == nullptr ? default_value : value; | ||
| } | ||
|
|
||
| // Parses a string as a command line flag. The string should have | ||
| // the format "--flag=value". When def_optional is true, the "=value" | ||
| // part can be omitted. | ||
| // | ||
| // Returns the value of the flag, or nullptr if the parsing failed. | ||
| const char* ParseFlagValue(const char* str, const char* flag, | ||
| bool def_optional) { | ||
| // str and flag must not be nullptr. | ||
| if (str == nullptr || flag == nullptr) return nullptr; | ||
|
|
||
| // The flag must start with "--". | ||
| const std::string flag_str = std::string("--") + std::string(flag); | ||
| const size_t flag_len = flag_str.length(); | ||
| if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; | ||
|
|
||
| // Skips the flag name. | ||
| const char* flag_end = str + flag_len; | ||
|
|
||
| // When def_optional is true, it's OK to not have a "=value" part. | ||
| if (def_optional && (flag_end[0] == '\0')) return flag_end; | ||
|
|
||
| // If def_optional is true and there are more characters after the | ||
| // flag name, or if def_optional is false, there must be a '=' after | ||
| // the flag name. | ||
| if (flag_end[0] != '=') return nullptr; | ||
|
|
||
| // Returns the string after "=". | ||
| return flag_end + 1; | ||
| } | ||
|
|
||
| bool ParseBoolFlag(const char* str, const char* flag, bool* value) { | ||
| // Gets the value of the flag as a string. | ||
| const char* const value_str = ParseFlagValue(str, flag, true); | ||
|
|
||
| // Aborts if the parsing failed. | ||
| if (value_str == nullptr) return false; | ||
|
|
||
| // Converts the string value to a bool. | ||
| *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); | ||
| return true; | ||
| } | ||
|
|
||
| bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { | ||
| // Gets the value of the flag as a string. | ||
| const char* const value_str = ParseFlagValue(str, flag, false); | ||
|
|
||
| // Aborts if the parsing failed. | ||
| if (value_str == nullptr) return false; | ||
|
|
||
| // Sets *value to the value of the flag. | ||
| return ParseInt32(std::string("The value of flag --") + flag, value_str, | ||
| value); | ||
| } | ||
|
|
||
| bool ParseDoubleFlag(const char* str, const char* flag, double* value) { | ||
| // Gets the value of the flag as a string. | ||
| const char* const value_str = ParseFlagValue(str, flag, false); | ||
|
|
||
| // Aborts if the parsing failed. | ||
| if (value_str == nullptr) return false; | ||
|
|
||
| // Sets *value to the value of the flag. | ||
| return ParseDouble(std::string("The value of flag --") + flag, value_str, | ||
| value); | ||
| } | ||
|
|
||
| bool ParseStringFlag(const char* str, const char* flag, std::string* value) { | ||
| // Gets the value of the flag as a string. | ||
| const char* const value_str = ParseFlagValue(str, flag, false); | ||
|
|
||
| // Aborts if the parsing failed. | ||
| if (value_str == nullptr) return false; | ||
|
|
||
| *value = value_str; | ||
| return true; | ||
| } | ||
|
|
||
| bool IsFlag(const char* str, const char* flag) { | ||
| return (ParseFlagValue(str, flag, true) != nullptr); | ||
| } | ||
| } // end namespace benchmark |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #ifndef BENCHMARK_COMMANDLINEFLAGS_H_ | ||
| #define BENCHMARK_COMMANDLINEFLAGS_H_ | ||
|
|
||
| #include <cstdint> | ||
| #include <string> | ||
|
|
||
| // Macro for referencing flags. | ||
| #define FLAG(name) FLAGS_##name | ||
|
|
||
| // Macros for declaring flags. | ||
| #define DECLARE_bool(name) extern bool FLAG(name) | ||
| #define DECLARE_int32(name) extern int32_t FLAG(name) | ||
| #define DECLARE_int64(name) extern int64_t FLAG(name) | ||
| #define DECLARE_double(name) extern double FLAG(name) | ||
| #define DECLARE_string(name) extern std::string FLAG(name) | ||
|
|
||
| // Macros for defining flags. | ||
| #define DEFINE_bool(name, default_val, doc) bool FLAG(name) = (default_val) | ||
| #define DEFINE_int32(name, default_val, doc) int32_t FLAG(name) = (default_val) | ||
| #define DEFINE_int64(name, default_val, doc) int64_t FLAG(name) = (default_val) | ||
| #define DEFINE_double(name, default_val, doc) double FLAG(name) = (default_val) | ||
| #define DEFINE_string(name, default_val, doc) \ | ||
| std::string FLAG(name) = (default_val) | ||
|
|
||
| namespace benchmark { | ||
| // Parses 'str' for a 32-bit signed integer. If successful, writes the result | ||
| // to *value and returns true; otherwise leaves *value unchanged and returns | ||
| // false. | ||
| bool ParseInt32(const std::string& src_text, const char* str, int32_t* value); | ||
|
|
||
| // Parses a bool/Int32/string from the environment variable | ||
| // corresponding to the given Google Test flag. | ||
| bool BoolFromEnv(const char* flag, bool default_val); | ||
| int32_t Int32FromEnv(const char* flag, int32_t default_val); | ||
| double DoubleFromEnv(const char* flag, double default_val); | ||
| const char* StringFromEnv(const char* flag, const char* default_val); | ||
|
|
||
| // Parses a string for a bool flag, in the form of either | ||
| // "--flag=value" or "--flag". | ||
| // | ||
| // In the former case, the value is taken as true as long as it does | ||
| // not start with '0', 'f', or 'F'. | ||
| // | ||
| // In the latter case, the value is taken as true. | ||
| // | ||
| // On success, stores the value of the flag in *value, and returns | ||
| // true. On failure, returns false without changing *value. | ||
| bool ParseBoolFlag(const char* str, const char* flag, bool* value); | ||
|
|
||
| // Parses a string for an Int32 flag, in the form of | ||
| // "--flag=value". | ||
| // | ||
| // On success, stores the value of the flag in *value, and returns | ||
| // true. On failure, returns false without changing *value. | ||
| bool ParseInt32Flag(const char* str, const char* flag, int32_t* value); | ||
|
|
||
| // Parses a string for a Double flag, in the form of | ||
| // "--flag=value". | ||
| // | ||
| // On success, stores the value of the flag in *value, and returns | ||
| // true. On failure, returns false without changing *value. | ||
| bool ParseDoubleFlag(const char* str, const char* flag, double* value); | ||
|
|
||
| // Parses a string for a string flag, in the form of | ||
| // "--flag=value". | ||
| // | ||
| // On success, stores the value of the flag in *value, and returns | ||
| // true. On failure, returns false without changing *value. | ||
| bool ParseStringFlag(const char* str, const char* flag, std::string* value); | ||
|
|
||
| // Returns true if the string matches the flag. | ||
| bool IsFlag(const char* str, const char* flag); | ||
|
|
||
| } // end namespace benchmark | ||
|
|
||
| #endif // BENCHMARK_COMMANDLINEFLAGS_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,283 @@ | ||
| // Copyright 2016 Ismael Jimenez Martinez. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| // Source project : https://github.com/ismaelJimenez/cpp.leastsq | ||
| // Adapted to be used with google benchmark | ||
|
|
||
| #include "benchmark/benchmark_api.h" | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
| #include "check.h" | ||
| #include "complexity.h" | ||
| #include "stat.h" | ||
|
|
||
| namespace benchmark { | ||
|
|
||
| // Internal function to calculate the different scalability forms | ||
| BigOFunc* FittingCurve(BigO complexity) { | ||
| switch (complexity) { | ||
| case oN: | ||
| return [](int n) -> double { return n; }; | ||
| case oNSquared: | ||
| return [](int n) -> double { return n * n; }; | ||
| case oNCubed: | ||
| return [](int n) -> double { return n * n * n; }; | ||
| case oLogN: | ||
| return [](int n) { return std::log2(n); }; | ||
| case oNLogN: | ||
| return [](int n) { return n * std::log2(n); }; | ||
| case o1: | ||
| default: | ||
| return [](int) { return 1.0; }; | ||
| } | ||
| } | ||
|
|
||
| // Function to return an string for the calculated complexity | ||
| std::string GetBigOString(BigO complexity) { | ||
| switch (complexity) { | ||
| case oN: | ||
| return "N"; | ||
| case oNSquared: | ||
| return "N^2"; | ||
| case oNCubed: | ||
| return "N^3"; | ||
| case oLogN: | ||
| return "lgN"; | ||
| case oNLogN: | ||
| return "NlgN"; | ||
| case o1: | ||
| return "(1)"; | ||
| default: | ||
| return "f(N)"; | ||
| } | ||
| } | ||
|
|
||
| // Find the coefficient for the high-order term in the running time, by | ||
| // minimizing the sum of squares of relative error, for the fitting curve | ||
| // given by the lambda expresion. | ||
| // - n : Vector containing the size of the benchmark tests. | ||
| // - time : Vector containing the times for the benchmark tests. | ||
| // - fitting_curve : lambda expresion (e.g. [](int n) {return n; };). | ||
|
|
||
| // For a deeper explanation on the algorithm logic, look the README file at | ||
| // http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit | ||
|
|
||
| LeastSq MinimalLeastSq(const std::vector<int>& n, | ||
| const std::vector<double>& time, | ||
| BigOFunc* fitting_curve) { | ||
| double sigma_gn = 0.0; | ||
| double sigma_gn_squared = 0.0; | ||
| double sigma_time = 0.0; | ||
| double sigma_time_gn = 0.0; | ||
|
|
||
| // Calculate least square fitting parameter | ||
| for (size_t i = 0; i < n.size(); ++i) { | ||
| double gn_i = fitting_curve(n[i]); | ||
| sigma_gn += gn_i; | ||
| sigma_gn_squared += gn_i * gn_i; | ||
| sigma_time += time[i]; | ||
| sigma_time_gn += time[i] * gn_i; | ||
| } | ||
|
|
||
| LeastSq result; | ||
| result.complexity = oLambda; | ||
|
|
||
| // Calculate complexity. | ||
| result.coef = sigma_time_gn / sigma_gn_squared; | ||
|
|
||
| // Calculate RMS | ||
| double rms = 0.0; | ||
| for (size_t i = 0; i < n.size(); ++i) { | ||
| double fit = result.coef * fitting_curve(n[i]); | ||
| rms += pow((time[i] - fit), 2); | ||
| } | ||
|
|
||
| // Normalized RMS by the mean of the observed values | ||
| double mean = sigma_time / n.size(); | ||
| result.rms = sqrt(rms / n.size()) / mean; | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| // Find the coefficient for the high-order term in the running time, by | ||
| // minimizing the sum of squares of relative error. | ||
| // - n : Vector containing the size of the benchmark tests. | ||
| // - time : Vector containing the times for the benchmark tests. | ||
| // - complexity : If different than oAuto, the fitting curve will stick to | ||
| // this one. If it is oAuto, it will be calculated the best | ||
| // fitting curve. | ||
| LeastSq MinimalLeastSq(const std::vector<int>& n, | ||
| const std::vector<double>& time, | ||
| const BigO complexity) { | ||
| CHECK_EQ(n.size(), time.size()); | ||
| CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two | ||
| // benchmark runs are given | ||
| CHECK_NE(complexity, oNone); | ||
|
|
||
| LeastSq best_fit; | ||
|
|
||
| if (complexity == oAuto) { | ||
| std::vector<BigO> fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed}; | ||
|
|
||
| // Take o1 as default best fitting curve | ||
| best_fit = MinimalLeastSq(n, time, FittingCurve(o1)); | ||
| best_fit.complexity = o1; | ||
|
|
||
| // Compute all possible fitting curves and stick to the best one | ||
| for (const auto& fit : fit_curves) { | ||
| LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit)); | ||
| if (current_fit.rms < best_fit.rms) { | ||
| best_fit = current_fit; | ||
| best_fit.complexity = fit; | ||
| } | ||
| } | ||
| } else { | ||
| best_fit = MinimalLeastSq(n, time, FittingCurve(complexity)); | ||
| best_fit.complexity = complexity; | ||
| } | ||
|
|
||
| return best_fit; | ||
| } | ||
|
|
||
| std::vector<BenchmarkReporter::Run> ComputeStats( | ||
| const std::vector<BenchmarkReporter::Run>& reports) { | ||
| typedef BenchmarkReporter::Run Run; | ||
| std::vector<Run> results; | ||
|
|
||
| auto error_count = | ||
| std::count_if(reports.begin(), reports.end(), | ||
| [](Run const& run) { return run.error_occurred; }); | ||
|
|
||
| if (reports.size() - error_count < 2) { | ||
| // We don't report aggregated data if there was a single run. | ||
| return results; | ||
| } | ||
| // Accumulators. | ||
| Stat1_d real_accumulated_time_stat; | ||
| Stat1_d cpu_accumulated_time_stat; | ||
| Stat1_d bytes_per_second_stat; | ||
| Stat1_d items_per_second_stat; | ||
| // All repetitions should be run with the same number of iterations so we | ||
| // can take this information from the first benchmark. | ||
| int64_t const run_iterations = reports.front().iterations; | ||
|
|
||
| // Populate the accumulators. | ||
| for (Run const& run : reports) { | ||
| CHECK_EQ(reports[0].benchmark_name, run.benchmark_name); | ||
| CHECK_EQ(run_iterations, run.iterations); | ||
| if (run.error_occurred) continue; | ||
| real_accumulated_time_stat += | ||
| Stat1_d(run.real_accumulated_time / run.iterations, run.iterations); | ||
| cpu_accumulated_time_stat += | ||
| Stat1_d(run.cpu_accumulated_time / run.iterations, run.iterations); | ||
| items_per_second_stat += Stat1_d(run.items_per_second, run.iterations); | ||
| bytes_per_second_stat += Stat1_d(run.bytes_per_second, run.iterations); | ||
| } | ||
|
|
||
| // Get the data from the accumulator to BenchmarkReporter::Run's. | ||
| Run mean_data; | ||
| mean_data.benchmark_name = reports[0].benchmark_name + "_mean"; | ||
| mean_data.iterations = run_iterations; | ||
| mean_data.real_accumulated_time = | ||
| real_accumulated_time_stat.Mean() * run_iterations; | ||
| mean_data.cpu_accumulated_time = | ||
| cpu_accumulated_time_stat.Mean() * run_iterations; | ||
| mean_data.bytes_per_second = bytes_per_second_stat.Mean(); | ||
| mean_data.items_per_second = items_per_second_stat.Mean(); | ||
|
|
||
| // Only add label to mean/stddev if it is same for all runs | ||
| mean_data.report_label = reports[0].report_label; | ||
| for (std::size_t i = 1; i < reports.size(); i++) { | ||
| if (reports[i].report_label != reports[0].report_label) { | ||
| mean_data.report_label = ""; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| Run stddev_data; | ||
| stddev_data.benchmark_name = reports[0].benchmark_name + "_stddev"; | ||
| stddev_data.report_label = mean_data.report_label; | ||
| stddev_data.iterations = 0; | ||
| stddev_data.real_accumulated_time = real_accumulated_time_stat.StdDev(); | ||
| stddev_data.cpu_accumulated_time = cpu_accumulated_time_stat.StdDev(); | ||
| stddev_data.bytes_per_second = bytes_per_second_stat.StdDev(); | ||
| stddev_data.items_per_second = items_per_second_stat.StdDev(); | ||
|
|
||
| results.push_back(mean_data); | ||
| results.push_back(stddev_data); | ||
| return results; | ||
| } | ||
|
|
||
| std::vector<BenchmarkReporter::Run> ComputeBigO( | ||
| const std::vector<BenchmarkReporter::Run>& reports) { | ||
| typedef BenchmarkReporter::Run Run; | ||
| std::vector<Run> results; | ||
|
|
||
| if (reports.size() < 2) return results; | ||
|
|
||
| // Accumulators. | ||
| std::vector<int> n; | ||
| std::vector<double> real_time; | ||
| std::vector<double> cpu_time; | ||
|
|
||
| // Populate the accumulators. | ||
| for (const Run& run : reports) { | ||
| CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?"; | ||
| n.push_back(run.complexity_n); | ||
| real_time.push_back(run.real_accumulated_time / run.iterations); | ||
| cpu_time.push_back(run.cpu_accumulated_time / run.iterations); | ||
| } | ||
|
|
||
| LeastSq result_cpu; | ||
| LeastSq result_real; | ||
|
|
||
| if (reports[0].complexity == oLambda) { | ||
| result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda); | ||
| result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda); | ||
| } else { | ||
| result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); | ||
| result_real = MinimalLeastSq(n, real_time, result_cpu.complexity); | ||
| } | ||
| std::string benchmark_name = | ||
| reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/')); | ||
|
|
||
| // Get the data from the accumulator to BenchmarkReporter::Run's. | ||
| Run big_o; | ||
| big_o.benchmark_name = benchmark_name + "_BigO"; | ||
| big_o.iterations = 0; | ||
| big_o.real_accumulated_time = result_real.coef; | ||
| big_o.cpu_accumulated_time = result_cpu.coef; | ||
| big_o.report_big_o = true; | ||
| big_o.complexity = result_cpu.complexity; | ||
|
|
||
| double multiplier = GetTimeUnitMultiplier(reports[0].time_unit); | ||
|
|
||
| // Only add label to mean/stddev if it is same for all runs | ||
| Run rms; | ||
| big_o.report_label = reports[0].report_label; | ||
| rms.benchmark_name = benchmark_name + "_RMS"; | ||
| rms.report_label = big_o.report_label; | ||
| rms.iterations = 0; | ||
| rms.real_accumulated_time = result_real.rms / multiplier; | ||
| rms.cpu_accumulated_time = result_cpu.rms / multiplier; | ||
| rms.report_rms = true; | ||
| rms.complexity = result_cpu.complexity; | ||
|
|
||
| results.push_back(big_o); | ||
| results.push_back(rms); | ||
| return results; | ||
| } | ||
|
|
||
| } // end namespace benchmark |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| // Copyright 2016 Ismael Jimenez Martinez. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| // Source project : https://github.com/ismaelJimenez/cpp.leastsq | ||
| // Adapted to be used with google benchmark | ||
|
|
||
| #ifndef COMPLEXITY_H_ | ||
| #define COMPLEXITY_H_ | ||
|
|
||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "benchmark/benchmark_api.h" | ||
| #include "benchmark/reporter.h" | ||
|
|
||
| namespace benchmark { | ||
|
|
||
| // Return a vector containing the mean and standard devation information for | ||
| // the specified list of reports. If 'reports' contains less than two | ||
| // non-errored runs an empty vector is returned | ||
| std::vector<BenchmarkReporter::Run> ComputeStats( | ||
| const std::vector<BenchmarkReporter::Run>& reports); | ||
|
|
||
| // Return a vector containing the bigO and RMS information for the specified | ||
| // list of reports. If 'reports.size() < 2' an empty vector is returned. | ||
| std::vector<BenchmarkReporter::Run> ComputeBigO( | ||
| const std::vector<BenchmarkReporter::Run>& reports); | ||
|
|
||
| // This data structure will contain the result returned by MinimalLeastSq | ||
| // - coef : Estimated coeficient for the high-order term as | ||
| // interpolated from data. | ||
| // - rms : Normalized Root Mean Squared Error. | ||
| // - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability | ||
| // form has been provided to MinimalLeastSq this will return | ||
| // the same value. In case BigO::oAuto has been selected, this | ||
| // parameter will return the best fitting curve detected. | ||
|
|
||
| struct LeastSq { | ||
| LeastSq() : | ||
| coef(0.0), | ||
| rms(0.0), | ||
| complexity(oNone) {} | ||
|
|
||
| double coef; | ||
| double rms; | ||
| BigO complexity; | ||
| }; | ||
|
|
||
| // Function to return an string for the calculated complexity | ||
| std::string GetBigOString(BigO complexity); | ||
|
|
||
| } // end namespace benchmark | ||
| #endif // COMPLEXITY_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| // Copyright 2015 Google Inc. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #include "benchmark/reporter.h" | ||
| #include "complexity.h" | ||
|
|
||
| #include <algorithm> | ||
| #include <cstdint> | ||
| #include <cstdio> | ||
| #include <iostream> | ||
| #include <string> | ||
| #include <tuple> | ||
| #include <vector> | ||
|
|
||
| #include "check.h" | ||
| #include "colorprint.h" | ||
| #include "commandlineflags.h" | ||
| #include "internal_macros.h" | ||
| #include "string_util.h" | ||
| #include "walltime.h" | ||
|
|
||
| DECLARE_bool(color_print); | ||
|
|
||
| namespace benchmark { | ||
|
|
||
| bool ConsoleReporter::ReportContext(const Context& context) { | ||
| name_field_width_ = context.name_field_width; | ||
|
|
||
| PrintBasicContext(&GetErrorStream(), context); | ||
|
|
||
| #ifdef BENCHMARK_OS_WINDOWS | ||
| if (FLAGS_color_print && &std::cout != &GetOutputStream()) { | ||
| GetErrorStream() << "Color printing is only supported for stdout on windows." | ||
| " Disabling color printing\n"; | ||
| FLAGS_color_print = false; | ||
| } | ||
| #endif | ||
| std::string str = FormatString("%-*s %13s %13s %10s\n", | ||
| static_cast<int>(name_field_width_), "Benchmark", | ||
| "Time", "CPU", "Iterations"); | ||
| GetOutputStream() << str << std::string(str.length() - 1, '-') << "\n"; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) { | ||
| for (const auto& run : reports) | ||
| PrintRunData(run); | ||
| } | ||
|
|
||
| void ConsoleReporter::PrintRunData(const Run& result) { | ||
| auto& Out = GetOutputStream(); | ||
|
|
||
| auto name_color = | ||
| (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; | ||
| ColorPrintf(Out, name_color, "%-*s ", name_field_width_, | ||
| result.benchmark_name.c_str()); | ||
|
|
||
| if (result.error_occurred) { | ||
| ColorPrintf(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", | ||
| result.error_message.c_str()); | ||
| ColorPrintf(Out, COLOR_DEFAULT, "\n"); | ||
| return; | ||
| } | ||
| // Format bytes per second | ||
| std::string rate; | ||
| if (result.bytes_per_second > 0) { | ||
| rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s"); | ||
| } | ||
|
|
||
| // Format items per second | ||
| std::string items; | ||
| if (result.items_per_second > 0) { | ||
| items = StrCat(" ", HumanReadableNumber(result.items_per_second), | ||
| " items/s"); | ||
| } | ||
|
|
||
| const double real_time = result.GetAdjustedRealTime(); | ||
| const double cpu_time = result.GetAdjustedCPUTime(); | ||
|
|
||
| if (result.report_big_o) { | ||
| std::string big_o = GetBigOString(result.complexity); | ||
| ColorPrintf(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, | ||
| big_o.c_str(), cpu_time, big_o.c_str()); | ||
| } else if (result.report_rms) { | ||
| ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100, | ||
| cpu_time * 100); | ||
| } else { | ||
| const char* timeLabel = GetTimeUnitString(result.time_unit); | ||
| ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel, | ||
| cpu_time, timeLabel); | ||
| } | ||
|
|
||
| if (!result.report_big_o && !result.report_rms) { | ||
| ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations); | ||
| } | ||
|
|
||
| if (!rate.empty()) { | ||
| ColorPrintf(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str()); | ||
| } | ||
|
|
||
| if (!items.empty()) { | ||
| ColorPrintf(Out, COLOR_DEFAULT, " %*s", 18, items.c_str()); | ||
| } | ||
|
|
||
| if (!result.report_label.empty()) { | ||
| ColorPrintf(Out, COLOR_DEFAULT, " %s", result.report_label.c_str()); | ||
| } | ||
|
|
||
| ColorPrintf(Out, COLOR_DEFAULT, "\n"); | ||
| } | ||
|
|
||
| } // end namespace benchmark |