Skip to content

Commit dc02705

Browse files
authored
Merge branch 'main' into add-abi-checking-tool
2 parents 720f890 + 82ca962 commit dc02705

File tree

19 files changed

+690
-423
lines changed

19 files changed

+690
-423
lines changed

.github/workflows/build-wheel.yml

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,24 @@ jobs:
4444
with:
4545
fetch-depth: 0
4646

47-
# The env vars ACTIONS_CACHE_SERVICE_V2, ACTIONS_RESULTS_URL, and ACTIONS_RUNTIME_TOKEN
48-
# are exposed by this action.
49-
- name: Enable sccache
50-
uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # 0.0.9
51-
with:
52-
disable_annotations: 'true'
47+
- name: Install latest rapidsai/sccache
48+
if: ${{ startsWith(inputs.host-platform, 'linux') }}
49+
run: |
50+
curl -fsSL "https://github.com/rapidsai/sccache/releases/latest/download/sccache-$(uname -m)-unknown-linux-musl.tar.gz" \
51+
| sudo tar -C /usr/local/bin -xvzf - --wildcards --strip-components=1 -x '*/sccache'
52+
echo "SCCACHE_PATH=/usr/local/bin/sccache" >> "$GITHUB_ENV"
53+
echo "SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE=true" >> "$GITHUB_ENV"
5354
5455
# xref: https://github.com/orgs/community/discussions/42856#discussioncomment-7678867
5556
- name: Adding addtional GHA cache-related env vars
5657
uses: actions/github-script@v8
5758
with:
5859
script: |
59-
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'])
60-
core.exportVariable('ACTIONS_RUNTIME_URL', process.env['ACTIONS_RUNTIME_URL'])
60+
core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on');
61+
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'] || '');
62+
core.exportVariable('ACTIONS_RESULTS_URL', process.env['ACTIONS_RESULTS_URL'] || '');
63+
core.exportVariable('ACTIONS_RUNTIME_URL', process.env['ACTIONS_RUNTIME_URL'] || '');
64+
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN'] || '');
6165
6266
- name: Setup proxy cache
6367
uses: nv-gha-runners/setup-proxy-cache@main
@@ -176,14 +180,15 @@ jobs:
176180
ACTIONS_RESULTS_URL=${{ env.ACTIONS_RESULTS_URL }}
177181
ACTIONS_CACHE_URL=${{ env.ACTIONS_CACHE_URL }}
178182
ACTIONS_CACHE_SERVICE_V2=${{ env.ACTIONS_CACHE_SERVICE_V2 }}
183+
SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE=${{ env.SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE }}
179184
SCCACHE_DIR=/host/${{ env.SCCACHE_DIR }}
180185
SCCACHE_CACHE_SIZE=${{ env.SCCACHE_CACHE_SIZE }}
181186
CIBW_ENVIRONMENT_WINDOWS: >
182187
CUDA_PATH="$(cygpath -w ${{ env.CUDA_PATH }})"
183188
CUDA_PYTHON_PARALLEL_LEVEL=${{ env.CUDA_PYTHON_PARALLEL_LEVEL }}
184189
# check cache stats before leaving cibuildwheel
185190
CIBW_BEFORE_TEST_LINUX: >
186-
"/host/${{ env.SCCACHE_PATH }}" --show-stats &&
191+
"/host/${{ env.SCCACHE_PATH }}" --show-adv-stats &&
187192
"/host/${{ env.SCCACHE_PATH }}" --show-stats --stats-format=json > /host/${{ github.workspace }}/sccache_bindings.json
188193
# force the test stage to be run (so that before-test is not skipped)
189194
# TODO: we might want to think twice on adding this, it does a lot of
@@ -241,6 +246,7 @@ jobs:
241246
ACTIONS_RESULTS_URL=${{ env.ACTIONS_RESULTS_URL }}
242247
ACTIONS_CACHE_URL=${{ env.ACTIONS_CACHE_URL }}
243248
ACTIONS_CACHE_SERVICE_V2=${{ env.ACTIONS_CACHE_SERVICE_V2 }}
249+
SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE=${{ env.SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE }}
244250
SCCACHE_DIR=/host/${{ env.SCCACHE_DIR }}
245251
SCCACHE_CACHE_SIZE=${{ env.SCCACHE_CACHE_SIZE }}
246252
CIBW_ENVIRONMENT_WINDOWS: >
@@ -250,7 +256,7 @@ jobs:
250256
PIP_FIND_LINKS="$(cygpath -w ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }})"
251257
# check cache stats before leaving cibuildwheel
252258
CIBW_BEFORE_TEST_LINUX: >
253-
"/host${{ env.SCCACHE_PATH }}" --show-stats &&
259+
"/host${{ env.SCCACHE_PATH }}" --show-adv-stats &&
254260
"/host${{ env.SCCACHE_PATH }}" --show-stats --stats-format=json > /host/${{ github.workspace }}/sccache_core.json
255261
# force the test stage to be run (so that before-test is not skipped)
256262
# TODO: we might want to think twice on adding this, it does a lot of
@@ -429,6 +435,7 @@ jobs:
429435
ACTIONS_RESULTS_URL=${{ env.ACTIONS_RESULTS_URL }}
430436
ACTIONS_CACHE_URL=${{ env.ACTIONS_CACHE_URL }}
431437
ACTIONS_CACHE_SERVICE_V2=${{ env.ACTIONS_CACHE_SERVICE_V2 }}
438+
SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE=${{ env.SCCACHE_GHA_USE_PREPROCESSOR_CACHE_MODE }}
432439
SCCACHE_DIR=/host/${{ env.SCCACHE_DIR }}
433440
SCCACHE_CACHE_SIZE=${{ env.SCCACHE_CACHE_SIZE }}
434441
CIBW_ENVIRONMENT_WINDOWS: >
@@ -438,7 +445,7 @@ jobs:
438445
PIP_FIND_LINKS="$(cygpath -w ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }})"
439446
# check cache stats before leaving cibuildwheel
440447
CIBW_BEFORE_TEST_LINUX: >
441-
"/host${{ env.SCCACHE_PATH }}" --show-stats &&
448+
"/host${{ env.SCCACHE_PATH }}" --show-adv-stats &&
442449
"/host${{ env.SCCACHE_PATH }}" --show-stats --stats-format=json > /host/${{ github.workspace }}/sccache_core_prev.json
443450
# force the test stage to be run (so that before-test is not skipped)
444451
# TODO: we might want to think twice on adding this, it does a lot of

