Skip to content

Commit e236a52

Browse files
authored
[libc++] Unify the benchmarks with the test suite (#101399)
Instead of building the benchmarks separately via CMake and running them separately from the test suite, this patch merges the benchmarks into the test suite and handles both uniformly. As a result: - It is now possible to run individual benchmarks like we run tests (e.g. using libcxx-lit), which is a huge quality-of-life improvement. - The benchmarks will be run under exactly the same configuration as the rest of the tests, which is a nice simplification. This does mean that one has to be careful to enable the desired optimization flags when running benchmarks, but that is easy with e.g. `libcxx-lit <...> --param optimization=speed`. - Benchmarks can use the same annotations as the rest of the test suite, such as `// UNSUPPORTED` & friends. When running the tests via `check-cxx`, we only compile the benchmarks because running them would be too time consuming. This introduces a bit of complexity in the testing setup, and instead it would be better to allow passing a --dry-run flag to GoogleBenchmark executables, which is the topic of google/benchmark#1827. I am not really satisfied with the layering violation of adding the %{benchmark_flags} substitution to cmake-bridge, however I believe this can be improved in the future.
1 parent 4f24d03 commit e236a52

21 files changed

+100
-408
lines changed

.github/workflows/libcxx-build-and-test.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,6 @@ jobs:
159159
'generic-no-rtti',
160160
'generic-optimized-speed',
161161
'generic-static',
162-
# TODO Find a better place for the benchmark and bootstrapping builds to live. They're either very expensive
163-
# or don't provide much value since the benchmark run results are too noise on the bots.
164-
'benchmarks',
165162
'bootstrapping-build'
166163
]
167164
machine: [ 'libcxx-runners-set' ]

libcxx/CMakeLists.txt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,19 @@ message(STATUS "Using libc++ testing configuration: ${LIBCXX_TEST_CONFIG}")
150150
set(LIBCXX_TEST_PARAMS "" CACHE STRING
151151
"A list of parameters to run the Lit test suite with.")
152152

153-
# Benchmark options -----------------------------------------------------------
154-
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ON)
155-
156-
set(LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT --benchmark_min_time=0.01)
157-
set(LIBCXX_BENCHMARK_TEST_ARGS "${LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT}" CACHE STRING
158-
"Arguments to pass when running the benchmarks using check-cxx-benchmarks")
153+
# TODO: Figure out how to build GoogleBenchmark on those platforms, and how to build when exceptions or RTTI is disabled
154+
if (WIN32 OR MINGW OR ANDROID OR ${CMAKE_SYSTEM_NAME} MATCHES "AIX"
155+
OR NOT LIBCXX_ENABLE_LOCALIZATION
156+
OR NOT LIBCXX_ENABLE_THREADS
157+
OR NOT LIBCXX_ENABLE_FILESYSTEM
158+
OR NOT LIBCXX_ENABLE_RANDOM_DEVICE
159+
OR NOT LIBCXX_ENABLE_EXCEPTIONS
160+
OR NOT LIBCXX_ENABLE_RTTI)
161+
set(_include_benchmarks OFF)
162+
else()
163+
set(_include_benchmarks ON)
164+
endif()
165+
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ${_include_benchmarks})
159166

160167
option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
161168
set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING

libcxx/docs/TestingLibcxx.rst

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ Test Filenames`_ when determining the names for new test files.
392392
of Lit test to be executed. This can be used to generate multiple Lit tests from a single source file, which is useful for testing repetitive properties
393393
in the library. Be careful not to abuse this since this is not a replacement for usual code reuse techniques.
394394

395+
* - ``FOO.bench.cpp``
396+
- A benchmark test. These tests are linked against the GoogleBenchmark library and generally consist of micro-benchmarks of individual
397+
components of the library.
398+
395399

396400
libc++-Specific Lit Features
397401
----------------------------
@@ -438,43 +442,29 @@ Libc++ contains benchmark tests separately from the test of the test suite.
438442
The benchmarks are written using the `Google Benchmark`_ library, a copy of which
439443
is stored in the libc++ repository.
440444

441-
For more information about using the Google Benchmark library see the
445+
For more information about using the Google Benchmark library, see the
442446
`official documentation <https://github.com/google/benchmark>`_.
443447

