Skip to content

Commit 5adb0bf

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 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 94b7d21 commit 5adb0bf

File tree

14 files changed

+67
-405
lines changed

14 files changed

+67
-405
lines changed

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,7 @@ jobs:
154154
'generic-no-rtti',
155155
'generic-optimized-speed',
156156
'generic-static',
157-
# TODO Find a better place for the benchmark and bootstrapping builds to live. They're either very expensive
158-
# or don't provide much value since the benchmark run results are too noise on the bots.
159-
'benchmarks',
157+
# TODO Find a better place for the bootstrapping build to live, since it's very expensive.
160158
'bootstrapping-build'
161159
]
162160
machine: [ 'libcxx-runners-8-set' ]

libcxx/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,8 @@ message(STATUS "Using libc++ testing configuration: ${LIBCXX_TEST_CONFIG}")
156156
set(LIBCXX_TEST_PARAMS "" CACHE STRING
157157
"A list of parameters to run the Lit test suite with.")
158158

159-
# Benchmark options -----------------------------------------------------------
160159
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ON)
161160

162-
set(LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT --benchmark_min_time=0.01)
163-
set(LIBCXX_BENCHMARK_TEST_ARGS "${LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT}" CACHE STRING
164-
"Arguments to pass when running the benchmarks using check-cxx-benchmarks")
165-
166161
option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
167162
set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
168163
"Define suffix of library directory name (32/64)")

libcxx/docs/BuildingLibcxx.rst

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,8 @@ libc++ Feature Options
381381

382382
**Default**: ``ON`` (or value of ``LLVM_INCLUDE_TESTS``)
383383

384-
Build the libc++ tests.
384+
Build the libc++ test suite, which includes various types of tests like conformance
385+
tests, vendor-specific tests and benchmarks.
385386

386387
.. option:: LIBCXX_INCLUDE_BENCHMARKS:BOOL
387388

@@ -390,15 +391,6 @@ libc++ Feature Options
390391
Build the libc++ benchmark tests and the Google Benchmark library needed
391392
to support them.
392393

393-
.. option:: LIBCXX_BENCHMARK_TEST_ARGS:STRING
394-
395-
**Default**: ``--benchmark_min_time=0.01``
396-
397-
A semicolon list of arguments to pass when running the libc++ benchmarks using the
398-
``check-cxx-benchmarks`` rule. By default we run the benchmarks for a very short amount of time,
399-
since the primary use of ``check-cxx-benchmarks`` is to get test and sanitizer coverage, not to
400-
get accurate measurements.
401-
402394
.. option:: LIBCXX_ASSERTION_HANDLER_FILE:PATH
403395

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

libcxx/docs/TestingLibcxx.rst

Lines changed: 14 additions & 39 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 contain micro-benchmarks of individual
397+
components of the library.
398+
395399

396400
libc++-Specific Lit Features
397401
----------------------------
@@ -438,48 +442,20 @@ 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:
453-
454-
.. code-block:: bash
455-
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``.
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.
461452

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

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

484460
.. _testing-hardening-assertions:
485461

@@ -523,4 +499,3 @@ A toy example:
523499
524500
Note that error messages are only tested (matched) if the ``debug``
525501
hardening mode is used.
526-

libcxx/test/CMakeLists.txt

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

4-
if (LIBCXX_INCLUDE_BENCHMARKS)
5-
add_subdirectory(benchmarks)
6-
endif()
7-
84
set(AUTO_GEN_COMMENT "## Autogenerated by libcxx configuration.\n# Do not edit!")
95
set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to pick them up\n")
106

117
serialize_lit_string_param(SERIALIZED_LIT_PARAMS compiler "${CMAKE_CXX_COMPILER}")
128