.github/workflows/ci.yml

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,151 @@ jobs:
7171
echo "skip=${skip}" >> "$GITHUB_OUTPUT"
7272
echo "doc_only=${doc_only}" >> "$GITHUB_OUTPUT"
7373
74+
# Detect which top-level modules were touched by the PR so downstream build
75+
# and test jobs can avoid rebuilding/retesting modules unaffected by the
76+
# change. See issue #299.
77+
#
78+
# Dependency graph (verified in pyproject.toml files):
79+
# cuda_pathfinder -> (no internal deps)
80+
# cuda_bindings -> cuda_pathfinder
81+
# cuda_core -> cuda_pathfinder, cuda_bindings
82+
# cuda_python -> cuda_bindings (meta package)
83+
#
84+
# A change to cuda_pathfinder (or shared infra) forces a rebuild of every
85+
# downstream module. A change to cuda_bindings forces rebuild of cuda_core.
86+
# A change to cuda_core alone skips rebuilding/retesting cuda_bindings.
87+
# On push to main, tag refs, schedule, or workflow_dispatch events we
88+
# unconditionally run everything because there is no meaningful "changed
89+
# paths" baseline for those events.
90+
detect-changes:
91+
runs-on: ubuntu-latest
92+
outputs:
93+
bindings: ${{ steps.compose.outputs.bindings }}
94+
core: ${{ steps.compose.outputs.core }}
95+
pathfinder: ${{ steps.compose.outputs.pathfinder }}
96+
python_meta: ${{ steps.compose.outputs.python_meta }}
97+
test_helpers: ${{ steps.compose.outputs.test_helpers }}
98+
shared: ${{ steps.compose.outputs.shared }}
99+
build_bindings: ${{ steps.compose.outputs.build_bindings }}
100+
build_core: ${{ steps.compose.outputs.build_core }}
101+
build_pathfinder: ${{ steps.compose.outputs.build_pathfinder }}
102+
test_bindings: ${{ steps.compose.outputs.test_bindings }}
103+
test_core: ${{ steps.compose.outputs.test_core }}
104+
test_pathfinder: ${{ steps.compose.outputs.test_pathfinder }}
105+
steps:
106+
- name: Checkout repository
107+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
108+
with:
109+
fetch-depth: 0
110+
111+
# copy-pr-bot pushes every PR (whether it targets main or a backport
112+
# branch such as 12.9.x) to pull-request/<N>, so the base branch
113+
# cannot be inferred from github.ref_name. Look it up via the
114+
# upstream PR metadata so the diff below is rooted at the right place.
115+
- name: Resolve PR base branch
116+
id: pr-info
117+
if: ${{ startsWith(github.ref_name, 'pull-request/') }}
118+
uses: nv-gha-runners/get-pr-info@main
119+
120+
- name: Detect changed paths
121+
id: filter
122+
if: ${{ startsWith(github.ref_name, 'pull-request/') }}
123+
env:
124+
BASE_REF: ${{ fromJSON(steps.pr-info.outputs.pr-info).base.ref }}
125+
run: |
126+
# Diff against the merge base with the PR's actual target branch.
127+
# Uses merge-base so diverged branches only show files changed on
128+
# the PR side, not upstream commits.
129+
if [[ -z "${BASE_REF}" ]]; then
130+
echo "Could not resolve PR base branch from get-pr-info output" >&2
131+
exit 1
132+
fi
133+
base=$(git merge-base HEAD "origin/${BASE_REF}")
134+
changed=$(git diff --name-only "$base"...HEAD)
135+
136+
has_match() {
137+
grep -qE "$1" <<< "$changed" && echo true || echo false
138+
}
139+
140+
{
141+
echo "bindings=$(has_match '^cuda_bindings/')"
142+
echo "core=$(has_match '^cuda_core/')"
143+
echo "pathfinder=$(has_match '^cuda_pathfinder/')"
144+
echo "python_meta=$(has_match '^cuda_python/')"
145+
echo "test_helpers=$(has_match '^cuda_python_test_helpers/')"
146+
echo "shared=$(has_match '^(\.github/|ci/|scripts/|toolshed/|conftest\.py$|pyproject\.toml$|pixi\.(toml|lock)$|pytest\.ini$|ruff\.toml$)')"
147+
} >> "$GITHUB_OUTPUT"
148+
149+
- name: Compose gating outputs
150+
id: compose
151+
env:
152+
IS_PR: ${{ startsWith(github.ref_name, 'pull-request/') }}
153+
BINDINGS: ${{ steps.filter.outputs.bindings || 'false' }}
154+
CORE: ${{ steps.filter.outputs.core || 'false' }}
155+
PATHFINDER: ${{ steps.filter.outputs.pathfinder || 'false' }}
156+
PYTHON_META: ${{ steps.filter.outputs.python_meta || 'false' }}
157+
TEST_HELPERS: ${{ steps.filter.outputs.test_helpers || 'false' }}
158+
SHARED: ${{ steps.filter.outputs.shared || 'false' }}
159+
run: |
160+
set -euxo pipefail
161+
# Non-PR events (push to main, tag push, schedule, workflow_dispatch)
162+
# always exercise the full pipeline because there is no baseline for
163+
# a meaningful diff.
164+
if [[ "${IS_PR}" != "true" ]]; then
165+
bindings=true
166+
core=true
167+
pathfinder=true
168+
python_meta=true
169+
test_helpers=true
170+
shared=true
171+
else
172+
bindings="${BINDINGS}"
173+
core="${CORE}"
174+
pathfinder="${PATHFINDER}"
175+
python_meta="${PYTHON_META}"
176+
test_helpers="${TEST_HELPERS}"
177+
shared="${SHARED}"
178+
fi
179+
180+
or_flag() {
181+
for v in "$@"; do
182+
if [[ "${v}" == "true" ]]; then
183+
echo "true"
184+
return
185+
fi
186+
done
187+
echo "false"
188+
}
189+
190+
# Build gating: pathfinder change forces rebuild of bindings and
191+
# core; bindings change forces rebuild of core. shared changes force
192+
# a full rebuild.
193+
build_pathfinder="$(or_flag "${shared}" "${pathfinder}")"
194+
build_bindings="$(or_flag "${shared}" "${pathfinder}" "${bindings}")"
195+
build_core="$(or_flag "${shared}" "${pathfinder}" "${bindings}" "${core}")"
196+
197+
# Test gating: tests for a module must run whenever that module, any
198+
# of its runtime dependencies, the shared test helper package, or
199+
# shared infra changes. pathfinder tests are cheap and always run.
200+
test_pathfinder=true
201+
test_bindings="$(or_flag "${shared}" "${pathfinder}" "${bindings}" "${test_helpers}")"
202+
test_core="$(or_flag "${shared}" "${pathfinder}" "${bindings}" "${core}" "${test_helpers}")"
203+
204+
{
205+
echo "bindings=${bindings}"
206+
echo "core=${core}"
207+
echo "pathfinder=${pathfinder}"
208+
echo "python_meta=${python_meta}"
209+
echo "test_helpers=${test_helpers}"
210+
echo "shared=${shared}"
211+
echo "build_bindings=${build_bindings}"
212+
echo "build_core=${build_core}"
213+
echo "build_pathfinder=${build_pathfinder}"
214+
echo "test_bindings=${test_bindings}"
215+
echo "test_core=${test_core}"
216+
echo "test_pathfinder=${test_pathfinder}"
217+
} >> "$GITHUB_OUTPUT"
218+
74219
# NOTE: Build jobs are intentionally split by platform rather than using a single
75220
# matrix. This allows each test job to depend only on its corresponding build,
76221
# so faster platforms can proceed through build & test without waiting for slower
@@ -151,6 +296,7 @@ jobs:
151296
needs:
152297
- ci-vars
153298
- should-skip
299+
- detect-changes
154300
- build-linux-64
155301
secrets: inherit
156302
uses: ./.github/workflows/test-wheel-linux.yml
@@ -159,6 +305,7 @@ jobs:
159305
host-platform: ${{ matrix.host-platform }}
160306
build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }}
161307
nruns: ${{ (github.event_name == 'schedule' && 100) || 1}}
308+
skip-bindings-test: ${{ !fromJSON(needs.detect-changes.outputs.test_bindings) }}
162309

