更大的 cmake ctest 的奇怪行为 CTEST_PARALLEL_LEVEL
strange behavior of cmake ctest for bigger CTEST_PARALLEL_LEVEL
我是 SO 的新手。
我有一个简单的单元测试代码,我正在执行以下操作:
- 使用
mysqrt
库计算数字的平方根。
- 使用平方根的输出,将此结果与相同的数字相加并显示结果。
当我运行使用 CTEST_PARALLEL_LEVEL = 1
编写代码时,我的所有测试用例都通过了。
但是当我做 CTEST_PARALLEL_LEVEL = 8
时,我的测试用例在某些输入上失败了一段时间,这些输入在每个 运行.
中都不是固定的
99% 的所有结果都通过了,但 1% 的结果失败了。
错误:
mysqrt.o: file not recognized: File truncated
我已经使用 rm *.o 显式删除了目标文件,但是在 运行s 之后仍然出现这个错误。
我不确定为什么 CTEST_PARALLEL_LEVEL = 8
会出现此错误
我附上我的 CMakeList
只是因为一些 Stack Overflow 专家可以通过检查这 3 个 CMakeLists.txt
文件来理解这个问题。
注意:根据 Stack overflow 指南,我没有附上我的 sqrt 和 addition 函数的源代码以避免更大的长度的问题。
我的文件夹结构:
SAMPLE_TEST
├── CMakeLists.txt
├── MathFunctions
│ ├── CMakeLists.txt
│ ├── MathFunctions.h
│ └── mysqrt.cpp
└── unit_test
├── CMakeLists.txt
└── step2
├── CMakeLists.txt
├── execute.cpp
└── tutorial.cpp
SAMPLE_TEST
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(Tutorial)
ENABLE_TESTING()
add_subdirectory(MathFunctions)
add_subdirectory(unit_test)
MathFunctions 文件夹
CMakeLists.txt
add_library(MathFunctions mysqrt.cpp)
set(REF_FILES mysqrt.cpp)
add_definitions(-Wall -Wextra -pedantic -std=c++11)
add_custom_target(build_reference_library
DEPENDS sqrtlib
COMMENT "Generating sqrtlib")
ADD_LIBRARY(sqrtlib OBJECT ${REF_FILES})
unit_test文件夹
CMakeLists.txt
set(REF_MATHLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../MathFunctions)
macro(GENERATION file input)
set(ip_generator ctest_input_${input})
add_executable(${ip_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${ip_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${ip_generator} PUBLIC
dl pthread
)
target_include_directories(${ip_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(INPUT_FILE0_TXT ip0_${input}.txt)
add_custom_command(
OUTPUT ${INPUT_FILE0} ${INPUT_FILE0_TXT}
COMMAND ${ip_generator} > ${INPUT_FILE0_TXT}
MAIN_DEPENDENCY ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_input_${input}
DEPENDS ${INPUT_FILE0}
COMMENT "Generated output files")
endmacro()
####################
macro(EXECUTE file input)
get_filename_component(main_base_name ${file} NAME_WE)
set(main_base_name_mangled ${main_base_name}_${input})
set(exe_generator ctest_ref_${input})
add_executable(${exe_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${exe_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${exe_generator} PUBLIC
dl pthread
)
target_include_directories(${exe_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(EXE_FILE0 exeadd_${input}.y)
set(EXE_FILE_TXT exeadd_${input}.txt)
add_custom_command(
OUTPUT ${EXE_FILE0} ${EXE_FILE_TXT}
COMMAND ${exe_generator} > ${EXE_FILE_TXT}
MAIN_DEPENDENCY ${INPUT_FILE0} ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_execute_${input}
DEPENDS ${EXE_FILE0}
COMMENT "Generated output files")
# add test to simulate
add_test(NAME ctest_execute_${input}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
--target gen_execute_${input})
#add_dependencies(execute_${main_base_name_mangled}
#gen_input)
endmacro()
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
# add test directories
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
set(TEST_DIRECTORIES
step2
)
foreach(dir ${TEST_DIRECTORIES})
add_subdirectory(${dir})
endforeach()
step2文件夹
CMakeLists.txt
set(UT_IPGEN_FILES tutorial.cpp)
set(UT_EXECUTE_FILES execute.cpp)
set(input_integer_range 1 4 9 16 25 36 49 64 81 100 121 144 )
foreach(ip_integer ${input_integer_range})
GENERATION(${UT_IPGEN_FILES} ${ip_integer})
EXECUTE(${UT_EXECUTE_FILES} ${ip_integer})
endforeach(ip_integer)
结果:
第一 运行:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #4: ctest_execute_16 .................***Failed 1.14 sec
2/12 Test #6: ctest_execute_36 ................. Passed 1.27 sec
3/12 Test #7: ctest_execute_49 ................. Passed 1.32 sec
4/12 Test #8: ctest_execute_64 ................. Passed 1.32 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
Start 12: ctest_execute_144
5/12 Test #1: ctest_execute_1 .................. Passed 1.33 sec
6/12 Test #2: ctest_execute_4 .................. Passed 1.33 sec
7/12 Test #3: ctest_execute_9 .................. Passed 1.33 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.33 sec
9/12 Test #10: ctest_execute_100 ................ Passed 0.54 sec
10/12 Test #11: ctest_execute_121 ................ Passed 0.55 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.55 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.55 sec
92% tests passed, 1 tests failed out of 12
Total Test time (real) = 1.88 sec
The following tests FAILED:
4 - ctest_execute_16 (Failed)
第二 运行:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #6: ctest_execute_36 ................. Passed 1.31 sec
2/12 Test #7: ctest_execute_49 ................. Passed 1.36 sec
3/12 Test #8: ctest_execute_64 ................. Passed 1.36 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
4/12 Test #1: ctest_execute_1 .................. Passed 1.37 sec
5/12 Test #2: ctest_execute_4 .................. Passed 1.37 sec
6/12 Test #3: ctest_execute_9 .................. Passed 1.36 sec
7/12 Test #4: ctest_execute_16 ................. Passed 1.36 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.37 sec
Start 12: ctest_execute_144
9/12 Test #11: ctest_execute_121 ................ Passed 0.50 sec
10/12 Test #10: ctest_execute_100 ................ Passed 0.51 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.51 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.34 sec
100% tests passed, 0 tests failed out of 12
Total Test time (real) = 2.01 sec
您的测试正在执行
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ...
在项目的构建目录中有效 运行s make
(或您使用的任何构建工具)。
但是在同一目录中 make
的并发调用永远不能保证正常工作。这就是为什么 运行 并行测试(设置了 CTEST_PARALLEL_LEVEL
变量)时出现奇怪错误的原因。
例如所有这些测试都试图创建相同的目标文件 mysqrt.o
,而这个创建绝对不是 thread-safe.
来自 运行宁
make sqrtlib
之前
ctest
您可以确定当测试 运行 时目标文件已经创建,并且测试不会尝试再次创建它。
但是你仍然可以在并行测试中遇到其他冲突。
这取决于你实际想通过测试检查什么,但通常 test 检查某些程序或库的 behavior,并且它不打算检查该程序的编译(构建)。因此,编译(构建)命令在 在 测试之前执行。
通常遵循(实施)此工作流程进行测试很方便:
# Configure the project
cmake <source-directory>
# Build the project.
# It builds both program/library intended, and the tests themselves.
make
# run tests
ctest <params>
在那种情况下,测试可以具有以下定义:
add_test(NAME ctest_execute_${input} COMMAND ${exe_generator})
(除非您想通过某种自动方式检查测试的输出,否则无需通过重定向到文件中来明确保存此输出。ctest
本身会收集测试的输出,因此您如果需要可以阅读它)。
我是 SO 的新手。 我有一个简单的单元测试代码,我正在执行以下操作:
- 使用
mysqrt
库计算数字的平方根。 - 使用平方根的输出,将此结果与相同的数字相加并显示结果。
当我运行使用 CTEST_PARALLEL_LEVEL = 1
编写代码时,我的所有测试用例都通过了。
但是当我做 CTEST_PARALLEL_LEVEL = 8
时,我的测试用例在某些输入上失败了一段时间,这些输入在每个 运行.
99% 的所有结果都通过了,但 1% 的结果失败了。
错误:
mysqrt.o: file not recognized: File truncated
我已经使用 rm *.o 显式删除了目标文件,但是在 运行s 之后仍然出现这个错误。
我不确定为什么 CTEST_PARALLEL_LEVEL = 8
我附上我的 CMakeList
只是因为一些 Stack Overflow 专家可以通过检查这 3 个 CMakeLists.txt
文件来理解这个问题。
注意:根据 Stack overflow 指南,我没有附上我的 sqrt 和 addition 函数的源代码以避免更大的长度的问题。
我的文件夹结构:
SAMPLE_TEST
├── CMakeLists.txt
├── MathFunctions
│ ├── CMakeLists.txt
│ ├── MathFunctions.h
│ └── mysqrt.cpp
└── unit_test
├── CMakeLists.txt
└── step2
├── CMakeLists.txt
├── execute.cpp
└── tutorial.cpp
SAMPLE_TEST
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(Tutorial)
ENABLE_TESTING()
add_subdirectory(MathFunctions)
add_subdirectory(unit_test)
MathFunctions 文件夹
CMakeLists.txt
add_library(MathFunctions mysqrt.cpp)
set(REF_FILES mysqrt.cpp)
add_definitions(-Wall -Wextra -pedantic -std=c++11)
add_custom_target(build_reference_library
DEPENDS sqrtlib
COMMENT "Generating sqrtlib")
ADD_LIBRARY(sqrtlib OBJECT ${REF_FILES})
unit_test文件夹
CMakeLists.txt
set(REF_MATHLIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../MathFunctions)
macro(GENERATION file input)
set(ip_generator ctest_input_${input})
add_executable(${ip_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${ip_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${ip_generator} PUBLIC
dl pthread
)
target_include_directories(${ip_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(INPUT_FILE0_TXT ip0_${input}.txt)
add_custom_command(
OUTPUT ${INPUT_FILE0} ${INPUT_FILE0_TXT}
COMMAND ${ip_generator} > ${INPUT_FILE0_TXT}
MAIN_DEPENDENCY ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_input_${input}
DEPENDS ${INPUT_FILE0}
COMMENT "Generated output files")
endmacro()
####################
macro(EXECUTE file input)
get_filename_component(main_base_name ${file} NAME_WE)
set(main_base_name_mangled ${main_base_name}_${input})
set(exe_generator ctest_ref_${input})
add_executable(${exe_generator}
${file}
$<TARGET_OBJECTS:sqrtlib>
)
target_compile_options(${exe_generator} PUBLIC
-Wall -Wextra -g -std=c++11
-DCTEST_INPUT=${input})
target_link_libraries(${exe_generator} PUBLIC
dl pthread
)
target_include_directories(${exe_generator} PUBLIC
${REF_MATHLIB_DIR}
)
set(INPUT_FILE0 ip0_${input}.y)
set(EXE_FILE0 exeadd_${input}.y)
set(EXE_FILE_TXT exeadd_${input}.txt)
add_custom_command(
OUTPUT ${EXE_FILE0} ${EXE_FILE_TXT}
COMMAND ${exe_generator} > ${EXE_FILE_TXT}
MAIN_DEPENDENCY ${INPUT_FILE0} ${sqrtlib}
COMMENT "Generating output files of for testcase")
add_custom_target(gen_execute_${input}
DEPENDS ${EXE_FILE0}
COMMENT "Generated output files")
# add test to simulate
add_test(NAME ctest_execute_${input}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
--target gen_execute_${input})
#add_dependencies(execute_${main_base_name_mangled}
#gen_input)
endmacro()
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
# add test directories
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
set(TEST_DIRECTORIES
step2
)
foreach(dir ${TEST_DIRECTORIES})
add_subdirectory(${dir})
endforeach()
step2文件夹
CMakeLists.txt
set(UT_IPGEN_FILES tutorial.cpp)
set(UT_EXECUTE_FILES execute.cpp)
set(input_integer_range 1 4 9 16 25 36 49 64 81 100 121 144 )
foreach(ip_integer ${input_integer_range})
GENERATION(${UT_IPGEN_FILES} ${ip_integer})
EXECUTE(${UT_EXECUTE_FILES} ${ip_integer})
endforeach(ip_integer)
结果: 第一 运行:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #4: ctest_execute_16 .................***Failed 1.14 sec
2/12 Test #6: ctest_execute_36 ................. Passed 1.27 sec
3/12 Test #7: ctest_execute_49 ................. Passed 1.32 sec
4/12 Test #8: ctest_execute_64 ................. Passed 1.32 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
Start 12: ctest_execute_144
5/12 Test #1: ctest_execute_1 .................. Passed 1.33 sec
6/12 Test #2: ctest_execute_4 .................. Passed 1.33 sec
7/12 Test #3: ctest_execute_9 .................. Passed 1.33 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.33 sec
9/12 Test #10: ctest_execute_100 ................ Passed 0.54 sec
10/12 Test #11: ctest_execute_121 ................ Passed 0.55 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.55 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.55 sec
92% tests passed, 1 tests failed out of 12
Total Test time (real) = 1.88 sec
The following tests FAILED:
4 - ctest_execute_16 (Failed)
第二 运行:
Start 1: ctest_execute_1
Start 2: ctest_execute_4
Start 3: ctest_execute_9
Start 4: ctest_execute_16
Start 5: ctest_execute_25
Start 6: ctest_execute_36
Start 7: ctest_execute_49
Start 8: ctest_execute_64
1/12 Test #6: ctest_execute_36 ................. Passed 1.31 sec
2/12 Test #7: ctest_execute_49 ................. Passed 1.36 sec
3/12 Test #8: ctest_execute_64 ................. Passed 1.36 sec
Start 9: ctest_execute_81
Start 10: ctest_execute_100
Start 11: ctest_execute_121
4/12 Test #1: ctest_execute_1 .................. Passed 1.37 sec
5/12 Test #2: ctest_execute_4 .................. Passed 1.37 sec
6/12 Test #3: ctest_execute_9 .................. Passed 1.36 sec
7/12 Test #4: ctest_execute_16 ................. Passed 1.36 sec
8/12 Test #5: ctest_execute_25 ................. Passed 1.37 sec
Start 12: ctest_execute_144
9/12 Test #11: ctest_execute_121 ................ Passed 0.50 sec
10/12 Test #10: ctest_execute_100 ................ Passed 0.51 sec
11/12 Test #9: ctest_execute_81 ................. Passed 0.51 sec
12/12 Test #12: ctest_execute_144 ................ Passed 0.34 sec
100% tests passed, 0 tests failed out of 12
Total Test time (real) = 2.01 sec
您的测试正在执行
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ...
在项目的构建目录中有效 运行s make
(或您使用的任何构建工具)。
但是在同一目录中 make
的并发调用永远不能保证正常工作。这就是为什么 运行 并行测试(设置了 CTEST_PARALLEL_LEVEL
变量)时出现奇怪错误的原因。
例如所有这些测试都试图创建相同的目标文件 mysqrt.o
,而这个创建绝对不是 thread-safe.
来自 运行宁
make sqrtlib
之前
ctest
您可以确定当测试 运行 时目标文件已经创建,并且测试不会尝试再次创建它。 但是你仍然可以在并行测试中遇到其他冲突。
这取决于你实际想通过测试检查什么,但通常 test 检查某些程序或库的 behavior,并且它不打算检查该程序的编译(构建)。因此,编译(构建)命令在 在 测试之前执行。
通常遵循(实施)此工作流程进行测试很方便:
# Configure the project
cmake <source-directory>
# Build the project.
# It builds both program/library intended, and the tests themselves.
make
# run tests
ctest <params>
在那种情况下,测试可以具有以下定义:
add_test(NAME ctest_execute_${input} COMMAND ${exe_generator})
(除非您想通过某种自动方式检查测试的输出,否则无需通过重定向到文件中来明确保存此输出。ctest
本身会收集测试的输出,因此您如果需要可以阅读它)。