diff --git a/.gitmodules b/.gitmodules index 470cf466..d33d0a64 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "third_party/eigen"] path = third_party/eigen url = git@github.com:InfiniTensor/eigen-mirror.git +[submodule "third_party/googletest"] + path = third_party/googletest + url = git@github.com:google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea3529c..7cc7ea84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ option(USE_CUDA "Support NVIDIA CUDA" OFF) option(PROFILE_MODE "ENABLE PROFILE MODE" OFF) option(USE_OMP "Use OpenMP as backend for Eigen" ON) option(USE_NCCL "Build project for distributed running" ON) +option(BUILD_TEST "Build InfiniTrain tests" OFF) project(infini_train VERSION 0.5.0 LANGUAGES CXX) @@ -14,6 +15,19 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Generate compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# ------------------------------------------------------------------------------ +# GoogleTest (submodule) +# ------------------------------------------------------------------------------ +if(BUILD_TEST) + if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/googletest/CMakeLists.txt) + message(FATAL_ERROR "googletest submodule not found at third_party/googletest. " + "Run: git submodule update --init third_party/googletest") + endif() + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + add_subdirectory(third_party/googletest) + enable_testing() +endif() + # ------------------------------------------------------------------------------ # Third-party deps # ------------------------------------------------------------------------------ @@ -48,6 +62,10 @@ endif() # Framework core sources (*.cc), excluding cpu kernels (they are built separately) file(GLOB_RECURSE SRC ${PROJECT_SOURCE_DIR}/infini_train/src/*.cc) list(FILTER SRC EXCLUDE REGEX ".*kernels/cpu/.*") +if(NOT USE_CUDA) + list(FILTER SRC EXCLUDE REGEX ".*runtime/cuda/.*") + list(FILTER SRC EXCLUDE REGEX ".*ccl/cuda/.*") +endif() if(NOT USE_NCCL) list(FILTER SRC EXCLUDE REGEX ".*infini_train/src/core/ccl/cuda/.*") endif() @@ -195,34 +213,6 @@ add_subdirectory(tools/infini_run) set_target_properties(infini_run PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) # Tests -add_executable(test_hook test/hook/test_hook.cc) -link_infini_train_exe(test_hook) - -add_executable(test_precision_check test/hook/test_precision_check.cc) -link_infini_train_exe(test_precision_check) - -add_executable(test_lora test/lora/test_lora.cc) -link_infini_train_exe(test_lora) - -add_executable(test_transformer_architecture test/transformer/test_transformer_architecture.cc) -link_infini_train_exe(test_transformer_architecture) - -add_executable(test_scalar test/dtype/test_scalar.cc) -link_infini_train_exe(test_scalar) - -add_executable(test_dtype_dispatch test/dtype/test_dtype_dispatch.cc) -link_infini_train_exe(test_dtype_dispatch) - -# Negative compile test: missing dtype registration must fail at compile time. -set(DTYPE_DISPATCH_COMPILE_FAIL_SOURCE - ${PROJECT_SOURCE_DIR}/test/dtype/test_dtype_dispatch_compile_fail.cc) - -add_executable(test_dtype_dispatch_compile_fail EXCLUDE_FROM_ALL - ${DTYPE_DISPATCH_COMPILE_FAIL_SOURCE} -) - -target_include_directories(test_dtype_dispatch_compile_fail PRIVATE - ${PROJECT_SOURCE_DIR} -) - -link_infini_train_exe(test_dtype_dispatch_compile_fail) +if(BUILD_TEST) + add_subdirectory(tests) +endif() diff --git a/cmake/test_macros.cmake b/cmake/test_macros.cmake new file mode 100644 index 00000000..500103b9 --- /dev/null +++ b/cmake/test_macros.cmake @@ -0,0 +1,128 @@ +# ============================================================================ +# InfiniTrain Test Macros +# ============================================================================ +# Unified test configuration interface to reduce boilerplate. +# +# Usage: +# 1. Include this file in tests/CMakeLists.txt +# 2. Use infini_train_add_test macro to register tests +# +# Examples: +# infini_train_add_test( +# test_tensor_create +# SOURCES test_tensor_create.cc +# LABELS cpu cuda +# ) +# ============================================================================ + +include_guard(GLOBAL) + +# ----------------------------------------------------------------------------- +# Load GoogleTest module (provides gtest_discover_tests) +# ----------------------------------------------------------------------------- +include(GoogleTest) + +# ----------------------------------------------------------------------------- +# infini_train_add_test - Test registration macro +# ----------------------------------------------------------------------------- +# Features: +# 1. Create executable target +# 2. Configure compile options, link libraries, and include paths +# 3. Use gtest_discover_tests to auto-discover test cases +# 4. Set test labels +# +# Arguments: +# SOURCES: Source file list (required) +# LABELS: Test labels, e.g. "cpu" "cuda" "distributed" (optional, default "cpu") +# TEST_FILTER: gtest test filter pattern (optional) +# +# Examples: +# # Single-label test (one liner) +# infini_train_add_test(test_example SOURCES test_example.cc LABELS cpu) +# +# # Filter same binary by label suffix (one call per label) +# infini_train_add_test(test_example SOURCES test_example.cc LABELS cpu TEST_FILTER "-*CUDA*") +# infini_train_add_test(test_example_cuda SOURCES test_example.cc LABELS cuda TEST_FILTER "*CUDA*") +# ----------------------------------------------------------------------------- +macro(infini_train_add_test) + cmake_parse_arguments(ARG "" "TEST_NAME;TEST_FILTER" "SOURCES;LABELS" ${ARGN}) + + if(NOT ARG_TEST_NAME) + set(ARG_TEST_NAME ${ARG_UNPARSED_ARGUMENTS}) + endif() + + if(NOT ARG_SOURCES) + message(FATAL_ERROR "infini_train_add_test: TEST_NAME and SOURCES are required") + endif() + + # 1. Create executable target + add_executable(${ARG_TEST_NAME} ${ARG_SOURCES} $) + + # 2. Disable -Werror so tests can run under relaxed warning levels + target_compile_options(${ARG_TEST_NAME} PRIVATE -Wno-error) + + # 3. Link Google Test (uses custom main from test_main that initializes GlobalEnv) + target_link_libraries(${ARG_TEST_NAME} PRIVATE GTest::gtest) + + # 4. Add include paths + target_include_directories(${ARG_TEST_NAME} PRIVATE + ${glog_SOURCE_DIR}/src + ) + + # 5. Link project library (reuses framework linking strategy) + link_infini_train_exe(${ARG_TEST_NAME}) + + # 6. Auto-discover gtest cases and register as ctest tests + set(labels "cpu") + if(ARG_LABELS) + set(labels "${ARG_LABELS}") + endif() + + if(ARG_TEST_FILTER) + gtest_discover_tests(${ARG_TEST_NAME} + EXTRA_ARGS --gtest_output=xml:%T.xml + TEST_FILTER "${ARG_TEST_FILTER}" + DISCOVERY_TIMEOUT 10 + PROPERTIES LABELS "${labels}" TIMEOUT 10 + ) + else() + gtest_discover_tests(${ARG_TEST_NAME} + EXTRA_ARGS --gtest_output=xml:%T.xml + PROPERTIES LABELS "${labels}" TIMEOUT 10 + ) + endif() +endmacro() + +# ----------------------------------------------------------------------------- +# infini_train_add_test_suite - Register cpu/cuda/distributed targets in one call +# ----------------------------------------------------------------------------- +# Calls infini_train_add_test three times (or fewer) with the correct +# TEST_FILTER and LABELS derived from the label list. +# +# Arguments: +# Base name; each target is named _