Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ jobs:
PY

# ---------------------------------------------------------------------- #
# (c) CPU-only tests: the CPU subset of the suite. GPU, network, and
# undeclared-dep tests are ignored (see BASELINE). The two known
# np.unicode_ test-only failures are deselected until restructure-tests
# (PR D) fixes the NumPy-2 alias.
# TODO(PR D): once pytest markers land, replace the --ignore/--deselect
# list with `-m "not gpu and not slow and not network"`.
# (c) CPU-only tests: the CPU subset of the suite, selected by pytest
# markers (`-m "not gpu and not slow and not network"`). GPU tests are
# additionally skipped at collection when cupy/ccc_cuda_ext are absent
# (tests/gpu/conftest.py). The research-only modules import undeclared
# heavy deps (requests/minepy/IPython) and are excluded from the wheel,
# so they are still `--ignore`d here (owned by improve-docs / PR E).
# ---------------------------------------------------------------------- #
test-cpu:
name: CPU tests
Expand Down Expand Up @@ -141,11 +141,9 @@ jobs:
PATH: /opt/conda/bin:/usr/local/cuda/bin:/usr/bin:/bin
run: |
python -m pytest tests/ \
--ignore=tests/gpu \
--ignore=tests/test_giant.py \
--ignore=tests/test_methods.py \
--ignore=tests/test_plots.py \
--ignore=tests/test_corr.py \
--deselect "tests/test_coef_pval.py::test_cm_numerical_and_categorical_features_perfect_relationship_pvalue" \
--deselect "tests/test_coef_pval.py::test_cm_numerical_and_categorical_features_weakly_relationship_pvalue" \
-m "not gpu and not slow and not network" \
-q -ra -p no:cacheprovider -o addopts=""
128 changes: 73 additions & 55 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.15...3.26)
project(${SKBUILD_PROJECT_NAME} LANGUAGES CUDA CXX)

# When ON, build the CUDA C++ gtests under tests/cuda_ext/ and register them with
# ctest. OFF by default so the wheel build never fetches googletest or compiles
# the native tests. Enable with: cmake -S . -B build -DCCC_BUILD_TESTS=ON
option(CCC_BUILD_TESTS "Build the CUDA C++ gtests and register them with ctest" OFF)

# Export compile_commands.json so clang-tidy (and editors/LSP) can analyze the
# CUDA/C++ sources. Run clang-tidy host-only, e.g.:
# clang-tidy -p build --extra-arg=--cuda-host-only libs/ccc_cuda_ext/*.cu
Expand Down Expand Up @@ -42,14 +47,10 @@ find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
find_package(pybind11 CONFIG REQUIRED)
set(PYBIND11_NEWPYTHON ON)

# Download and configure Google Test
# Google Test is fetched only when building the native tests (CCC_BUILD_TESTS);
# the default wheel build must not touch the network for gtest. See the guarded
# test block near the end of this file.
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.15.2 # Adjust version as needed
)
FetchContent_MakeAvailable(googletest)
# Download and configure spdlog
FetchContent_Declare(
spdlog
Expand All @@ -62,54 +63,6 @@ FetchContent_MakeAvailable(spdlog)

# include_directories("${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}")

# Setup Gtest
enable_testing()
# Function to automatically add tests from a directory
function(add_tests_from_directory TEST_DIR)
# Find all test files in the directory
file(GLOB_RECURSE TEST_FILES
"${TEST_DIR}/*_test.cu" # Files ending with _test.cu
"${TEST_DIR}/test_*.cu" # Files starting with test_
)

# Loop through each test file
foreach(TEST_FILE ${TEST_FILES})
# Get the filename without extension
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)

# Create an executable for this test
add_executable(${TEST_NAME} ${TEST_FILE} ${headers} ${sources})

# target_include_directories(${TEST_NAME} PRIVATE
# ${PROJECT_INCLUDE_DIR} # Add this line
# ${Python_INCLUDE_DIRS}
# )

