|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +dpctl is a Python/Cython wrapper over a subset of SYCL, built on a C API |
| 4 | +library (`libsyclinterface`). It is compiled with Intel oneAPI DPC++ (`icx`/`icpx`). |
| 5 | + |
| 6 | +## Environment |
| 7 | + |
| 8 | +- Activate the compiler before building or testing: `source /opt/intel/oneapi/setvars.sh` |
| 9 | + (or use a conda env with `dpcpp_linux-64`). The environment does not persist |
| 10 | + between shell invocations; source it in the same command: |
| 11 | + `source /opt/intel/oneapi/setvars.sh && python -m pytest dpctl/tests/...`. |
| 12 | +- Check visible devices: `sycl-ls`. Tests skip on missing devices/aspects; a CPU |
| 13 | + OpenCL device is enough for most of the suite. |
| 14 | +- Python build deps: `pip install numpy cython scikit-build cmake ninja pytest "versioneer[toml]==0.29"`. |
| 15 | + |
| 16 | +## Commands |
| 17 | + |
| 18 | +- Build in place + editable install: `python scripts/build_locally.py --verbose` |
| 19 | + - defaults to `icx`/`icpx` on `PATH`; other compilers need `--compiler-root` |
| 20 | + - `--debug`, `--clean`, `--target-cuda[=sm_XX]`, `--target-hip=<arch>`, |
| 21 | + `--cmake-opts="-D..."` |
| 22 | +- Python tests: `python -m pytest dpctl/tests` |
| 23 | + - one file: `python -m pytest dpctl/tests/test_sycl_queue.py` |
| 24 | + - one test: `python -m pytest dpctl/tests/test_sycl_queue.py -k memset` |
| 25 | + - without a C compiler/Cython: add `-k "not test_cython_api and not test_c_headers"` |
| 26 | +- C API tests (GoogleTest, needs `GTEST_ROOT`): `bash libsyclinterface/dbg_build.sh` |
| 27 | + (runs `make check`) |
| 28 | +- Coverage (C + Python, rebuilds with `-DDPCTL_BUILD_CAPI_TESTS=ON`): |
| 29 | + `python scripts/gen_coverage.py --oneapi` |
| 30 | +- Docs (needs doxyrest): `python scripts/gen_docs.py --doxyrest-root=<path>` |
| 31 | +- Lint/format one file (no build needed): `pre-commit run --files <path>` |
| 32 | +- Lint/format everything: `pre-commit run --all-files` |
| 33 | + (black, isort, flake8, cython-lint, clang-format, codespell, bandit, shellcheck, |
| 34 | + gitleaks, actionlint). Config: `pyproject.toml`, `.flake8`, `.clang-format`. |
| 35 | + |
| 36 | +## Structure |
| 37 | + |
| 38 | +- `libsyclinterface/` — C API over SYCL (C++ implementation) |
| 39 | + - `include/syclinterface/*.h` — public C headers, `DPCTL<Type>_<Op>` functions |
| 40 | + - `source/*.cpp` — implementations |
| 41 | + - `tests/*.cpp` — GoogleTest suite; `*.spv` are prebuilt kernel fixtures |
| 42 | +- `dpctl/` — Python package |
| 43 | + - `_backend.pxd` — Cython `extern` declarations of the C API |
| 44 | + - `_sycl_*.pyx/.pxd` — `SyclDevice`, `SyclQueue`, `SyclContext`, `SyclEvent`, ... |
| 45 | + - `memory/` — USM memory objects (`MemoryUSMDevice`, ...), IPC memory |
| 46 | + - `compiler/` — `SyclKernelBundle` creation (SPIR-V, SYCL source) |
| 47 | + - `program/` — deprecated alias of `dpctl.compiler` |
| 48 | + - `utils/` — order manager, device queries, Intel device info |
| 49 | + - `apis/include/` — Python C-API headers for extensions (`dpctl_capi.h`, `dpctl4pybind11.hpp`) |
| 50 | + - `tests/` — pytest suite; `tests/helper/` has `get_queue_or_skip` and friends |
| 51 | +- `examples/` — python, cython, pybind11, c extension examples (each with README) |
| 52 | +- `docs/doc_sources/` — Sphinx sources |
| 53 | +- `conda-recipe/`, `conda-recipe-cf/` — conda packaging used by CI |
| 54 | +- `scripts/` — build, coverage, docs drivers |
| 55 | + |
| 56 | +## Adding a SYCL feature (typical PR shape) |
| 57 | + |
| 58 | +1. Declare in `libsyclinterface/include/syclinterface/dpctl_sycl_<x>_interface.h` |
| 59 | + with a Doxygen comment and ownership attributes. |
| 60 | +2. Implement in `libsyclinterface/source/dpctl_sycl_<x>_interface.cpp`. |
| 61 | +3. Add GoogleTest cases in `libsyclinterface/tests/test_sycl_<x>_interface.cpp`. |
| 62 | +4. Declare in `dpctl/_backend.pxd`; wrap in `dpctl/_sycl_<x>.pyx` (and `.pxd` if |
| 63 | + the method is `cdef`). |
| 64 | +5. Add pytest coverage in `dpctl/tests/`. |
| 65 | +6. Add a `CHANGELOG.md` entry with the PR link. |
| 66 | + |
| 67 | +Reference PRs to copy from: |
| 68 | +- New queue operation: gh-2361 (`DPCTLQueue_Memset` → `SyclQueue.memset`, |
| 69 | + `dpctl/tests/test_sycl_queue_memset.py`). |
| 70 | +- New device info query: gh-2324 (`dpctl_sycl_device_interface.h` → |
| 71 | + `dpctl/_sycl_device.pyx`; register the check in |
| 72 | + `dpctl/tests/_device_attributes_checks.py`). New enums go through |
| 73 | + `dpctl_sycl_enum_types.h`, `libsyclinterface/helper/`, and `dpctl/enum_types.py`. |
| 74 | + |
| 75 | +## Conventions |
| 76 | + |
| 77 | +### C API |
| 78 | +- Opaque refs (`DPCTLSyclQueueRef`, ...) via `wrap<T>`/`unwrap<T>` |
| 79 | + (`dpctl_sycl_type_casters.hpp`). |
| 80 | +- Annotate ownership: `__dpctl_give` (caller must delete), `__dpctl_take` |
| 81 | + (callee consumes), `__dpctl_keep` (borrowed). See `Support/MemOwnershipAttrs.h`. |
| 82 | +- Never let a C++ exception cross the C boundary: catch, call |
| 83 | + `error_handler(e, __FILE__, __func__, __LINE__)`, return `nullptr`/error value. |
| 84 | +- Null-check every incoming ref and report via `error_handler`. |
| 85 | +- Errors are silent unless `DPCTL_VERBOSITY=warning` (or `error`) is set; set it |
| 86 | + when debugging a `nullptr` return. |
| 87 | + |
| 88 | +### Cython / Python |
| 89 | +- Release the GIL (`with nogil:`) around calls that may block on the device. |
| 90 | +- Python-visible errors: raise specific exceptions (`TypeError`, `ValueError`, |
| 91 | + `SyclQueueCreationError`, ...) when the C API returns `NULL`. |
| 92 | +- Free-threaded CPython (3.14t) is supported; do not rely on the GIL for |
| 93 | + thread safety of shared state. |
| 94 | +- Line length 80 (black, isort, cython-lint, clang-format). |
| 95 | + |
| 96 | +### Tests |
| 97 | +- Get devices with `get_queue_or_skip()` / skip on missing aspects; never assume |
| 98 | + a GPU or fp64 support. |
| 99 | +- Test both sync and `*_async` variants when adding queue operations. |
| 100 | + |
| 101 | +### Files |
| 102 | +- New files need the Apache-2.0 license header from `CONTRIBUTING.md` |
| 103 | + (C/C++ headers also need the `\file` Doxygen block). |
| 104 | +- Comments and docstrings: short, describe what the code does. |
| 105 | + |
| 106 | +## Git |
| 107 | + |
| 108 | +- Branch off `master`; pre-commit blocks commits directly to `master` and |
| 109 | + `maintenance/*`. |
| 110 | +- One concern per PR; fill in `.github/pull_request_template.md`. |
| 111 | +- Update `CHANGELOG.md` (Keep a Changelog sections: Added, Changed, Deprecated, |
| 112 | + Removed, Fixed, Maintenance) for user-visible changes, citing `gh-NNNN`. |
| 113 | + |
| 114 | +## Boundaries |
| 115 | + |
| 116 | +- Generated, do not edit: `dpctl/*.cxx`, `dpctl/**/*.cxx`, `dpctl/include/` |
| 117 | + (headers copied/generated at build time), `dpctl/_version.py` (versioneer), |
| 118 | + `_skbuild/`, `build/`. |
| 119 | +- Edit C headers in `libsyclinterface/include/`, not their copies under `dpctl/include/`. |
| 120 | +- In-place `.so` files survive branch switches; rebuild (`--clean`) before |
| 121 | + trusting test results after checking out another branch. |
| 122 | +- Changing an existing C API signature or enum value is a breaking change: |
| 123 | + call it out in the PR and the CHANGELOG `NOTE` list. |
| 124 | +- `.github/workflows/` actions are pinned to commit SHAs (checked by zizmor); |
| 125 | + keep that when adding steps. |
| 126 | +- `conda-recipe*/`, release versions, and doc version lists need maintainer review. |
0 commit comments