Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ rules.ninja
# out-of-source build top-level folders.
build/
_build/

# in-source dependancies
/googletest/

2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ install:
fi

script:
- cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS}" -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} ..
- cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} ..
- make
- ctest -C ${BUILD_TYPE} --output-on-failure

Expand Down
16 changes: 13 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project (benchmark)
foreach(p
CMP0054 # CMake 3.1
CMP0056 # export EXE_LINKER_FLAGS to try_run
CMP0057 # Support no if() IN_LIST operator
)
if(POLICY ${p})
cmake_policy(SET ${p} NEW)
Expand All @@ -18,6 +19,14 @@ option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library
option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF)
option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON)

# Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which
# may require downloading the source code.
option(BENCHMARK_DOWNLOAD_DEPENDENCIES "Allow the downloading and in-tree building of unmet dependencies" OFF)

# This option can be used to disable building and running unit tests which depend on gtest
# in cases where it is not possible to build or find a valid version of gtest.
option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend on gtest" ON)

# Make sure we can import out CMake functions
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
Expand Down Expand Up @@ -97,9 +106,7 @@ else()
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
add_cxx_compiler_flag(-fno-exceptions)
endif()
if (NOT BENCHMARK_USE_LIBCXX)
add_cxx_compiler_flag(-Wzero-as-null-pointer-constant)
endif()

if (HAVE_CXX_FLAG_FSTRICT_ALIASING)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing
add_cxx_compiler_flag(-Wstrict-aliasing)
Expand Down Expand Up @@ -199,5 +206,8 @@ add_subdirectory(src)

if (BENCHMARK_ENABLE_TESTING)
enable_testing()
if (BENCHMARK_ENABLE_GTEST_TESTS)
include(HandleGTest)
endif()
add_subdirectory(test)
endif()
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,31 @@ IRC channel: https://freenode.net #googlebenchmark
[Additional Tooling Documentation](docs/tools.md)


## Building

The basic steps for configuring and building the library look like this:

```bash
$ git clone https://github.com/google/benchmark.git
# Benchmark requires GTest as a dependency. Add the source tree as a subdirectory.
$ git clone https://github.com/google/googletest.git benchmark/googletest
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd highly recommend

  1. providing an option specifying the path to the gtest sources
  2. defaulting to /usr/src/googletest/, since that is the natural location, and is where debian puts it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, I don't really care to allow users to specify random/arbirtrary out-of-tree GTest source directories. We already have a mechanism to allow users to specify arbitrary GTest installation using CMAKE_MODULE_PATH to influence find_package(GTest).

I've changed the build, as you've suggested, to only download dependencies if -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON is specified. So GTest installations among /usr/ and /usr/local/ should work by default.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not git submodules?

$ mkdir build && cd build
$ cmake -G <generator> [options] ../benchmark
# Assuming a makefile generator was used
$ make
```

Note that Google Benchmark requires GTest to build and run the tests. This
dependency can be provided three ways:

