Skip to content

Commit f19ffaa

Browse files
committed
[libc++] Unify the benchmarks with the test suite
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 a GoogleBenchmark issue. 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 b2d2494 commit f19ffaa

21 files changed

+96
-408
lines changed

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

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

libcxx/CMakeLists.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,13 @@ 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: On Windows and MinGW, disable the benchmarks since we don't know how to build GoogleBenchmark yet
154+
if (WIN32 OR MINGW)
155+
set(_include_benchmarks OFF)
156+
else()
157+
set(_include_benchmarks ON)
158+
endif()
159+
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ${_include_benchmarks})
159160

160161
option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
161162
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: 11 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,16 @@ 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+
AND LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_THREADS AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_RANDOM_DEVICE
67+
AND LIBCXX_ENABLE_EXCEPTIONS AND LIBCXX_ENABLE_RTTI) # TODO: The benchmarks should work with exceptions/RTTI disabled
68+
add_subdirectory(benchmarks)
69+
set(_libcxx_benchmark_mode "dry-run")
70+
else()
71+
serialize_lit_string_param(SERIALIZED_LIT_PARAMS enable_benchmarks "no")
72+
set(_libcxx_benchmark_mode "no")
73+
endif()
74+
6975
if (NOT LIBCXX_ENABLE_EXCEPTIONS)
7076
serialize_lit_param(SERIALIZED_LIT_PARAMS enable_exceptions False)
7177
endif()
@@ -102,4 +108,5 @@ configure_lit_site_cfg(
102108
add_lit_testsuite(check-cxx
103109
"Running libcxx tests"
104110
${CMAKE_CURRENT_BINARY_DIR}
111+
PARAMS enable_benchmarks="${_libcxx_benchmark_mode}"
105112
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)