62 changes: 62 additions & 0 deletions libcxx/benchmarks/algorithms.bench.cpp
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()
278 changes: 251 additions & 27 deletions libcxx/benchmarks/unordered_set_operations.bench.cpp
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"

template <class IntT>
std::vector<IntT> getInputs(size_t N) {
std::vector<IntT> inputs;
for (size_t i=0; i < N; ++i) {
inputs.push_back(i);
}
return inputs;
#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;
}

template <class Container, class Inputs>
void BM_SetInsert(benchmark::State& st, Container c, Inputs const& in) {
const auto end = in.end();
while (st.KeepRunning()) {
c.clear();
for (auto it = in.begin(); it != end; ++it) {
benchmark::DoNotOptimize(c.insert(*it));
}
benchmark::DoNotOptimize(c);
}
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);
}
BENCHMARK_CAPTURE(BM_SetInsert, uint32_insert,
std::unordered_set<uint32_t>{}, getInputs<uint32_t>(1024));

template <class Container, class Inputs>
void BM_SetFind(benchmark::State& st, Container c, Inputs const& in) {
c.insert(in.begin(), in.end());
const auto end = in.end();
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.begin(); it != end; ++it) {
benchmark::DoNotOptimize(c.find(*it));
for (auto it = in.data(); it != end; ++it) {
benchmark::DoNotOptimize(last_hash += fn(*it));
}
benchmark::ClobberMemory();
}
}
BENCHMARK_CAPTURE(BM_SetFind, uint32_lookup,
std::unordered_set<uint32_t>{}, getInputs<uint32_t>(1024));

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()
22 changes: 19 additions & 3 deletions libcxx/docs/BuildingLibcxx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ ABI Library Specific Options
libc++abi is the C++ ABI library used.


libc++ Feature options
libc++ Feature Options
----------------------

.. option:: LIBCXX_ENABLE_EXCEPTIONS:BOOL
Expand All @@ -242,9 +242,25 @@ libc++ Feature options

Build libc++ with run time type information.

.. option:: LIBCXX_INCLUDE_BENCHMARKS:BOOL

libc++ Feature options
----------------------
**Default**: ``OFF``

Build the libc++ benchmark tests and the Google Benchmark library needed
to support them.

.. option:: LIBCXX_BUILD_BENCHMARK_NATIVE_STDLIB:BOOL

**Default**:: ``OFF``

Build the libc++ benchmark tests and Google Benchmark library against the
native standard library on the platform. On linux this can be used to compare
libc++ to libstdc++ by building the benchmark tests against both standard
libraries.


libc++ ABI Feature Options
--------------------------

The following options allow building libc++ for a different ABI version.

Expand Down
59 changes: 59 additions & 0 deletions libcxx/docs/TestingLibcxx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,62 @@ Environment Variables
If ``LIBCXX_COLOR_DIAGNOSTICS`` is defined then the test suite will attempt
to use color diagnostic outputs from the compiler.
Also see :option:`color_diagnostics`.

Benchmarks
==========

Libc++ contains benchmark tests separately from the test of the test suite.
The benchmarks are written using the `Google Benchmark`_ library, a copy of which
is stored in the libc++ repository.

For more information about using the Google Benchmark library see the
`official documentation <https://github.com/google/benchmark>`_.

.. _`Google Benchmark`: https://github.com/google/benchmark

Building Benchmarks
-------------------

The benchmark tests are not enabled by default. To build the benchmarks
libc++ must be configured using the CMake option ``-DLIBCXX_INCLUDE_BENCHMARKS=ON``.
Then the benchmarks can be built using the ``libcxx-benchmarks`` target.

An example build would look like:

.. code-block:: bash
$ cd build
$ cmake [options] -DLIBCXX_INCLUDE_BENCHMARKS=ON <path to libcxx sources>
$ make libcxx-benchmarks
This will build all of the benchmarks under ``<libcxx-src>/benchmarks`` to be
built against the just-built libc++. The compiled tests are output into
``build/benchmarks``.

The benchmarks can also be built against the platforms native standard library
using the ``-DLIBCXX_BUILD_BENCHMARKS_NATIVE_STDLIB=ON`` CMake option. This
is useful for comparing the performance of libc++ to other standard libraries.
The compiled benchmarks are named ``<test>.libcxx.out`` if they test libc++ and
``<test>.native.out`` otherwise.

