Add start of filesystem benchmarks

llvm-svn: 285524
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 3aa5478e212ced5f0f6ee61359d7ebbe167bbb10
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d5a51b..b29d6c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,8 +58,24 @@
 option(LIBCXX_ENABLE_FILESYSTEM
         "Build filesystem as part of libc++experimental.a" ${LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY})
 option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
+
+
+# Benchmark options -----------------------------------------------------------
 option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependancies" ON)
-option(LIBCXX_BUILD_BENCHMARK_NATIVE_STDLIB "Build the benchmarks against the native STL" OFF)
+set(LIBCXX_BENCHMARK_NATIVE_STDLIB "" CACHE STRING
+        "Build the benchmarks against the specified native STL.
+         The value must be one of libc++/libstdc++")
+set(LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN "" CACHE STRING
+    "Use alternate GCC toolchain when building the native benchmarks")
+
+if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
+  if (NOT (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libc++"
+        OR LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++"))
+    message(FATAL_ERROR "Invalid value for LIBCXX_BENCHMARK_NATIVE_STDLIB: "
+            "'${LIBCXX_BENCHMARK_NATIVE_STDLIB}'")
+  endif()
+endif()
+
 option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
 set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
     "Define suffix of library directory name (32/64)")
diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
index 4160157..ed562e0 100644
--- a/benchmarks/CMakeLists.txt
+++ b/benchmarks/CMakeLists.txt
@@ -37,7 +37,14 @@
 #==============================================================================
 # Build Google Benchmark for the native stdlib
 #==============================================================================
-if (LIBCXX_BUILD_BENCHMARK_NATIVE_STDLIB)
+set(BENCHMARK_NATIVE_TARGET_FLAGS)
+if (LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN)
+  set(BENCHMARK_NATIVE_TARGET_FLAGS
+      -gcc-toolchain ${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN})
+endif()
+split_list(BENCHMARK_NATIVE_TARGET_FLAGS)
+
+if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
   ExternalProject_Add(google-benchmark-native
         EXCLUDE_FROM_ALL ON
         PREFIX benchmark-native
@@ -46,6 +53,7 @@
         CMAKE_CACHE_ARGS
           -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
           -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+          -DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_NATIVE_TARGET_FLAGS}
           -DCMAKE_BUILD_TYPE:STRING=RELEASE
           -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
           -DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
@@ -72,12 +80,18 @@
     -nodefaultlibs
     -L${BENCHMARK_LIBCXX_INSTALL}/lib/
 )
+set(BENCHMARK_TEST_NATIVE_COMPILE_FLAGS
+  ${BENCHMARK_NATIVE_TARGET_FLAGS}
+  ${BENCHMARK_TEST_COMPILE_FLAGS}
+)
 set(BENCHMARK_TEST_NATIVE_LINK_FLAGS
-    -L${BENCHMARK_NATIVE_INSTALL}/lib/
+    ${BENCHMARK_NATIVE_TARGET_FLAGS}
+    -L${BENCHMARK_NATIVE_INSTALL}/lib
 )
 split_list(BENCHMARK_TEST_COMPILE_FLAGS)
 split_list(BENCHMARK_TEST_LIBCXX_COMPILE_FLAGS)
 split_list(BENCHMARK_TEST_LIBCXX_LINK_FLAGS)
+split_list(BENCHMARK_TEST_NATIVE_COMPILE_FLAGS)
 split_list(BENCHMARK_TEST_NATIVE_LINK_FLAGS)
 macro(add_benchmark_test name source_file)
   set(libcxx_target ${name}_libcxx)
@@ -89,17 +103,25 @@
   else()
     target_link_libraries(${libcxx_target} cxx_static)
   endif()
+  if (TARGET cxx_experimental)
+    target_link_libraries(${libcxx_target} cxx_experimental)
+  endif()
   target_link_libraries(${libcxx_target} -lbenchmark)
   set_target_properties(${libcxx_target}
     PROPERTIES
           OUTPUT_NAME "${name}.libcxx.out"
           COMPILE_FLAGS "${BENCHMARK_TEST_LIBCXX_COMPILE_FLAGS}"
           LINK_FLAGS "${BENCHMARK_TEST_LIBCXX_LINK_FLAGS}")
-  if (LIBCXX_BUILD_BENCHMARK_NATIVE_STDLIB)
+  if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
     set(native_target ${name}_native)
     add_executable(${native_target} EXCLUDE_FROM_ALL ${source_file})
     add_dependencies(${native_target} google-benchmark-native)
     target_link_libraries(${native_target} -lbenchmark)
+    if (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++")
+      target_link_libraries(${native_target} -lstdc++fs)
+    elseif (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libc++")
+      target_link_libraries(${native_target} -lc++experimental)
+    endif()
     if (LIBCXX_HAS_PTHREAD_LIB)
       target_link_libraries(${native_target} -pthread)
     endif()
@@ -108,7 +130,7 @@
       PROPERTIES
           OUTPUT_NAME "${name}.native.out"
           INCLUDE_DIRECTORIES ""
-          COMPILE_FLAGS "${BENCHMARK_TEST_COMPILE_FLAGS}"
+          COMPILE_FLAGS "${BENCHMARK_TEST_NATIVE_COMPILE_FLAGS}"
           LINK_FLAGS "${BENCHMARK_TEST_NATIVE_LINK_FLAGS}")
   endif()
 endmacro()
diff --git a/benchmarks/GenerateInput.hpp b/benchmarks/GenerateInput.hpp
index affd541..9d5adac 100644
--- a/benchmarks/GenerateInput.hpp
+++ b/benchmarks/GenerateInput.hpp
@@ -137,4 +137,6 @@
         cinputs.push_back(str.c_str());
     return cinputs;
 }
+
+
 #endif // BENCHMARK_GENERATE_INPUT_HPP
diff --git a/benchmarks/filesystem.bench.cpp b/benchmarks/filesystem.bench.cpp
new file mode 100644
index 0000000..8dacbe6
--- /dev/null
+++ b/benchmarks/filesystem.bench.cpp
@@ -0,0 +1,90 @@
+#include <experimental/filesystem>
+
+#include "benchmark/benchmark_api.h"
+#include "GenerateInput.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+static const size_t TestNumInputs = 1024;
+
+
+template <class GenInputs>
+void BM_PathConstructString(benchmark::State &st, GenInputs gen) {
+  using namespace fs;
+  const auto in = gen(st.range(0));
+  path PP;
+  for (auto& Part : in)
+    PP /= Part;
+  benchmark::DoNotOptimize(PP.native().data());
+  while (st.KeepRunning()) {
+    const path P(PP.native());
+    benchmark::DoNotOptimize(P.native().data());
+  }
+}
+BENCHMARK_CAPTURE(BM_PathConstructString, iterate_elements,
+  getRandomStringInputs)->Arg(TestNumInputs);
+
+
+template <class GenInputs>
+void BM_PathIterateMultipleTimes(benchmark::State &st, GenInputs gen) {
+  using namespace fs;
+  const auto in = gen(st.range(0));
+  path PP;
+  for (auto& Part : in)
+    PP /= Part;
+  benchmark::DoNotOptimize(PP.native().data());
+  while (st.KeepRunning()) {
+    for (auto &E : PP) {
+      benchmark::DoNotOptimize(E.native().data());
+    }
+    benchmark::ClobberMemory();
+  }
+}
+BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements,
+  getRandomStringInputs)->Arg(TestNumInputs);
+
+
+template <class GenInputs>
+void BM_PathIterateOnce(benchmark::State &st, GenInputs gen) {
+  using namespace fs;
+  const auto in = gen(st.range(0));
+  path PP;
+  for (auto& Part : in)
+    PP /= Part;
+  benchmark::DoNotOptimize(PP.native().data());
+  while (st.KeepRunning()) {
+    const path P = PP.native();
+    for (auto &E : P) {
+      benchmark::DoNotOptimize(E.native().data());
+    }
+    benchmark::ClobberMemory();
+  }
+}
+BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements,
+  getRandomStringInputs)->Arg(TestNumInputs);
+
+template <class GenInputs>
+void BM_PathIterateOnceBackwards(benchmark::State &st, GenInputs gen) {
+  using namespace fs;
+  const auto in = gen(st.range(0));
+  path PP;
+  for (auto& Part : in)
+    PP /= Part;
+  benchmark::DoNotOptimize(PP.native().data());
+  while (st.KeepRunning()) {
+    const path P = PP.native();
+    const auto B = P.begin();
+    auto I = P.end();
+    while (I != B) {
+      --I;
+      benchmark::DoNotOptimize(*I);
+    }
+    benchmark::DoNotOptimize(*I);
+  }
+}
+BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements,
+  getRandomStringInputs)->Arg(TestNumInputs);
+
+
+
+BENCHMARK_MAIN()
diff --git a/docs/BuildingLibcxx.rst b/docs/BuildingLibcxx.rst
index 1c3be87..b00bbdd 100644
--- a/docs/BuildingLibcxx.rst
+++ b/docs/BuildingLibcxx.rst
@@ -256,14 +256,21 @@
   Build the libc++ benchmark tests and the Google Benchmark library needed
   to support them.
 
-.. option:: LIBCXX_BUILD_BENCHMARK_NATIVE_STDLIB:BOOL
+.. option:: LIBCXX_BENCHMARK_NATIVE_STDLIB:STRING
 
-  **Default**:: ``OFF``
+  **Default**:: ``""``
+
+  **Values**:: ``libc++``, ``libstdc++``
 
   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.
+  specified 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.
+
+.. option:: LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN:STRING
+
+  Use the specified GCC toolchain and standard library when building the native
+  stdlib benchmark tests.
 
 
 libc++ ABI Feature Options