Skip to content

Commit b31f6e6

Browse files
committed
First pass at coverage automation
1 parent 8edc5ea commit b31f6e6

4 files changed

Lines changed: 166 additions & 2 deletions

File tree

.coveragerc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
3+
4+
[report]
5+
show_missing = true
6+
7+
[run]
8+
plugins = Cython.Coverage

.github/workflows/coverage.yml

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
name: "CI: Coverage"
6+
7+
on:
8+
schedule:
9+
- cron: '0 0 * * *' # This runs the workflow every day at 12:00 AM UTC
10+
workflow_dispatch: {}
11+
12+
defaults:
13+
run:
14+
shell: bash --noprofile --norc -xeuo pipefail {0}
15+
16+
env:
17+
PY_VER: "3.14"
18+
CUDA_VER: "13.0.2"
19+
LOCAL_CTK: "1"
20+
GPU: "a100"
21+
DRIVER: "latest"
22+
ARCH: "x86_64"
23+
24+
jobs:
25+
coverage:
26+
name: Coverage - py${{ vars.PY_VER }}, ${{ vars.CUDA_VER }}, ${{ (vars.LOCAL_CTK == '1' && 'local') || 'wheels' }}, ${{ vars.GPU }}
27+
runs-on: "linux-${{ vars.ARCH }}-gpu-${{ vars.GPU }}-${{ vars.DRIVER }}-1"
28+
# Our self-hosted runners require a container
29+
# TODO: use a different (nvidia?) container
30+
container:
31+
options: -u root --security-opt seccomp=unconfined --shm-size 16g
32+
image: ubuntu:22.04
33+
env:
34+
NVIDIA_VISIBLE_DEVICES: ${{ vars.NVIDIA_VISIBLE_DEVICES }}
35+
steps:
36+
- name: Ensure GPU is working
37+
run: nvidia-smi
38+
39+
- name: Checkout ${{ github.event.repository.name }}
40+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
41+
42+
- name: Setup proxy cache
43+
uses: nv-gha-runners/setup-proxy-cache@main
44+
continue-on-error: true
45+
46+
- name: Install dependencies
47+
uses: ./.github/actions/install_unix_deps
48+
continue-on-error: false
49+
with:
50+
# for artifact fetching, graphics libs
51+
dependencies: "jq wget libgl1 libegl1"
52+
dependent_exes: "jq wget"
53+
54+
- name: Set environment variables
55+
env:
56+
BUILD_CUDA_VER: ${{ vars.CUDA_VER }}
57+
CUDA_VER: ${{ vars.CUDA_VER }}
58+
HOST_PLATFORM: linux-64
59+
LOCAL_CTK: ${{ vars.LOCAL_CTK }}
60+
PY_VER: ${{ vars.PY_VER }}
61+
SHA: ${{ github.sha }}
62+
run: |
63+
./ci/tools/env-vars test
64+
echo "CUDA_PYTHON_COVERAGE=1" >> $GITHUB_ENV
65+
66+
- name: Set up Python ${{ vars.PY_VER }}
67+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
68+
with:
69+
python-version: ${{ vars.PY_VER }}
70+
env:
71+
# we use self-hosted runners on which setup-python behaves weirdly...
72+
AGENT_TOOLSDIRECTORY: "/opt/hostedtoolcache"
73+
74+
- name: Set up mini CTK
75+
if: ${{ vars.LOCAL_CTK == '1' }}
76+
uses: ./.github/actions/fetch_ctk
77+
continue-on-error: false
78+
with:
79+
host-platform: ${{ vars.HOST_PLATFORM }}
80+
cuda-version: ${{ vars.CUDA_VER }}
81+
82+
- name: Build cuda-pathfinder
83+
run:
84+
pip install -v ./cuda_pathfinder
85+
86+
- name: Build cuda-python-test-helpers
87+
run:
88+
pip install -v ./cuda_python_test_helpers
89+
90+
- name: Build cuda-bindings
91+
run:
92+
cd cuda_bindings
93+
pip install -v . --group test
94+
95+
- name: Build cuda-core
96+
run:
97+
cd cuda_core
98+
pip install -v . --group test
99+
100+
- name: Install coverage tools
101+
run: |
102+
pip install coverage pytest-cov
103+
104+
- name: Set cuda package install root
105+
run: |
106+
echo "CUDA_PYTHON_ROOT=$(python -c 'import cuda; print(cuda.__path__[0])')" >> $GITHUB_ENV
107+
108+
- name: Run cuda.pathfinder tests
109+
run:
110+
pytest -v --cov=$CUDA_PYTHON_ROOT --cov-append --cov-config=.coveragerc cuda_pathfinder/tests
111+
112+
- name: Run cuda.bindings tests
113+
run:
114+
pytest -v --cov=$CUDA_PYTHON_ROOT --cov-append --cov-config=.coveragerc cuda_bindings/tests
115+
116+
- name: Run cuda.core tests
117+
run:
118+
pytest -v --cov=$CUDA_PYTHON_ROOT --cov-append --cov-config=.coveragerc cuda_core/tests
119+
120+
- name: Generate coverage report
121+
run: |
122+
coverage html
123+
coverage xml -o htmlcov/coverage.xml
124+
125+
- name: Deploy to gh-pages
126+
uses: JamesIves/github-pages-deploy-action@4a3abc783e1a24aeb44c16e869ad83caf6b4cc23 # v4.7.4
127+
with:
128+
git-config-name: cuda-python-bot
129+
git-config-email: cuda-python-bot@users.noreply.github.com
130+
folder: htmlcov/
131+
target-folder: docs/coverage/
132+
commit-message: "Deploy coverage: ${{ vars.COMMIT_HASH }}"
133+
clean: false

