mirror of
https://github.com/catchorg/Catch2.git
synced 2026-08-10 15:41:32 +02:00
Avoid n^2 behaviour when appending script commands in catch_discover_tests
Repeatedly calling `string(APPEND` on the same destination string leads to quadratic running time. We avoid this by flushing the CTest script into a file periodically, currently every 50kB of text. This can cause _slight_ slowdown just around the flush boundary (each file write is quite expensive, so if we flush just before the last test is written, it hurts), but it avoids terrible performance for large test suites. The performance is roughly equal at 500 tests to discover, and clearly wins at more; for 1/2/4/8 k tests, the improvements are 0.3/1.6/6.4/27 s.
This commit is contained in:
@@ -75,6 +75,12 @@ function(catch_discover_tests_impl)
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
# We periodically append to the output file below, so we have to ensure
|
||||
# that it is empty at the start, or we get duplicated test scripts.
|
||||
file(REMOVE "${_CTEST_FILE}")
|
||||
# Size (in Bytes) at which the intermediate `script` var is dumped to file.
|
||||
set(_WriteToFileThreshold 50000)
|
||||
|
||||
set(add_tags "${_ADD_TAGS_AS_LABELS}")
|
||||
set(prefix "${_TEST_PREFIX}")
|
||||
set(suffix "${_TEST_SUFFIX}")
|
||||
@@ -213,6 +219,15 @@ function(catch_discover_tests_impl)
|
||||
math(EXPR num_tests "${num_tests} - 1")
|
||||
|
||||
foreach(idx RANGE ${num_tests})
|
||||
string(LENGTH "${script}" script_len)
|
||||
# Because appending to the same string in CMake has quadratic runtime,
|
||||
# we flush the script into the file periodically to avoid the worst case.
|
||||
if (script_len GREATER _WriteToFileThreshold)
|
||||
file(APPEND "${_CTEST_FILE}" "${script}")
|
||||
set(script "")
|
||||
endif()
|
||||
|
||||
|
||||
if(add_tags)
|
||||
string(JSON single_test GET "${test_listing}" ${idx})
|
||||
string(JSON test_tags GET "${single_test}" "tags")
|
||||
@@ -295,8 +310,8 @@ function(catch_discover_tests_impl)
|
||||
prepare_command(set ${_TEST_LIST} ${tests})
|
||||
string(APPEND script "${_Command}")
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${_CTEST_FILE}" "${script}")
|
||||
# Write any script leftovers we have
|
||||
file(APPEND "${_CTEST_FILE}" "${script}")
|
||||
endfunction()
|
||||
|
||||
# To enable `include`ing this file in the unit test scripts, we only run
|
||||
|
||||
Reference in New Issue
Block a user