Skip to content

Commit ba1451c

Browse files
committed
docs: correct stale bindings and core contributor guidance
Signed-off-by: Ralf W. Grosse-Kunstleve <[email protected]>
1 parent afa6249 commit ba1451c

4 files changed

Lines changed: 38 additions & 32 deletions

File tree

‎cuda_bindings_13/AGENTS.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ subpackage in the `cuda-python` monorepo.
4444
- **Cython tests**:
4545
- build: `tests/cython/build_tests.sh` (or platform equivalent)
4646
- run: `pytest tests/cython/`
47-
- **Samples**: sample coverage is pytest-based under `../samples/cuda_bindings/`.
48-
- **Benchmarks**: run with `pytest --benchmark-only benchmarks/` when needed.
47+
- **Samples**: run pytest-based sample coverage in `tests/example_tests/`;
48+
sample sources and instructions live in `../samples/cuda_bindings/`.
49+
- **Benchmarks**: see the [benchmark README](../benchmarks/cuda_bindings/README.md)
50+
for the Pixi tasks that run the Python and C++ benchmarks.
4951

50-
The `legacy_tests` subdirectory tests the old pre-v2 APIs of `driver`, `runtime`
52+
The `tests/legacy_api` subdirectory tests the old pre-v2 APIs of `driver`, `runtime`
5153
and `nvrtc`. These test files should not be added to, only updated when
5254
necessary to fix test failures. The canonical set of tests are those outside of
53-
the `legacy_tests` subdirectory.
55+
the `tests/legacy_api` subdirectory.
5456

5557
## Build and environment notes
5658

