Skip to content

Commit

Permalink
cmake: allow running the tests in parallel like in the Makefile (#102)
Browse files Browse the repository at this point in the history
Allow running tests in parallel by default by setting the CTEST_PARALLEL_LEVEL
environment variable. The functionality is added using a CMake script in
order to determine options when running the tests (rather than when configuring
CMake) in compatibility with the Makefile (in particular -- the `J` and
`TEST_TMPDIR` environment variables).

Test Plan: run the check target using different generators (ninja, make)
to see the improvement in test runtime.
  • Loading branch information
isaac-io committed Aug 19, 2022
1 parent 643d7a9 commit 5099fa5
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 3 deletions.
23 changes: 20 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,18 @@ if(WITH_TESTS OR WITH_BENCHMARK_TOOLS)
endif()

if(WITH_TESTS)
# c_test - doesn't use gtest
# env_test - suspicious use of test::TmpDir
# deletefile_test - serial because it generates giant temporary files in
# its various tests. Running its tests in parallel can fill up your /dev/shm
# db_bloom_filter_test - serial because excessive space usage by instances
# of DBFilterConstructionReserveMemoryTestWithParam can fill up /dev/shm
set(NON_PARALLEL_TEST
c_test
env_test
deletefile_test
db_bloom_filter_test
)
set(TESTS
db/db_basic_test.cc
env/env_basic_test.cc
Expand Down Expand Up @@ -1396,7 +1408,10 @@ if(WITH_TESTS)
utilities/cassandra/test_utils.cc
)
enable_testing()
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
add_custom_target(check
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/CTestRunner.cmake
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
VERBATIM USES_TERMINAL)
set(TESTUTILLIB testutillib${ARTIFACT_SUFFIX})
add_library(${TESTUTILLIB} STATIC ${TESTUTIL_SOURCE})
target_link_libraries(${TESTUTILLIB} ${ROCKSDB_LIB})
Expand All @@ -1419,10 +1434,12 @@ if(WITH_TESTS)
OUTPUT_NAME ${exename}${ARTIFACT_SUFFIX}
)
target_link_libraries(${exename}${ARTIFACT_SUFFIX} ${TESTUTILLIB} testharness gtest ${THIRDPARTY_LIBS} ${ROCKSDB_LIB})
if(NOT "${exename}" MATCHES "db_sanity_test")
if(NOT "${exename}" IN_LIST NON_PARALLEL_TEST)
gtest_discover_tests(${exename} DISCOVERY_TIMEOUT 120)
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
else()
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
endif()
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
endforeach(sourcefile ${TESTS})

if(WIN32)
Expand Down
85 changes: 85 additions & 0 deletions cmake/CTestRunner.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright (C) 2022 Speedb Ltd. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Choose the amount of tests to run in parallel if CTEST_PARALLEL_LEVEL wasn't set
if(NOT DEFINED ENV{CTEST_PARALLEL_LEVEL})
# Compatibility with the Makefile: support the `J` environment variable
if(DEFINED ENV{J} AND "$ENV{J}" GREATER 0)
set(ENV{CTEST_PARALLEL_LEVEL} ${ENV{J}})
else()
include(ProcessorCount)
ProcessorCount(NCPU)
if(NOT NCPU EQUAL 0)
set(ENV{CTEST_PARALLEL_LEVEL} ${NCPU})
endif()
endif()
endif()

# For Makefile compatibility try the following sequence if TEST_TMPDIR isn't set:
# * Use TMPD if set
# * Create a temp directory under /dev/shm on Linux if it has the sticky bit set
# * Use TMPDIR if set, and if not on Windows create a temp directory under it
# * If not on Windows, fall back to creating a temp directory under /tmp if exists
if(NOT DEFINED ENV{TEST_TMPDIR})
# Use TMPD if set
if(DEFINED ENV{TMPD})
set(test_dir ENV{TMPD})
else()
# On Linux, use /dev/shm if the sticky bit is set
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux" AND IS_DIRECTORY /dev/shm)
execute_process(COMMAND test -k /dev/shm RESULT_VARIABLE status OUTPUT_QUIET ERROR_QUIET)
if(status EQUAL 0)
set(test_dir /dev/shm)
endif()
endif()
# Use TMPDIR as base if set
if(NOT DEFINED test_dir AND IS_DIRECTORY "$ENV{TMPDIR}")
set(test_dir $ENV{TMPDIR})
endif()
if(NOT "${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
# Fall back to /tmp if exists
if(NOT DEFINED test_dir AND IS_DIRECTORY /tmp)
set(test_dir /tmp)
endif()
# Create a temporary directory under the test location that we determined
if(DEFINED test_dir)
execute_process(
COMMAND "mktemp" "-d" "${test_dir}/rocksdb.XXXX"
RESULT_VARIABLE status OUTPUT_VARIABLE tmpdir
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT status EQUAL 0)
message(FATAL_ERROR "mkdtemp failed")
endif()
set(test_dir ${tmpdir})
endif()
endif()
endif()
if(DEFINED test_dir)
set(ENV{TEST_TMPDIR} ${test_dir})
endif()
endif()

if(DEFINED ENV{TEST_TMPDIR})
message(STATUS "Running $ENV{CTEST_PARALLEL_LEVEL} tests in parallel in $ENV{TEST_TMPDIR}")
endif()

# Use a timeout of 10 minutes per test by default
if(DEFINED ENV{TEST_TIMEOUT})
set(test_timeout "$ENV{TEST_TIMEOUT}")
else()
set(test_timeout 600)
endif()

# Run all tests, and show test output on failure
execute_process(COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure --timeout ${test_timeout})

0 comments on commit 5099fa5

Please sign in to comment.