444-
.. _`Google Benchmark`: https://github.com/google/benchmark
445-
446-
Building Benchmarks
447-
-------------------
448-
449-
The benchmark tests are not built by default. The benchmarks can be built using
450-
the ``cxx-benchmarks`` target.
451-
452-
An example build would look like:
448+
The benchmarks are located under ``libcxx/test/benchmarks``. Running a benchmark
449+
works in the same way as running a test. Both the benchmarks and the tests share
450+
the same configuration, so make sure to enable the relevant optimization level
451+
when running the benchmarks. For example,
453452

454453
.. code-block:: bash
455454
456-
$ ninja -C build cxx-benchmarks
457-
458-
This will build all of the benchmarks under ``<libcxx>/test/benchmarks`` to be
459-
built against the just-built libc++. The compiled tests are output into
460-
``build/libcxx/test/benchmarks``.
455+
$ libcxx/utils/libcxx-lit <build> -sv libcxx/test/benchmarks/string.bench.cpp --param optimization=speed
461456
462-
Running Benchmarks
463-
------------------
457+
If you want to see where a benchmark is located (e.g. you want to store the executable
458+
for subsequent analysis), you can print that information by passing ``--show-all`` to
459+
``lit``. That will print the command-lines being executed, which includes the location
460+
of the executable created for that benchmark.
464461

465-
The benchmarks must be run manually by the user. Currently there is no way
466-
to run them as part of the build.
467-
468-
For example:
469-
470-
.. code-block:: bash
471-
472-
$ cd build/libcxx/test/benchmarks
473-
$ ./find.bench.out # Runs all the benchmarks
474-
$ ./find.bench.out --benchmark_filter="bm_ranges_find<std::vector<char>>" # Only runs that specific benchmark
475-
476-
For more information about running benchmarks see `Google Benchmark`_.
462+
Note that benchmarks are only dry-run when run via the ``check-cxx`` target since
463+
we only want to make sure they don't rot. Do not rely on the results of benchmarks
464+
run through ``check-cxx`` for anything, instead run the benchmarks manually using
465+
the instructions for running individual tests.
477466

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

479469
.. _testing-hardening-assertions:
480470

@@ -518,4 +508,3 @@ A toy example:
518508
519509
Note that error messages are only tested (matched) if the ``debug``
520510
hardening mode is used.
521-

libcxx/docs/VendorDocumentation.rst

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ General purpose options
244244

245245
**Default**: ``ON`` (or value of ``LLVM_INCLUDE_TESTS``)
246246

247-
Build the libc++ tests.
247+
Build the libc++ test suite, which includes various types of tests like conformance
248+
tests, vendor-specific tests and benchmarks.
248249

249250
.. option:: LIBCXX_INCLUDE_BENCHMARKS:BOOL
250251

@@ -253,15 +254,6 @@ General purpose options
253254
Build the libc++ benchmark tests and the Google Benchmark library needed
254255
to support them.
255256

256-
.. option:: LIBCXX_BENCHMARK_TEST_ARGS:STRING
257-
258-
**Default**: ``--benchmark_min_time=0.01``
259-
260-
A semicolon list of arguments to pass when running the libc++ benchmarks using the
261-
``check-cxx-benchmarks`` rule. By default we run the benchmarks for a very short amount of time,
262-
since the primary use of ``check-cxx-benchmarks`` is to get test and sanitizer coverage, not to
263-
get accurate measurements.
264-
265257
.. option:: LIBCXX_ASSERTION_HANDLER_FILE:PATH
266258

267259
**Default**:: ``"${CMAKE_CURRENT_SOURCE_DIR}/vendor/llvm/default_assertion_handler.in"``

libcxx/test/CMakeLists.txt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
include(HandleLitArguments)
22
add_subdirectory(tools)
33

4-
if (LIBCXX_INCLUDE_BENCHMARKS)
5-
add_subdirectory(benchmarks)
6-
endif()
7-
84
# Install the library at a fake location so we can run the test suite against it.
95
# This ensures that we run the test suite against a setup that matches what we ship
106
# in production as closely as possible (in terms of file paths, rpaths, etc).
@@ -66,6 +62,14 @@ set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to pick
6662