163310
# See test-linux-64 for why test jobs are split by platform.
164311
test-linux-aarch64:
@@ -174,6 +321,7 @@ jobs:
174321
needs:
175322
- ci-vars
176323
- should-skip
324+
- detect-changes
177325
- build-linux-aarch64
178326
secrets: inherit
179327
uses: ./.github/workflows/test-wheel-linux.yml
@@ -182,6 +330,7 @@ jobs:
182330
host-platform: ${{ matrix.host-platform }}
183331
build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }}
184332
nruns: ${{ (github.event_name == 'schedule' && 100) || 1}}
333+
skip-bindings-test: ${{ !fromJSON(needs.detect-changes.outputs.test_bindings) }}
185334

186335
# See test-linux-64 for why test jobs are split by platform.
187336
test-windows:
@@ -197,6 +346,7 @@ jobs:
197346
needs:
198347
- ci-vars
199348
- should-skip
349+
- detect-changes
200350
- build-windows
201351
secrets: inherit
202352
uses: ./.github/workflows/test-wheel-windows.yml
@@ -205,6 +355,7 @@ jobs:
205355
host-platform: ${{ matrix.host-platform }}
206356
build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }}
207357
nruns: ${{ (github.event_name == 'schedule' && 100) || 1}}
358+
skip-bindings-test: ${{ !fromJSON(needs.detect-changes.outputs.test_bindings) }}
208359