Also See:

* :ref:`Building Libc++ <build instructions>`
* :ref:`CMake Options`

Running Benchmarks
------------------

The benchmarks must be run manually by the user. Currently there is no way
to run them as part of the build.

For example:

.. code-block:: bash
$ cd build/benchmarks
$ make libcxx-benchmarks
$ ./algorithms.libcxx.out # Runs all the benchmarks
$ ./algorithms.libcxx.out --benchmark_filter=BM_Sort.* # Only runs the sort benchmarks
For more information about running benchmarks see `Google Benchmark`_.
46 changes: 46 additions & 0 deletions libcxx/utils/google-benchmark/.gitignore
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/
33 changes: 33 additions & 0 deletions libcxx/utils/google-benchmark/AUTHORS
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>
147 changes: 147 additions & 0 deletions libcxx/utils/google-benchmark/CMakeLists.txt
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()
58 changes: 58 additions & 0 deletions libcxx/utils/google-benchmark/CONTRIBUTING.md
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
52 changes: 52 additions & 0 deletions libcxx/utils/google-benchmark/CONTRIBUTORS
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>
202 changes: 202 additions & 0 deletions libcxx/utils/google-benchmark/LICENSE
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.
6 changes: 6 additions & 0 deletions libcxx/utils/google-benchmark/README.LLVM
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++.
510 changes: 510 additions & 0 deletions libcxx/utils/google-benchmark/README.md

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions libcxx/utils/google-benchmark/cmake/AddCXXCompilerFlag.cmake
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()

42 changes: 42 additions & 0 deletions libcxx/utils/google-benchmark/cmake/CXXFeatureCheck.cmake
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()

51 changes: 51 additions & 0 deletions libcxx/utils/google-benchmark/cmake/GetGitVersion.cmake
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()
12 changes: 12 additions & 0 deletions libcxx/utils/google-benchmark/cmake/gnu_posix_regex.cpp
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;
}

14 changes: 14 additions & 0 deletions libcxx/utils/google-benchmark/cmake/posix_regex.cpp
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;
}

10 changes: 10 additions & 0 deletions libcxx/utils/google-benchmark/cmake/std_regex.cpp
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;
}

7 changes: 7 additions & 0 deletions libcxx/utils/google-benchmark/cmake/steady_clock.cpp
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() {}
21 changes: 21 additions & 0 deletions libcxx/utils/google-benchmark/include/benchmark/benchmark.h
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_
747 changes: 747 additions & 0 deletions libcxx/utils/google-benchmark/include/benchmark/benchmark_api.h

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions libcxx/utils/google-benchmark/include/benchmark/macros.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_
216 changes: 216 additions & 0 deletions libcxx/utils/google-benchmark/include/benchmark/reporter.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_
320 changes: 320 additions & 0 deletions libcxx/utils/google-benchmark/mingw.py
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)
51 changes: 51 additions & 0 deletions libcxx/utils/google-benchmark/src/CMakeLists.txt
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")
34 changes: 34 additions & 0 deletions libcxx/utils/google-benchmark/src/arraysize.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_
1,123 changes: 1,123 additions & 0 deletions libcxx/utils/google-benchmark/src/benchmark.cc

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions libcxx/utils/google-benchmark/src/check.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_
158 changes: 158 additions & 0 deletions libcxx/utils/google-benchmark/src/colorprint.cc
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
27 changes: 27 additions & 0 deletions libcxx/utils/google-benchmark/src/colorprint.h
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_
220 changes: 220 additions & 0 deletions libcxx/utils/google-benchmark/src/commandlineflags.cc
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
76 changes: 76 additions & 0 deletions libcxx/utils/google-benchmark/src/commandlineflags.h
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_
283 changes: 283 additions & 0 deletions libcxx/utils/google-benchmark/src/complexity.cc
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
64 changes: 64 additions & 0 deletions libcxx/utils/google-benchmark/src/complexity.h
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_
124 changes: 124 additions & 0 deletions libcxx/utils/google-benchmark/src/console_reporter.cc
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
Loading