@@ -5,241 +5,21 @@ applyTo:
55 - " dpctl/**/*.pxi"
66---
77
8- # Cython Bindings Instructions
8+ # Cython Instructions
99
10- ## Context
10+ See [ dpctl/AGENTS.md ] ( /dpctl/AGENTS.md ) for conventions and patterns.
1111
12- Cython files in dpctl provide the bridge between Python and the C/C++ SYCL interface. They wrap SYCL runtime objects as Python extension types.
13-
14- ## File Types
15-
16- | Extension | Purpose |
17- | -----------| ---------|
18- | ` .pyx ` | Implementation files (compiled to C++) |
19- | ` .pxd ` | Declaration files (like C headers) |
20- | ` .pxi ` | Include files (textually included) |
21-
22- ## Required Directives
23-
24- Every ` .pyx ` file must start with (after license header):
12+ ## Quick Reference
2513
14+ ### Required Directives (after license header)
2615``` cython
2716# distutils: language = c++
2817# cython: language_level=3
2918# cython: linetrace=True
3019```
3120
32- ## Import Conventions
33-
34- ### cimport vs import
35-
36- ``` cython
37- # cimport - for C-level declarations (compile-time)
38- from cpython cimport pycapsule
39- from cpython.mem cimport PyMem_Free, PyMem_Malloc
40- from ._backend cimport DPCTLSyclDeviceRef, DPCTLDevice_Create
41-
42- # import - for Python-level usage (runtime)
43- import numpy as np
44- from . import _device_selection
45- ```
46-
47- ### Import Order
48- 1 . Standard library cimports
49- 2 . Third-party cimports
50- 3 . Local cimports (with ` # noqa: E211 ` if needed)
51- 4 . Blank line
52- 5 . Standard library imports
53- 6 . Third-party imports
54- 7 . Local imports
55-
56- ## Extension Type Pattern
57-
58- ``` cython
59- cdef class SyclDevice:
60- """
61- Python wrapper for sycl::device.
62-
63- Docstring describing the class.
64- """
65- # C-level attribute (not accessible from Python)
66- cdef DPCTLSyclDeviceRef _device_ref
67-
68- def __cinit__(self, filter_string=None):
69- """
70- Called before __init__, handles C memory allocation.
71- Must not raise Python exceptions that leave C state invalid.
72- """
73- if filter_string is not None:
74- self._device_ref = DPCTLDevice_CreateFromSelector(...)
75- else:
76- self._device_ref = NULL
77-
78- def __dealloc__(self):
79- """
80- Called during garbage collection. Clean up C resources.
81- """
82- if self._device_ref is not NULL:
83- DPCTLDevice_Delete(self._device_ref)
84-
85- cdef DPCTLSyclDeviceRef get_device_ref(self):
86- """
87- Internal method for C-level access.
88- Not visible from Python.
89- """
90- return self._device_ref
91-
92- @property
93- def name(self):
94- """Python property wrapping C getter."""
95- cdef const char *name_ptr = DPCTLDevice_GetName(self._device_ref)
96- if name_ptr is NULL:
97- raise RuntimeError("Failed to get device name")
98- try:
99- return name_ptr.decode("utf-8")
100- finally:
101- DPCTLCString_Delete(name_ptr)
102- ```
103-
104- ## Memory Management
105-
106- ### Rule: Always Clean Up in __ dealloc__
107-
108- ``` cython
109- def __dealloc__(self):
110- # Check for NULL before deleting
111- if self._queue_ref is not NULL:
112- DPCTLQueue_Delete(self._queue_ref)
113- ```
114-
115- ### Ownership Annotations
116-
117- Match C API annotations:
118- - ` __dpctl_give ` - Caller receives ownership, must delete
119- - ` __dpctl_take ` - Function takes ownership, don't use after
120- - ` __dpctl_keep ` - Function only observes, doesn't take ownership
121-
122- ``` cython
123- cdef void example():
124- # Receives ownership (__dpctl_give) - must delete
125- cdef DPCTLSyclEventRef event = DPCTLQueue_Submit(...)
126-
127- # ... use event ...
128-
129- # Clean up owned resource
130- DPCTLEvent_Delete(event)
131- ```
132-
133- ### GIL Management
134-
135- Release GIL for blocking C operations:
136-
137- ``` cython
138- cdef void copy_with_wait(DPCTLSyclEventRef event):
139- with nogil:
140- DPCTLEvent_Wait(event)
141-
142- # Or for longer sections
143- cdef void long_operation() nogil:
144- # Entire function runs without GIL
145- # Cannot call Python objects here
146- pass
147- ```
148-
149- ## Error Handling
150-
151- ### NULL Checks
152-
153- ``` cython
154- cdef DPCTLSyclDeviceRef dref = DPCTLDevice_Create(...)
155- if dref is NULL:
156- raise SyclDeviceCreationError("Failed to create device")
157- ```
158-
159- ### Exception Safety
160-
161- ``` cython
162- def create_something(self):
163- cdef SomeRef ref = SomeFunction()
164- if ref is NULL:
165- raise SomeError("Creation failed")
166- try:
167- # Operations that might raise
168- result = self._process(ref)
169- except:
170- # Clean up on exception
171- SomeDelete(ref)
172- raise
173- return result
174- ```
175-
176- ## Backend Declarations (.pxd)
177-
178- ``` cython
179- # _backend.pxd
180- cdef extern from "syclinterface/dpctl_sycl_device_interface.h":
181- ctypedef void* DPCTLSyclDeviceRef
182-
183- DPCTLSyclDeviceRef DPCTLDevice_Create(
184- DPCTLDeviceSelectorRef DSRef
185- ) nogil
186-
187- void DPCTLDevice_Delete(
188- DPCTLSyclDeviceRef DRef
189- ) nogil
190-
191- const char* DPCTLDevice_GetName(
192- DPCTLSyclDeviceRef DRef
193- ) nogil
194- ```
195-
196- ## Include Files (.pxi)
197-
198- Used for shared code snippets:
199-
200- ``` cython
201- # In main .pyx file
202- include "_sycl_usm_array_interface_utils.pxi"
203- ```
204-
205- ## Common Patterns
206-
207- ### Property with C String Return
208-
209- ``` cython
210- @property
211- def driver_version(self):
212- cdef const char* ver = DPCTLDevice_GetDriverVersion(self._device_ref)
213- if ver is NULL:
214- return ""
215- try:
216- return ver.decode("utf-8")
217- finally:
218- DPCTLCString_Delete(ver)
219- ```
220-
221- ### Capsule for Opaque Pointers
222-
223- ``` cython
224- def get_capsule(self):
225- """Return PyCapsule containing C pointer."""
226- if self._device_ref is NULL:
227- return None
228- return pycapsule.PyCapsule_New(
229- <void*>self._device_ref,
230- "SyclDeviceRef",
231- NULL # No destructor - we manage lifetime
232- )
233- ```
234-
235- ### Type Checking
236-
237- ``` cython
238- def some_method(self, other):
239- if not isinstance(other, SyclDevice):
240- raise TypeError(
241- f"Expected SyclDevice, got {type(other).__name__}"
242- )
243- cdef SyclDevice other_dev = <SyclDevice>other
244- # Now can access other_dev._device_ref
245- ```
21+ ### Key Rules
22+ - ` cimport ` for C-level declarations, ` import ` for Python
23+ - Store C refs as ` _*_ref ` , clean up in ` __dealloc__ `
24+ - Use ` with nogil: ` for blocking C operations
25+ - Check NULL before using C API returns
0 commit comments