더 큰 CTEST_PARALLEL_LEVEL에 대한 cmake ctest의 이상한 동작
나는 SO에 처음입니다. 다음 작업을 수행하는 간단한 단위 테스트 코드가 있습니다.
mysqrt
library를 사용하여 숫자의 제곱근을 계산 합니다.- 제곱근의 출력을 사용하여이 결과를 같은 수로 더하고 결과를 표시합니다.
CTEST_PARALLEL_LEVEL = 1
내 모든 테스트 케이스가 통과 하는 코드를 실행할 때 .
그러나 내가 할 CTEST_PARALLEL_LEVEL = 8
때 내 테스트 케이스는 모든 실행에서 수정되지 않는 일부 입력에 대해 얼마 동안 실패합니다.
99 % ALL 결과는 통과했지만 1 %는 실패했습니다.
오류:
mysqrt.o: file not recognized: File truncated
rm * .o를 사용하여 명시 적으로 개체 파일을 삭제했지만 몇 번 실행 한 후에도 여전히이 오류가 발생합니다.
이 오류가 왜 발생하는지 잘 모르겠습니다. CTEST_PARALLEL_LEVEL = 8
CMakeList
Stack Overflow 전문가 중 일부가이 3 개의 CMakeLists.txt
파일 을 확인하여 문제를 이해할 수 있기 때문에 저의 유일한 파일을 첨부하고 있습니다.
참고 : 스택 오버플로 지침 에 따라 질문의 더 큰 길이를 피하기 위해 sqrt 및 추가 기능 의 소스 코드를 첨부하지 않습니다 .
내 폴더 구조 :
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)
결과 : 1 차 실행 :
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)
2 차 실행 :
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 ...
make
프로젝트의 빌드 디렉토리에서 효과적으로 실행됩니다 (또는 사용하는 빌드 도구).
그러나 동일한 디렉토리에서의 동시 호출 이 make
올바르게 작동한다는 보장은 없습니다. 이것이 CTEST_PARALLEL_LEVEL
변수가 설정된 상태 에서 병렬로 테스트를 실행할 때 이상한 오류가 발생하는 이유 입니다.
예를 들어 이러한 모든 테스트는 동일한 객체 파일을 생성하려고 시도 mysqrt.o
하며이 생성은 확실히 스레드로부터 안전 하지 않습니다 .
달리기
make sqrtlib
전에
ctest
테스트가 실행될 때 개체 파일이 이미 생성되어 있는지 확인하고 테스트에서 다시 생성을 시도하지 않을 것입니다. 그러나 병렬 테스트에서 여전히 다른 충돌이 발생할 수 있습니다.
테스트에서 실제로 확인하려는 내용에 따라 다르지만 일반적으로 테스트 는 일부 프로그램 또는 라이브러리의 동작 을 확인하며 해당 프로그램의 컴파일 (빌딩)을 확인하지 않습니다. 따라서 테스트 전에 컴파일 (빌딩) 명령이 수행 됩니다.
일반적으로 테스트를 위해 다음 워크 플로를 따르는 것이 편리합니다 (구현).
# 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
자체적으로 테스트의 출력을 수집하므로 필요한 경우 읽을 수 있습니다).