* Checkout the GTest sources into `benchmark/googletest`.
* Otherwise, if `-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON` is specified during
configuration, the library will automatically download and build any required
dependencies.
* Otherwise, if nothing is done, CMake will use `find_package(GTest REQUIRED)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be the default, no? ie, why do we have it required to have it in-tree instead of just letting cmake do the right thing?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/usr/share/doc/googletest/README.Debian:

	Use of precompiled libgtest Not Recommended
	-------------------------------------------

The Google C++ Testing Framework uses conditional compilation for some
things.  Because of the C++ "One Definition Rule", gtest and gmock
must be compiled with exactly the same flags as your C++ code under
test.  Because this is hard to manage, upstream no longer recommends
using precompiled libraries [1].


	Using GTest with your project
	-----------------------------

See the upstream README for instructions on using gtest with your
project.  The sources for libgtest are installed into
/usr/src/googletest/googletest along with CMakeLists.txt for use with
cmake.

If your build system uses CMake, the ExternalProject command can be
used to build gtest, then FindGTest can be used to find the built
library.


	Using gmock with your project
	-----------------------------

See the upstream README for instructions on using gmock with your
project.  The sources for libgmock are installed into
/usr/src/googletest/googlemock along with CMakeLists.txt for use with
cmake.

With this Debian package something like the following should be enough to build 
a static library (which also includes gtest):

g++ -I/usr/src/googletest/googlemock -c /usr/src/googletest/googlemock/src/gmock-all.cc
g++ -I/usr/src/googletest/googletest -c /usr/src/googletest/googletest/src/gtest-all.cc
ar -rv libgmock.a gmock-all.o gtest-all.o



[1] http://groups.google.com/group/googletestframework/browse_thread/thread/668eff1cebf5309d

 -- Steve M. Robbins <[email protected]>, Sat, 19 Nov 2016 21:58:04 -0600

to resolve the required GTest dependency.


## Installation Guide

For Ubuntu and Debian Based System
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ build_script:
- md _build -Force
- cd _build
- echo %configuration%
- cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" ..
- cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON ..
- cmake --build . --config %configuration%

test_script:
Expand Down
77 changes: 77 additions & 0 deletions cmake/HandleGTest.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

macro(split_list listname)
string(REPLACE ";" " " ${listname} "${${listname}}")
endmacro()

macro(build_external_gtest)
include(ExternalProject)
set(GTEST_FLAGS "")
if (BENCHMARK_USE_LIBCXX)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
list(APPEND GTEST_FLAGS -stdlib=libc++)
else()
message(WARNING "Unsupported compiler (${CMAKE_CXX_COMPILER}) when using libc++")
endif()
endif()
if (BENCHMARK_BUILD_32_BITS)
list(APPEND GTEST_FLAGS -m32)
endif()
if (NOT "${CMAKE_CXX_FLAGS}" STREQUAL "")
list(APPEND GTEST_FLAGS ${CMAKE_CXX_FLAGS})
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" GTEST_BUILD_TYPE)
if ("${GTEST_BUILD_TYPE}" STREQUAL "COVERAGE")
set(GTEST_BUILD_TYPE "DEBUG")
endif()
split_list(GTEST_FLAGS)
ExternalProject_Add(googletest
EXCLUDE_FROM_ALL ON
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
PREFIX "${CMAKE_BINARY_DIR}/googletest"
INSTALL_DIR "${CMAKE_BINARY_DIR}/googletest"
CMAKE_CACHE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${GTEST_BUILD_TYPE}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since all this is just to propagate the current params, maybe it would be simpler to just use 2-step approach?
Here is how it looks in practice: [0] [1]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've looked into 2 step approaches, but I think that they're less idiomatic CMake.
If CMake meant for you to download and load subdirectories during configuration time, they would have provided an actually supported way to do so.

-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_CXX_FLAGS:STRING=${GTEST_FLAGS}
-Dgtest_force_shared_crt:BOOL=ON
)

ExternalProject_Get_Property(googletest install_dir)

add_library(gtest UNKNOWN IMPORTED)
add_library(gtest_main UNKNOWN IMPORTED)

set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")

if("${GTEST_BUILD_TYPE}" STREQUAL "DEBUG")
set(LIB_SUFFIX "d${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
file(MAKE_DIRECTORY ${install_dir}/include)
set_target_properties(gtest PROPERTIES
IMPORTED_LOCATION ${install_dir}/lib/${LIB_PREFIX}gtest${LIB_SUFFIX}
INTERFACE_INCLUDE_DIRECTORIES ${install_dir}/include
)
set_target_properties(gtest_main PROPERTIES
IMPORTED_LOCATION ${install_dir}/lib/${LIB_PREFIX}gtest_main${LIB_SUFFIX}
INTERFACE_INCLUDE_DIRECTORIES ${install_dir}/include
)
add_dependencies(gtest googletest)
add_dependencies(gtest_main googletest)
set(GTEST_BOTH_LIBRARIES gtest gtest_main)
#set(GTEST_INCLUDE_DIRS ${install_dir}/include)
endmacro(build_external_gtest)

if (BENCHMARK_ENABLE_GTEST_TESTS)
if (IS_DIRECTORY ${CMAKE_SOURCE_DIR}/googletest)
add_subdirectory(${CMAKE_SOURCE_DIR}/googletest)
set(GTEST_BOTH_LIBRARIES gtest gtest_main)
elseif(BENCHMARK_DOWNLOAD_DEPENDENCIES)
build_external_gtest()
else()
find_package(GTest REQUIRED)
endif()
endif()
24 changes: 23 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ macro(compile_output_test name)
${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
endmacro(compile_output_test)


# Demonstration executable
compile_benchmark_test(benchmark_test)
add_test(benchmark benchmark_test --benchmark_min_time=0.01)
Expand Down Expand Up @@ -135,6 +134,29 @@ endif()
compile_output_test(complexity_test)
add_test(complexity_benchmark complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME})

###############################################################################
# GoogleTest Unit Tests
###############################################################################

if (BENCHMARK_ENABLE_GTEST_TESTS)
macro(compile_gtest name)
add_executable(${name} "${name}.cc")
if (TARGET googletest)
add_dependencies(${name} googletest)
endif()
target_link_libraries(${name} benchmark
"${GTEST_BOTH_LIBRARIES}" ${CMAKE_THREAD_LIBS_INIT})
endmacro(compile_gtest)

macro(add_gtest name)
compile_gtest(${name})
add_test(${name} ${name})
endmacro()

add_gtest(statistics_test)
endif(BENCHMARK_ENABLE_GTEST_TESTS)


# Add the coverage command(s)
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
Expand Down
61 changes: 61 additions & 0 deletions test/statistics_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//===---------------------------------------------------------------------===//
// statistics_test - Unit tests for src/statistics.cc
//===---------------------------------------------------------------------===//

#include "../src/statistics.h"
#include "gtest/gtest.h"

namespace {
TEST(StatisticsTest, Mean) {
std::vector<double> Inputs;
{
Inputs = {42, 42, 42, 42};
double Res = benchmark::StatisticsMean(Inputs);
EXPECT_DOUBLE_EQ(Res, 42.0);
}
{
Inputs = {1, 2, 3, 4};
double Res = benchmark::StatisticsMean(Inputs);
EXPECT_DOUBLE_EQ(Res, 2.5);
}
{
Inputs = {1, 2, 5, 10, 10, 14};
double Res = benchmark::StatisticsMean(Inputs);
EXPECT_DOUBLE_EQ(Res, 7.0);
}
}

TEST(StatisticsTest, Median) {
std::vector<double> Inputs;
{
Inputs = {42, 42, 42, 42};
double Res = benchmark::StatisticsMedian(Inputs);
EXPECT_DOUBLE_EQ(Res, 42.0);
}
{
Inputs = {1, 2, 3, 4};
double Res = benchmark::StatisticsMedian(Inputs);
EXPECT_DOUBLE_EQ(Res, 2.5);
}
{
Inputs = {1, 2, 5, 10, 10};
double Res = benchmark::StatisticsMedian(Inputs);
EXPECT_DOUBLE_EQ(Res, 5.0);
}
}

TEST(StatisticsTest, StdDev) {
std::vector<double> Inputs;
{
Inputs = {101, 101, 101, 101};
double Res = benchmark::StatisticsStdDev(Inputs);
EXPECT_DOUBLE_EQ(Res, 0.0);
}
{
Inputs = {1, 2, 3};
double Res = benchmark::StatisticsStdDev(Inputs);
EXPECT_DOUBLE_EQ(Res, 1.0);
}
}

} // end namespace