209360
doc:
210361
name: Docs
@@ -228,6 +379,7 @@ jobs:
228379
runs-on: ubuntu-latest
229380
needs:
230381
- should-skip
382+
- detect-changes
231383
- test-linux-64
232384
- test-linux-aarch64
233385
- test-windows
@@ -254,7 +406,16 @@ jobs:
254406
#
255407
# Note: When [doc-only] is in PR title, test jobs are intentionally
256408
# skipped and should not cause failure.
409+
#
410+
# detect-changes gates whether heavy test matrices run at all; if it
411+
# does not succeed, downstream test jobs are skipped rather than
412+
# failed, which would otherwise go unnoticed here. Require its
413+
# success explicitly so a broken gating step cannot masquerade as a
414+
# green CI run.
257415
doc_only=${{ needs.should-skip.outputs.doc-only }}
416+
if ${{ needs.detect-changes.result != 'success' }}; then
417+
exit 1
418+
fi
258419
if ${{ needs.doc.result == 'cancelled' || needs.doc.result == 'failure' }}; then
259420
exit 1
260421
fi

.github/workflows/test-wheel-linux.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ on:
2222
nruns:
2323
type: number
2424
default: 1
25+
# When true, cuda.bindings tests (and the Cython tests that depend on
26+
# them) are skipped even when CTK majors match. Callers set this based
27+
# on the output of the detect-changes job in ci.yml so PRs that only
28+
# touch unrelated modules avoid the expensive bindings test suite.
29+
skip-bindings-test:
30+
type: boolean
31+
default: false
2532

2633
defaults:
2734
run:
@@ -113,6 +120,7 @@ jobs:
113120
LOCAL_CTK: ${{ matrix.LOCAL_CTK }}
114121
PY_VER: ${{ matrix.PY_VER }}
115122
SHA: ${{ github.sha }}
123+
SKIP_BINDINGS_TEST_OVERRIDE: ${{ inputs.skip-bindings-test && '1' || '0' }}
116124
run: ./ci/tools/env-vars test
117125

118126
- name: Download cuda-pathfinder build artifacts
@@ -122,21 +130,21 @@ jobs:
122130
path: ./cuda_pathfinder
123131

124132
- name: Download cuda-python build artifacts
125-
if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}}
133+
if: ${{ env.USE_BACKPORT_BINDINGS == '0' }}
126134
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
127135
with:
128136
name: cuda-python-wheel
129137
path: .
130138

131139
- name: Download cuda.bindings build artifacts
132-
if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}}
140+
if: ${{ env.USE_BACKPORT_BINDINGS == '0' }}
133141
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
134142
with:
135143
name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}
136144
path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}
137145

138146
- name: Download cuda-python & cuda.bindings build artifacts from the prior branch
139-
if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '1'}}
147+
if: ${{ env.USE_BACKPORT_BINDINGS == '1' }}
140148
env:
141149
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
142150
run: |

0 commit comments

Comments
 (0)