cuda_bindings/setup.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
PARSER_CACHING = os.environ.get("CUDA_PYTHON_PARSER_CACHING", False)
4545
PARSER_CACHING = bool(PARSER_CACHING)
4646

47+
COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
48+
4749
# ----------------------------------------------------------------------
4850
# Parse user-provided CUDA headers
4951

@@ -276,6 +278,10 @@ def generate_output(infile, local):
276278
# extra_compile_args += ["-D _LIBCPP_ENABLE_ASSERTIONS"] # Consider: if clang, use libc++ preprocessor macros.
277279
else:
278280
extra_compile_args += ["-O3"]
281+
if COMPILE_FOR_COVERAGE:
282+
# CYTHON_TRACE_NOGIL indicates to trace nogil functions. It is not
283+
# related to free-threading builds.
284+
extra_compile_args += ["-DCYTHON_TRACE_NOGIL=1", "-DCYTHON_USE_SYS_MONITORING=0"]
279285

280286
# For Setup
281287
extensions = []
@@ -342,10 +348,15 @@ def cleanup_dst_files():
342348

343349

344350
def do_cythonize(extensions):
351+
compiler_directives = dict(language_level=3, embedsignature=True, binding=True, freethreading_compatible=True)
352+
353+
if COMPILE_FOR_COVERAGE:
354+
compiler_directives["linetrace"] = True
355+
345356
return cythonize(
346357
extensions,
347358
nthreads=nthreads,
348-
compiler_directives=dict(language_level=3, embedsignature=True, binding=True, freethreading_compatible=True),
359+
compiler_directives=compiler_directives,
349360
**extra_cythonize_kwargs,
350361
)
351362

cuda_core/build_hooks.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
build_sdist = _build_meta.build_sdist
2323
get_requires_for_build_sdist = _build_meta.get_requires_for_build_sdist
2424

25+
COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
26+
2527

2628
@functools.cache
2729
def _get_proper_cuda_bindings_major_version() -> str:
@@ -84,24 +86,34 @@ def get_cuda_paths():
8486
print("CUDA paths:", CUDA_PATH)
8587
return CUDA_PATH
8688

89+
extra_compile_args = []
90+
if COMPILE_FOR_COVERAGE:
91+
# CYTHON_TRACE_NOGIL indicates to trace nogil functions. It is not
92+
# related to free-threading builds.
93+
extra_compile_args += ["-DCYTHON_TRACE_NOGIL=1", "-DCYTHON_USE_SYS_MONITORING=0"]
94+
8795
ext_modules = tuple(
8896
Extension(
8997
f"cuda.core.experimental.{mod.replace(os.path.sep, '.')}",
9098
sources=[f"cuda/core/experimental/{mod}.pyx"],
9199
include_dirs=list(os.path.join(root, "include") for root in get_cuda_paths()),
92100
language="c++",
101+
extra_compile_args=extra_compile_args,
93102
)
94103
for mod in module_names
95104
)
96105

97106
nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))
98107
compile_time_env = {"CUDA_CORE_BUILD_MAJOR": _get_proper_cuda_bindings_major_version()}
108+
compiler_directives = {"embedsignature": True, "warn.deprecated.IF": False, "freethreading_compatible": True}
109+
if COMPILE_FOR_COVERAGE:
110+
compiler_directives["linetrace"] = True
99111
_extensions = cythonize(
100112
ext_modules,
101113
verbose=True,
102114
language_level=3,
103115
nthreads=nthreads,
104-
compiler_directives={"embedsignature": True, "warn.deprecated.IF": False, "freethreading_compatible": True},
116+
compiler_directives=compiler_directives,
105117
compile_time_env=compile_time_env,
106118
)
107119

0 commit comments

Comments
 (0)