6763
serialize_lit_string_param(SERIALIZED_LIT_PARAMS compiler "${CMAKE_CXX_COMPILER}")
6864

65+
if (LIBCXX_INCLUDE_BENCHMARKS)
66+
add_subdirectory(benchmarks)
67+
set(_libcxx_benchmark_mode "dry-run")
68+
else()
69+
serialize_lit_string_param(SERIALIZED_LIT_PARAMS enable_benchmarks "no")
70+
set(_libcxx_benchmark_mode "no")
71+
endif()
72+
6973
if (NOT LIBCXX_ENABLE_EXCEPTIONS)
7074
serialize_lit_param(SERIALIZED_LIT_PARAMS enable_exceptions False)
7175
endif()
@@ -102,4 +106,5 @@ configure_lit_site_cfg(
102106
add_lit_testsuite(check-cxx
103107
"Running libcxx tests"
104108
${CMAKE_CURRENT_BINARY_DIR}
109+
PARAMS enable_benchmarks="${_libcxx_benchmark_mode}"
105110
DEPENDS cxx-test-depends)

libcxx/test/benchmarks/CMakeLists.txt

Lines changed: 10 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
include(ExternalProject)
2-
include(CheckCXXCompilerFlag)
3-
41
#==============================================================================
52
# Build Google Benchmark
63
#==============================================================================
74

5+
include(ExternalProject)
86
set(BENCHMARK_COMPILE_FLAGS
97
-Wno-unused-command-line-argument
108
-nostdinc++
@@ -24,6 +22,12 @@ if (DEFINED LIBCXX_CXX_ABI_LIBRARY_PATH)
2422
endif()
2523
split_list(BENCHMARK_COMPILE_FLAGS)
2624

25+
set(BENCHMARK_CXX_LIBRARIES)
26+
list(APPEND BENCHMARK_CXX_LIBRARIES c++)
27+
if (NOT LIBCXX_ENABLE_SHARED)
28+
list(APPEND BENCHMARK_CXX_LIBRARIES c++abi)
29+
endif()
30+
2731
ExternalProject_Add(google-benchmark
2832
EXCLUDE_FROM_ALL ON
2933
DEPENDS cxx cxx-headers
@@ -37,176 +41,7 @@ ExternalProject_Add(google-benchmark
3741
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
3842
-DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_COMPILE_FLAGS}
3943
-DBENCHMARK_USE_LIBCXX:BOOL=ON
40-
-DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
41-
42-
#==============================================================================
43-
# Benchmark tests configuration
44-
#==============================================================================
45-
add_custom_target(cxx-benchmarks)
46-
set(BENCHMARK_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
47-
set(BENCHMARK_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark)
48-
49-
add_library( cxx-benchmarks-flags INTERFACE)
50-
51-
# TODO(cmake): remove. This is a workaround to prevent older versions of GCC
52-
# from failing the configure step because they don't support C++23.
53-
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "13.0")
54-
return()
55-
endif()
56-
#TODO(cmake): remove the `add_compile_options`. Currently we have to explicitly
57-
# pass the `std:c++latest` flag on Windows to work around an issue where
58-
# requesting `cxx_std_23` results in an error -- somehow CMake fails to
59-
# translate the `c++23` flag into `c++latest`, and the highest numbered C++
60-
# version that MSVC flags support is C++20.
61-
if (MSVC)
62-
add_compile_options(/std:c++latest)
63-
# ibm-clang does not recognize the cxx_std_23 flag, so use this as a temporary
64-
# workaround on AIX as well.
65-
elseif (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
66-
add_compile_options(-std=c++23)
67-
else()
68-
target_compile_features( cxx-benchmarks-flags INTERFACE cxx_std_23)
69-
endif()
70-
71-
target_compile_options(cxx-benchmarks-flags INTERFACE -fsized-deallocation -nostdinc++
72-
${SANITIZER_FLAGS} -Wno-user-defined-literals -Wno-suggest-override)
73-
target_include_directories(cxx-benchmarks-flags INTERFACE "${LIBCXX_GENERATED_INCLUDE_DIR}"
74-
INTERFACE "${BENCHMARK_INSTALL_DIR}/include"
75-
INTERFACE "${LIBCXX_SOURCE_DIR}/test/support")
76-
target_link_options(cxx-benchmarks-flags INTERFACE -lm -nostdlib++
77-
"-L${BENCHMARK_INSTALL_DIR}/lib" "-L${BENCHMARK_INSTALL_DIR}/lib64"
78-
${SANITIZER_FLAGS})
44+
-DBENCHMARK_ENABLE_TESTING:BOOL=OFF
45+
-DBENCHMARK_CXX_LIBRARIES:STRING="${BENCHMARK_CXX_LIBRARIES}")
7946

80-
set(libcxx_benchmark_targets)
81-
82-
function(add_benchmark_test name source_file)
83-
set(libcxx_target ${name}_libcxx)
84-
list(APPEND libcxx_benchmark_targets ${libcxx_target})
85-
add_executable(${libcxx_target} EXCLUDE_FROM_ALL ${source_file})
86-
target_link_libraries(${libcxx_target} PRIVATE cxx-benchmarks-flags)
87-
add_dependencies(${libcxx_target} cxx google-benchmark)
88-
add_dependencies(cxx-benchmarks ${libcxx_target})
89-
if (LIBCXX_ENABLE_SHARED)
90-
target_link_libraries(${libcxx_target} PRIVATE cxx_shared)
91-
else()
92-
target_link_libraries(${libcxx_target} PRIVATE cxx_static)
93-
endif()
94-
target_link_libraries(${libcxx_target} PRIVATE cxx_experimental benchmark)
95-
if (LLVM_USE_SANITIZER)
96-
target_link_libraries(${libcxx_target} PRIVATE -ldl)
97-
endif()
98-
set_target_properties(${libcxx_target}
99-
PROPERTIES
100-
OUTPUT_NAME "${name}.bench.out"
101-
RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_OUTPUT_DIR}"
102-
CXX_EXTENSIONS NO)
103-
cxx_link_system_libraries(${libcxx_target})
104-
endfunction()
105-
106-
107-
#==============================================================================
108-
# Register Benchmark tests
109-
#==============================================================================
110-
set(BENCHMARK_TESTS
111-
algorithms.partition_point.bench.cpp
112-
algorithms/count.bench.cpp
113-
algorithms/equal.bench.cpp
114-
algorithms/find.bench.cpp
115-
algorithms/fill.bench.cpp
116-
algorithms/for_each.bench.cpp
117-
algorithms/lexicographical_compare.bench.cpp
118-
algorithms/lower_bound.bench.cpp
119-
algorithms/make_heap.bench.cpp
120-
algorithms/make_heap_then_sort_heap.bench.cpp
121-
algorithms/min.bench.cpp
122-
algorithms/minmax.bench.cpp
123-
algorithms/min_max_element.bench.cpp
124-
algorithms/mismatch.bench.cpp
125-
algorithms/pop_heap.bench.cpp
126-
algorithms/pstl.stable_sort.bench.cpp
127-
algorithms/push_heap.bench.cpp
128-
algorithms/ranges_contains.bench.cpp
129-
algorithms/ranges_ends_with.bench.cpp
130-
algorithms/ranges_make_heap.bench.cpp
131-
algorithms/ranges_make_heap_then_sort_heap.bench.cpp
132-
algorithms/ranges_pop_heap.bench.cpp
133-
algorithms/ranges_push_heap.bench.cpp
134-
algorithms/ranges_sort.bench.cpp
135-
algorithms/ranges_sort_heap.bench.cpp
136-
algorithms/ranges_stable_sort.bench.cpp
137-
algorithms/set_intersection.bench.cpp
138-
algorithms/sort.bench.cpp
139-
algorithms/sort_heap.bench.cpp
140-
algorithms/stable_sort.bench.cpp
141-
atomic_wait.bench.cpp
142-
atomic_wait_vs_mutex_lock.bench.cpp
143-
libcxxabi/dynamic_cast.bench.cpp
144-
libcxxabi/dynamic_cast_old_stress.bench.cpp
145-
allocation.bench.cpp
146-
deque.bench.cpp
147-
deque_iterator.bench.cpp
148-
exception_ptr.bench.cpp
149-
filesystem.bench.cpp
150-
format/write_double_comparison.bench.cpp
151-
format/write_int_comparison.bench.cpp
152-
format/write_string_comparison.bench.cpp
153-
format_to_n.bench.cpp
154-
format_to.bench.cpp
155-
format.bench.cpp
156-
formatted_size.bench.cpp
157-
formatter_float.bench.cpp
158-
formatter_int.bench.cpp
159-
function.bench.cpp
160-
hash.bench.cpp
161-
join_view.bench.cpp
162-
lexicographical_compare_three_way.bench.cpp
163-
map.bench.cpp
164-
monotonic_buffer.bench.cpp
165-
numeric/gcd.bench.cpp
166-
ordered_set.bench.cpp
167-
shared_mutex_vs_mutex.bench.cpp
168-
stop_token.bench.cpp
169-
std_format_spec_string_unicode.bench.cpp
170-
std_format_spec_string_unicode_escape.bench.cpp
171-
string.bench.cpp
172-
stringstream.bench.cpp
173-
system_error.bench.cpp
174-
to_chars.bench.cpp
175-
unordered_set_operations.bench.cpp
176-
util_smartptr.bench.cpp
177-
variant_visit_1.bench.cpp
178-
variant_visit_2.bench.cpp
179-
variant_visit_3.bench.cpp
180-
vector_operations.bench.cpp
181-
)
182-
183-
foreach(test_path ${BENCHMARK_TESTS})
184-
get_filename_component(test_file "${test_path}" NAME)
185-
string(REPLACE ".bench.cpp" "" test_name "${test_file}")
186-
if (NOT DEFINED ${test_name}_REPORTED)
187-
message(STATUS "Adding Benchmark: ${test_file}")
188-
# Only report the adding of the benchmark once.
189-
set(${test_name}_REPORTED ON CACHE INTERNAL "")
190-
endif()
191-
add_benchmark_test(${test_name} ${test_path})
192-
endforeach()
193-
194-
if (LIBCXX_INCLUDE_TESTS)
195-
include(AddLLVM)
196-
197-
configure_lit_site_cfg(
198-
${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py.in
199-
${CMAKE_CURRENT_BINARY_DIR}/lit.cfg.py)
200-
201-
configure_lit_site_cfg(
202-
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
203-
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
204-
205-
set(BENCHMARK_LIT_ARGS "--show-all --show-xfail --show-unsupported ${LIT_ARGS_DEFAULT}")
206-
207-
add_lit_target(check-cxx-benchmarks
208-
"Running libcxx benchmarks tests"
209-
${CMAKE_CURRENT_BINARY_DIR}
210-
DEPENDS cxx-benchmarks cxx-test-depends
211-
ARGS ${BENCHMARK_LIT_ARGS})
212-
endif()
47+
add_dependencies(cxx-test-depends google-benchmark)

libcxx/test/benchmarks/algorithms/min.bench.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ BENCHMARK(BM_std_min<unsigned char>)->Apply(run_sizes);
7878
BENCHMARK(BM_std_min<unsigned short>)->Apply(run_sizes);
7979
BENCHMARK(BM_std_min<unsigned int>)->Apply(run_sizes);
8080
BENCHMARK(BM_std_min<unsigned long long>)->Apply(run_sizes);
81+
#ifndef TEST_HAS_NO_INT128
8182
BENCHMARK(BM_std_min<unsigned __int128>)->Apply(run_sizes);
83+
#endif
8284

8385
BENCHMARK_MAIN();

libcxx/test/benchmarks/atomic_wait_vs_mutex_lock.bench.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88

99
// UNSUPPORTED: c++03, c++11, c++14, c++17
1010

11-
// To run this test, build libcxx and cxx-benchmarks targets
12-
// cd third-party/benchmark/tools
13-
// ./compare.py filters ../../../build/libcxx/benchmarks/atomic_wait_vs_mutex_lock.libcxx.out BM_atomic_wait BM_mutex
14-
1511
#include <atomic>
1612
#include <mutex>
1713
#include <numeric>

0 commit comments

Comments
 (0)