‎cuda_bindings_13/README.md‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,29 @@ To run these tests:
4242
Cython tests are located in `tests/cython` and need to be built. These builds have the same CUDA Toolkit header requirements as [Installing from Source](https://nvidia.github.io/cuda-python/cuda-bindings/latest/install.html#requirements) where the major.minor version must match `cuda.bindings`. To build them:
4343

4444
1. Setup environment variable `CUDA_PATH` (or `CUDA_HOME`) with the path to the CUDA Toolkit installation. Note: If both are set, `CUDA_PATH` takes precedence.
45-
2. Run `build_tests` script located in `test/cython` appropriate to your platform. This will both cythonize the tests and build them.
45+
2. Run the `build_tests` script located in `tests/cython` appropriate to your platform. This will both cythonize the tests and build them.
4646

4747
To run these tests:
4848
* `python -m pytest tests/cython/` against editable installations
4949
* `pytest tests/cython/` against installed packages
5050

5151
### Samples
5252

53-
Various [CUDA Samples](https://github.com/NVIDIA/cuda-samples/tree/master) that were rewritten using CUDA Python are located in `examples`.
53+
Various [CUDA Samples](https://github.com/NVIDIA/cuda-samples/tree/master) that were rewritten using CUDA Python are located in [samples/cuda_bindings](../samples/cuda_bindings/). Each sample directory has its own README with dependencies and instructions for running it.
5454

5555
In addition, extra examples are included:
5656

57-
* `examples/extra/jit_program_test.py`: Demonstrates the use of the API to compile and
57+
* [jitProgram.py](../samples/cuda_bindings/extra/jitProgram/jitProgram.py): Demonstrates the use of the API to compile and
5858
launch a kernel on the device. Includes device memory allocation /
5959
deallocation, transfers between host and device, creation and usage of
6060
streams, and context management.
6161

62-
To run these samples:
63-
* `python -m pytest tests/cython/` against editable installations
64-
* `pytest tests/cython/` against installed packages
62+
To run the automated sample coverage in `tests/example_tests/`, run
63+
`pixi run test-samples` from this directory.
6564

6665
### Benchmark
6766

68-
Allows for analyzing binding performance using plugin [pytest-benchmark](https://github.com/ionelmc/pytest-benchmark).
69-
70-
To run these benchmarks:
71-
* `python -m pytest --benchmark-only benchmarks/` against editable installations
72-
* `pytest --benchmark-only benchmarks/` against installed packages
67+
Python and C++ benchmarks for analyzing binding overhead live in
68+
[benchmarks/cuda_bindings](../benchmarks/cuda_bindings/). See the
69+
[benchmark README](../benchmarks/cuda_bindings/README.md) for the Pixi environments,
70+
benchmark commands, and result comparison instructions.

‎cuda_core/AGENTS.md‎

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,17 @@ and agents should flag violations.
156156
objects that are not meant to be shared (e.g., the thread-local `Device`) do not
157157
need such guards (see #2321). Reference-count integrity is guaranteed; cache
158158
value-identity/idempotency is not.
159-
- **Entry points work with or without the GIL**: Cython calls the helpers in
160-
`_cpp/rt/` both inside and outside `with nogil` blocks. They never require
161-
the GIL, release it around driver calls, and never acquire it while they
162-
hold a C++ lock. The only paths that acquire it are the reporting wrappers
163-
(`pw_*`, `report_*`) and the one-time driver function-table fill
164-
(`ensure_fn_table()`, see `_cpp/rt/DESIGN.md`). Driver and destructor
165-
callbacks run at arbitrary times, so they take the GIL (`with gil`) and probe
166-
for interpreter shutdown before touching Python objects.
159+
- **GIL handling depends on the path**: Cython calls the helpers in `_cpp/rt/`
160+
both inside and outside `with nogil` blocks. Follow each helper's GIL
161+
contract, release the GIL around driver calls, and never acquire it while
162+
holding a C++ lock. Reporting wrappers (`pw_*`, `report_*`), the one-time
163+
function-table fill (`ensure_fn_table()`), and Python-owner cleanup may
164+
acquire it internally. Owner-release deleters use `GILAcquireGuard` to probe
165+
for interpreter shutdown before touching Python objects. Python host
166+
callbacks use `_py_host_trampoline` (`with gil`); CUDA user-object destructor
167+
callbacks only enqueue deferred cleanup, without acquiring the GIL,
168+
touching Python objects, or calling the driver (see `_cpp/rt/DESIGN.md` and
169+
`_cpp/rt/py_deferred_cleanup.cpp`).
167170
- **Driver calls go through the table**: C++ calls the driver with
168171
`DRIVER_CALL(name, args...)`. Its pointers come from the table that
169172
cuda-bindings resolves, never from the Cython wrappers. If the installed
@@ -212,10 +215,10 @@ below are for contributors. Reviewers and agents should flag violations.
212215
`HANDLE_RETURN`; an `except` block whose rollback failed uses
213216
`attach_rollback_failure()`; a deleter or cleanup path uses a `pw_*`
214217
wrapper or `report_cuda_error()`; the same situation in Cython or Python
215-
uses `warnings.warn(..., CUDAWarning)`; a CUDA callback thread does nothing
216-
that needs the GIL and hands its work to the deferred-cleanup queue
217-
(`Py_AddPendingCall` is GIL-free and allowed there). The table in
218-
`_cpp/rt/DESIGN.md` ("Which channel to use") spells this out.
218+
uses `warnings.warn(..., CUDAWarning)`; a CUDA user-object destructor
219+
callback does nothing that needs the GIL and hands its work to the
220+
deferred-cleanup queue (`Py_AddPendingCall` is GIL-free and allowed there).
221+
The table in `_cpp/rt/DESIGN.md` ("Which channel to use") spells this out.
219222
- **`pw_*` runs user Python**: a `p_` pointer only calls the driver; its `pw_`
220223
twin also acquires the GIL on failure and runs the warning filters,
221224
`showwarning`, or `sys.unraisablehook`, any of which may call back into
@@ -320,7 +323,10 @@ Python or Cython type annotations should be included for all public APIs. Avoid
320323
the use of `Any` unless absolutely necessary. The argument and return types as
321324
defined in the docstrings should match the type annotations.
322325

323-
Python imports should generally be outside of an if typing.TYPE_CHECK: block, even if the imported object is only used in type annotations. Use if typing.TYPE_CHECK: only to avoid creating import cycles. (This guidance maximizes compatibility with the cross-reference mechanisms in Sphinx.)
326+
Python imports should generally be outside of an `if typing.TYPE_CHECKING:`
327+
block, even if the imported object is only used in type annotations. Use
328+
`if typing.TYPE_CHECKING:` only to avoid creating import cycles. (This guidance
329+
maximizes compatibility with the cross-reference mechanisms in Sphinx.)
324330

325331
### Semantics
326332

‎cuda_core/cuda/core/_cpp/rt/DESIGN.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ exactly one of these; none is ever dropped.
430430
| Cython, inside an `except` block whose rollback failed | `attach_rollback_failure(op, status, detail)` | Adds a note to the exception being handled. Reports instead if nothing is being handled. |
431431
| C++, a deleter or deferred cleanup | A `pw_*` wrapper, or `report_cuda_error()` / `report_message()` | Emits `CUDAWarning`. Never raises. |
432432
| Cython or Python, a `__dealloc__` or destructor-path callback | `warnings.warn(msg, CUDAWarning, stacklevel=2)` | Same. |
433-
| A CUDA callback thread | Nothing that needs the GIL. Hand the work to the deferred-cleanup queue with `Py_AddPendingCall` | CUDA forbids driver calls there, and acquiring the GIL there can deadlock with a GIL holder blocked in a driver call. GIL-free C API that only schedules work is fine. |
433+
| A CUDA user-object destructor callback | Nothing that needs the GIL. Hand the work to the deferred-cleanup queue with `Py_AddPendingCall` | CUDA forbids driver calls there, and acquiring the GIL there can deadlock with a GIL holder blocked in a driver call. GIL-free C API that only schedules work is fine. |
434434

435435
### `p_` versus `pw_`
436436

@@ -455,9 +455,9 @@ allocate or throw, since a deleter is `noexcept`.
455455
So: use `pw_` only in deleters and cleanup paths that hold no C++ lock and have
456456
finished updating the layer's own state. Where a lock must stay held, call
457457
`p_`, keep the status, and report after the lock is released, as
458-
`deviceptr_import_ipc` does. CUDA callback threads need no extra rule for
459-
`pw_`: the driver call is forbidden there, so the wrapper is too. The general
460-
rule for those threads is no GIL and no Python objects; GIL-free scheduling
458+
`deviceptr_import_ipc` does. CUDA user-object destructor callbacks need no extra
459+
rule for `pw_`: the driver call is forbidden there, so the wrapper is too. Those
460+
callbacks must not acquire the GIL or touch Python objects; GIL-free scheduling
461461
calls such as `Py_AddPendingCall` are how work leaves them.
462462

463463
## Usage from Cython

0 commit comments

Comments
 (0)