Skip to content

Commit 8e2b42a

Browse files
Bordaclaude[bot]
andauthored
feat(xla): test marker, extra + CPU-PJRT CI job (#1254)
* feat(xla): test marker, extra + CPU-PJRT CI job * fix(ci): torch_xla libpython on LD_LIBRARY_PATH * fix(ci): pin torch to torch_xla minor in XLA lane * test(deps): add pandas to the tests dependency group * fix(xla): align torch/torch_xla, harden verify * test(xla): add tpu marker + exclude from lanes --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
1 parent c3294a5 commit 8e2b42a

3 files changed

Lines changed: 135 additions & 1 deletion

File tree

.github/workflows/ci-tests-cpu.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
- name: 🧪 Run the Test
6666
run: |
6767
uv run --no-sync pytest src/ tests/ \
68-
-n 2 -m "not gpu and not coco17 and not e2e_coreml and not e2e_executorch" \
68+
-n 2 -m "not gpu and not coco17 and not e2e_coreml and not e2e_executorch and not xla and not tpu" \
6969
--ignore=tests/run_smoke_all_models.py \
7070
--ignore=tests/legacy/test_checkpoint_compat.py \
7171
--cov=rfdetr --cov-report=xml \

.github/workflows/ci-tests-xla.yml

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: XLA tests Workflow
2+
3+
# Hardware-free validation of the XLA code paths (grid_sample gather branch, all_gather device
4+
# probe, XLAPrecision selection, bool-mask dtype, keypoint host-sync gates, ...). torch_xla reports
5+
# device.type == "xla" on ANY PJRT backend, so PJRT_DEVICE=CPU exercises every device-gated branch
6+
# without a TPU. Real-TPU-only concerns (MXU/TFLOPS, bf16-MXU convergence parity) stay on Colab/Kaggle.
7+
#
8+
# torch_xla ships Linux x86_64 wheels only -> ubuntu runner. Its _XLAC extension is ABI-locked to
9+
# ONE torch minor, and torch_xla's latest (2.9) lags torch's latest in [2.2,3.0) (2.13) — so letting
10+
# both float does NOT align them; the mismatch surfaces as an `undefined symbol` ImportError on
11+
# `import torch_xla`. We pin torch to torch_xla's minor (torch==2.9.* <-> torch_xla 2.9); uv then
12+
# resolves torchvision to the matching minor. Bump both together when a newer torch_xla ships.
13+
#
14+
# Trigger is manual + PR for now; the job self-passes while no @pytest.mark.xla tests exist yet
15+
# (pytest exit code 5 = "no tests collected"). Flip the guard off once Phase 1 lands xla tests.
16+
17+
on:
18+
workflow_dispatch:
19+
pull_request:
20+
branches: ["main", "release/*", "develop"]
21+
paths:
22+
- "src/rfdetr/**"
23+
- "tests/**"
24+
- "pyproject.toml"
25+
- ".github/workflows/ci-tests-xla.yml"
26+
27+
permissions:
28+
contents: read
29+
defaults:
30+
run:
31+
shell: bash
32+
33+
env:
34+
UV_TORCH_BACKEND: "cpu" # CPU-only torch; works with 'uv pip'
35+
PJRT_DEVICE: "CPU" # run XLA on the CPU PJRT plugin (no TPU, no libtpu)
36+
37+
concurrency:
38+
group: pytest-xla-${{ github.ref }}
39+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
40+
41+
jobs:
42+
run-xla-tests:
43+
name: XLA CPU-PJRT testing
44+
timeout-minutes: 25
45+
runs-on: ubuntu-latest
46+
steps:
47+
- name: 📥 Checkout the repository
48+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
49+
50+
- name: 🐍 Install uv and set Python version 3.11
51+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
52+
with:
53+
version: "0.9.26"
54+
python-version: "3.11"
55+
activate-environment: true
56+
57+
- name: 🚀 Install Packages (torch + torch_xla, CPU)
58+
timeout-minutes: 8
59+
# [xla] pulls torch_xla AND pins torch to its matching minor (see the [xla] extra in
60+
# pyproject.toml), so the resolver can't float torch ahead of torch_xla into an
61+
# ABI-incompatible combo. UV_TORCH_BACKEND=cpu keeps torch CPU-only.
62+
run: |
63+
uv pip install -e ".[train,xla,cli]" --group tests
64+
65+
- name: 🔧 Expose libpython for torch_xla
66+
# torch_xla's _XLAC extension links the shared libpython3.11.so.1.0, which uv's standalone
67+
# CPython keeps in the interpreter LIBDIR — not on the loader path. Put LIBDIR on
68+
# LD_LIBRARY_PATH for all later steps, else `import torch_xla` fails with
69+
# "libpython3.11.so.1.0: cannot open shared object file".
70+
run: |
71+
LIBDIR=$(uv run --no-sync python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
72+
echo "LD_LIBRARY_PATH=${LIBDIR}:${LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
73+
74+
- name: 🔎 Verify torch_xla runtime
75+
# shell: python runs under the setup-uv-activated venv interpreter (VIRTUAL_ENV on PATH).
76+
shell: python
77+
run: |
78+
import importlib.metadata as md
79+
80+
# torch_xla's _XLAC is ABI-locked to one torch minor. Read the resolved versions from
81+
# metadata BEFORE importing torch_xla — a skew must fail here with a clear message, because
82+
# `import torch_xla` itself crashes with a cryptic `undefined symbol` error on mismatch.
83+
torch_ver = md.version("torch")
84+
xla_ver = md.version("torch_xla")
85+
torch_minor = torch_ver.split("+")[0].split(".")[:2]
86+
xla_minor = xla_ver.split("+")[0].split(".")[:2]
87+
assert torch_minor == xla_minor, (
88+
f"torch {torch_ver} and torch_xla {xla_ver} have mismatched minors — ABI-incompatible"
89+
)
90+
91+
import torch
92+
import torch_xla
93+
import torch_xla.core.xla_model as xm
94+
95+
device = xm.xla_device()
96+
print("torch", torch.__version__, "| torch_xla", torch_xla.__version__, "| device", device)
97+
assert str(device).startswith("xla"), f"expected an xla device, got {device!r}"
98+
99+
- name: 🧪 Run the XLA-marked Tests
100+
run: |
101+
set +e
102+
uv run --no-sync pytest src/ tests/ \
103+
-n 1 -m "xla and not gpu and not tpu" \
104+
--ignore=tests/run_smoke_all_models.py \
105+
--ignore=tests/legacy/test_checkpoint_compat.py \
106+
--timeout=420 \
107+
--durations=50
108+
rc=$?
109+
set -e
110+
if [ "$rc" -eq 5 ]; then
111+
echo "No @pytest.mark.xla tests collected yet (Phase 1 not landed) — passing."
112+
exit 0
113+
fi
114+
exit $rc
115+
116+
- name: Minimize uv cache
117+
continue-on-error: true
118+
run: uv cache prune --ci

pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,19 @@ visual = [
132132
]
133133
cli = ["jsonargparse[signatures]>=4.27.7"]
134134
plus = ["rfdetr_plus>=1.0.1, <2.0.0"]
135+
# XLA backend for TPU training AND hardware-free XLA validation on CPU/GPU PJRT.
136+
# torch_xla is built on top of torch (NOT mutually exclusive — it requires torch present) and its
137+
# _XLAC extension is ABI-locked to ONE torch minor (a mismatch surfaces as an `undefined symbol`
138+
# ImportError on `import torch_xla`). torch_xla does not hard-pin torch in requires_dist, and PEP 508
139+
# cannot express "equal minor", so we pin BOTH to the current known-good pair (2.9) — bump the two
140+
# together when a newer torch_xla ships. Wheels are Linux x86_64 only (py3.10-3.13) -> sys_platform
141+
# marker keeps macOS/Windows installs of this extra a no-op. The bare wheel runs the CPU PJRT plugin
142+
# (PJRT_DEVICE=CPU) with no libtpu; real TPU adds torch_xla[tpu] (libtpu), GPU PJRT needs the separate
143+
# CUDA plugin wheel. Used by ci-tests-xla.yml to exercise @pytest.mark.xla paths.
144+
xla = [
145+
"torch==2.9.*; sys_platform == 'linux'",
146+
"torch_xla==2.9.*; sys_platform == 'linux'",
147+
]
135148

136149
[dependency-groups]
137150
# TODO: Temporary: GPU runner only has CUDA 12.8 driver (12080); torch>=2.11 requires a newer driver.
@@ -167,6 +180,7 @@ tests = [
167180
"pytest-rerunfailures>=10,<15",
168181
"pytest-timeout>=2,<3",
169182
"pytest-doctestplus>=1.2,<2",
183+
"pandas", # imported directly by tests/training/test_metrics_csv.py to read CSVLogger output
170184
"tomli>=2.0; python_version < '3.11'",
171185
]
172186

@@ -287,6 +301,8 @@ doctest_norecursedirs = ["tests/*"]
287301
pythonpath = ["src", "."]
288302
markers = [
289303
"gpu: tests that require GPU or are slow on CPU",
304+
"xla: tests that require an XLA device or torch_xla runtime (TPU, or CPU/GPU PJRT)",
305+
"tpu: tests that require real TPU hardware (libtpu/MXU); not runnable on CPU/GPU PJRT",
290306
"coco17: tests that require COCO 2017 images or annotations",
291307
# `flaky` is provided by pytest-rerunfailures; registered here too for clarity and to stay
292308
# safe under --strict-markers (used by tests/benchmarks/test_training_*.py).

0 commit comments

Comments
 (0)