target_link_libraries(${TEST_NAME} PRIVATE
GTest::gtest_main
GTest::gtest
pybind11::headers
pybind11::embed
Python::Python
# Add your other project libraries here
# project_lib
)

# Add the test to CTest
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})

# Set test properties (optional)
# Set test properties (optional)
set_tests_properties(${TEST_NAME} PROPERTIES
TIMEOUT 10 # Timeout in seconds
WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)
endforeach()
endfunction()

# Specify your test directory and call the function
# add_tests_from_directory(${CMAKE_CURRENT_SOURCE_DIR}/tests)

# Optional: Set output directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
Expand All @@ -127,3 +80,68 @@ target_link_libraries(${CUDA_EXT_MODULE_NAME} PRIVATE
)

install(TARGETS ${CUDA_EXT_MODULE_NAME} LIBRARY DESTINATION .)

# --------------------------------------------------------------------------- #
# CUDA C++ gtests (opt-in). Guarded by CCC_BUILD_TESTS so the wheel build never
# fetches googletest or compiles the native tests.
# cmake -S . -B build -DCCC_BUILD_TESTS=ON && cmake --build build && ctest --test-dir build
# --------------------------------------------------------------------------- #
if(CCC_BUILD_TESTS)
message(STATUS "CCC_BUILD_TESTS=ON: configuring CUDA C++ gtests")

# Embedding a Python interpreter (test_ari_random.cu) needs Development.Embed,
# which the default wheel build (Development.Module only) does not require.
find_package(Python REQUIRED COMPONENTS Interpreter Development.Embed Development.Module)

FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.15.2
)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
enable_testing()

# The gtests exercise the ARI kernels in metrics.cu. Compile that translation
# unit once into a static library and link it into each test executable so we
# do not recompile the (slow) .cu file per test. coef.cu / binder.cu are not
# needed by the current tests and are intentionally excluded.
add_library(ccc_cuda_ext_testlib STATIC ${CUDA_EXT_DIR}/metrics.cu)
target_link_libraries(ccc_cuda_ext_testlib PUBLIC
spdlog::spdlog
pybind11::headers
Python::Python
)
set_target_properties(ccc_cuda_ext_testlib PROPERTIES
POSITION_INDEPENDENT_CODE ON
)

# Discover the gtest source files. test_ari_py.cu is a legacy manual driver
# with its own main() (not a gtest); it would clash with gtest_main, so skip it.
file(GLOB CCC_TEST_FILES "${CMAKE_CURRENT_SOURCE_DIR}/tests/cuda_ext/test_*.cu")
foreach(TEST_FILE ${CCC_TEST_FILES})
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
if(TEST_NAME STREQUAL "test_ari_py")
continue()
endif()

add_executable(${TEST_NAME} ${TEST_FILE})
target_link_libraries(${TEST_NAME} PRIVATE
ccc_cuda_ext_testlib
GTest::gtest_main
GTest::gtest
pybind11::headers
pybind11::embed
Python::Python
)

# gtest_discover_tests registers each TEST_P case with ctest. The default
# 10s ctest timeout was too tight for the Python-reference tests; raise it.
gtest_discover_tests(${TEST_NAME}
PROPERTIES
TIMEOUT 300
WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
DISCOVERY_TIMEOUT 120
)
endforeach()
endif()
8 changes: 8 additions & 0 deletions libs/ccc/bench/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Standalone benchmark CLI for CCC (``ccc-gpu-bench`` / ``python -m ccc.bench``).

Reproducible, structured GPU-vs-CPU performance measurement decoupled from the
test suite: end-to-end coefficient benchmarks, ARI-kernel micro-benchmarks and
CPU parallelism scaling, emitted as JSON Lines / CSV with full environment
metadata. Runs degrade gracefully on machines without a GPU (CPU-side modes work;
GPU modes fail fast with a clear message). See ``ccc-gpu-bench --help``.
"""
8 changes: 8 additions & 0 deletions libs/ccc/bench/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Enable ``python -m ccc.bench``."""

import sys

from .cli import main

if __name__ == "__main__":
sys.exit(main())
Loading
Loading