9+
if (LIBCXX_INCLUDE_BENCHMARKS
10+
AND LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_THREADS AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_RANDOM_DEVICE
11+
AND LIBCXX_ENABLE_EXCEPTIONS AND LIBCXX_ENABLE_RTTI) # TODO: The benchmarks should work with exceptions/RTTI disabled
12+
add_subdirectory(benchmarks)
13+
set(_libcxx_benchmark_mode "dry-run")
14+
else()
15+
serialize_lit_string_param(SERIALIZED_LIT_PARAMS enable_benchmarks "no")
16+
set(_libcxx_benchmark_mode "no")
17+
endif()
18+
1319
if (NOT LIBCXX_ENABLE_EXCEPTIONS)
1420
serialize_lit_param(SERIALIZED_LIT_PARAMS enable_exceptions False)
1521
endif()
@@ -46,4 +52,5 @@ configure_lit_site_cfg(
4652
add_lit_testsuite(check-cxx
4753
"Running libcxx tests"
4854
${CMAKE_CURRENT_BINARY_DIR}
55+
PARAMS enable_benchmarks="${_libcxx_benchmark_mode}"
4956
DEPENDS cxx-test-depends)

libcxx/test/benchmarks/CMakeLists.txt

Lines changed: 2 additions & 169 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++
@@ -39,169 +37,4 @@ ExternalProject_Add(google-benchmark
3937
-DBENCHMARK_USE_LIBCXX:BOOL=ON
4038
-DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
4139

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})
79-
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/lower_bound.bench.cpp
118-
algorithms/make_heap.bench.cpp
119-
algorithms/make_heap_then_sort_heap.bench.cpp
120-
algorithms/min.bench.cpp
121-
algorithms/minmax.bench.cpp
122-
algorithms/min_max_element.bench.cpp
123-
algorithms/mismatch.bench.cpp
124-
algorithms/pop_heap.bench.cpp
125-
algorithms/pstl.stable_sort.bench.cpp
126-
algorithms/push_heap.bench.cpp
127-
algorithms/ranges_contains.bench.cpp
128-
algorithms/ranges_ends_with.bench.cpp
129-
algorithms/ranges_make_heap.bench.cpp
130-
algorithms/ranges_make_heap_then_sort_heap.bench.cpp
131-
algorithms/ranges_pop_heap.bench.cpp
132-
algorithms/ranges_push_heap.bench.cpp
133-
algorithms/ranges_sort.bench.cpp
134-
algorithms/ranges_sort_heap.bench.cpp
135-
algorithms/ranges_stable_sort.bench.cpp
136-
algorithms/set_intersection.bench.cpp
137-
algorithms/sort.bench.cpp
138-
algorithms/sort_heap.bench.cpp
139-
algorithms/stable_sort.bench.cpp
140-
atomic_wait.bench.cpp
141-
atomic_wait_vs_mutex_lock.bench.cpp
142-
libcxxabi/dynamic_cast.bench.cpp
143-
libcxxabi/dynamic_cast_old_stress.bench.cpp
144-
allocation.bench.cpp
145-
deque.bench.cpp
146-
deque_iterator.bench.cpp
147-
exception_ptr.bench.cpp
148-
filesystem.bench.cpp
149-
format_to_n.bench.cpp
150-
format_to.bench.cpp
151-
format.bench.cpp
152-
formatted_size.bench.cpp
153-
formatter_float.bench.cpp
154-
formatter_int.bench.cpp
155-
function.bench.cpp
156-
join_view.bench.cpp
157-
lexicographical_compare_three_way.bench.cpp
158-
map.bench.cpp
159-
monotonic_buffer.bench.cpp
160-
numeric/gcd.bench.cpp
161-
ordered_set.bench.cpp
162-
shared_mutex_vs_mutex.bench.cpp
163-
stop_token.bench.cpp
164-
std_format_spec_string_unicode.bench.cpp
165-
std_format_spec_string_unicode_escape.bench.cpp
166-
string.bench.cpp
167-
stringstream.bench.cpp
168-
system_error.bench.cpp
169-
to_chars.bench.cpp
170-
unordered_set_operations.bench.cpp
171-
util_smartptr.bench.cpp
172-
variant_visit_1.bench.cpp
173-
variant_visit_2.bench.cpp
174-
variant_visit_3.bench.cpp
175-
vector_operations.bench.cpp
176-
)
177-
178-
foreach(test_path ${BENCHMARK_TESTS})
179-
get_filename_component(test_file "${test_path}" NAME)
180-
string(REPLACE ".bench.cpp" "" test_name "${test_file}")
181-
if (NOT DEFINED ${test_name}_REPORTED)
182-
message(STATUS "Adding Benchmark: ${test_file}")
183-
# Only report the adding of the benchmark once.
184-
set(${test_name}_REPORTED ON CACHE INTERNAL "")
185-
endif()
186-
add_benchmark_test(${test_name} ${test_path})
187-
endforeach()
188-
189-
if (LIBCXX_INCLUDE_TESTS)
190-
include(AddLLVM)
191-
192-
configure_lit_site_cfg(
193-
${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py.in
194-
${CMAKE_CURRENT_BINARY_DIR}/lit.cfg.py)
195-
196-
configure_lit_site_cfg(
197-
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
198-
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
199-
200-
set(BENCHMARK_LIT_ARGS "--show-all --show-xfail --show-unsupported ${LIT_ARGS_DEFAULT}")
201-
202-
add_lit_target(check-cxx-benchmarks
203-
"Running libcxx benchmarks tests"
204-
${CMAKE_CURRENT_BINARY_DIR}
205-
DEPENDS cxx-benchmarks cxx-test-depends
206-
ARGS ${BENCHMARK_LIT_ARGS})
207-
endif()
40+
add_dependencies(cxx-test-depends google-benchmark)

libcxx/test/benchmarks/lit.cfg.py.in

Lines changed: 0 additions & 23 deletions
This file was deleted.

libcxx/test/benchmarks/lit.site.cfg.py.in

Lines changed: 0 additions & 10 deletions
This file was deleted.

libcxx/test/configs/cmake-bridge.cfg.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ config.substitutions.append(('%{target-include-dir}', '@LIBCXX_GENERATED_INCLUDE
2929
config.substitutions.append(('%{lib-dir}', '@LIBCXX_LIBRARY_DIR@'))
3030
config.substitutions.append(('%{module-dir}', '@LIBCXX_GENERATED_MODULE_DIR@'))
3131
config.substitutions.append(('%{test-tools-dir}', '@LIBCXX_TEST_TOOLS_PATH@'))
32+
config.substitutions.append(('%{benchmark_flags}', '-I @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/include -L @LIBCXX_BINARY_DIR@/test/benchmarks/google-benchmark/lib -l benchmark'))

0 commit comments

Comments
 (0)