CUDA operator cleanup#
Status: implemented
Scope: dead CUDA headers, unused header symbols, unreachable @BE kernel entry points,
dead Python dispatch paths, FFI module-name consistency.
Background#
brainevent ships 45 .cu files and 9 headers as package data; there is no compile step at
build time. The kernix toolchain (brainevent/_op/kernix_*.py) parses // @BE <name> annotations
at runtime, generates an XLA FFI wrapper per annotation, invokes nvcc, and registers each target
as "<module>.<func>".
Consequently every @BE annotation has a cost: a generated FFI wrapper, a compiled symbol in
the .so, and a registered target on first lowering — whether or not the Python layer can ever
name it. Annotations that no Python code path can reach are pure overhead.
An audit of the whole CUDA surface found:
102 of 749
@BEentry points unreachable from Python.2 orphan header files (never
#included anywhere).8 unused symbols in the internal
cuda_common.h.2 dead Python dispatch paths in
_fcn/binary.py.3 FFI module names in
_jit_uniformthat break thejit_<family>_naming convention.
No entire .cu file is dead, and no Python-referenced target is dangling.
Non-findings (checked, deliberately not acted on)#
Wheel packaging of
include/*.h. Suspected missing from the wheel; verified against the installedbrainevent-0.1.2RECORD, which lists all 9 headers. Not a bug._dense/plasticity_binary_on_{pre,post}.cu. Untouched since 2026-03 and therefore look stale, but they are registered withdef_cuda_raw_kernel(..., asdefault=True)and are the default GPU backend. Left alone.dispatch.h/check.hpublic macros.BE_DISPATCH_FLOATING,BE_DISPATCH_INTEGRAL,BE_DISPATCH_ALL_TYPES,BE_CHECK,BE_CHECK_KERNEL_LAUNCHare documented indocs/reference/kernels/cpp-api.rstand exercised by_op/kernix_cpp_test.py/_op/kernix_dtypes_test.py.BE_DISPATCH_FLOATING_AND_HALF,BE_DISPATCH_COMPLEX,BE_DISPATCH_ALLandcomplex64_t/complex128_tare unused but live in the same public header — retained to avoid a breaking change for downstream kernel authors.HIPBackend(_op/kernix_compiler.py) — intentional stub with implementation guidance in its docstring, publicly exported.load_cuda_dir— never called internally, but documented public API.
Changes#
1. Orphan headers deleted#
File |
Lines |
Rationale |
|---|---|---|
|
26 |
Body was entirely a comment declaring itself a placeholder. Zero |
|
94 |
Zero |
Both were byte-hashed into the compile cache key, so removal invalidates cached modules once.
2. Unused symbols removed from cuda_common.h#
warp_reduce_max_f32, warp_reduce_max_f64, warp_reduce_min_f32, warp_reduce_min_f64,
ACC_T_F16, ACC_T_BF16, ACC_T_F32, ACC_T_F64.
All other helpers (warp_reduce_sum_*, atomic_add_*, READ_*, WRITE_*, IS_ACTIVE_*,
ZERO_*) remain — they are in heavy use.
3. Unreachable @BE entry points removed (749 → 647)#
Governing rule. In the CSR/slice/dt2t files, the _auto dispatcher internally launches the
__global__ strategy kernels. Removing an entry point therefore deletes only its host FFI
wrapper macro, that macro’s instantiations, and its // @BE annotation. A __global__ kernel is
removed only when nothing launches it afterward.
File |
Removed |
Notes |
|---|---|---|
|
12 |
|
|
8 |
|
|
12 |
|
|
8 |
|
|
6 |
both mv and mm |
|
32 |
both fwd and grad |
|
16 |
entire |
|
8 |
|
Why each was unreachable:
_nt_thread/_nt_warp/_nt_block; slice_thread/_warp/_block; dt2t_row_thread/_row_warp/_nz_thread— Python only ever composes the_autotarget name (_csr/float.py,_csr/binary.py,_csr/slice.py,_csr/dt2t.py). The explicit strategy variants had no caller and no test.binary_fcnmm_araw_*— the dispatch that would have named them was a'''...'''pseudo-code block containing non-parsing Python (else sraw:).binary_fcnmv_scatter_*_float_*—_fcn/binary.pyhardcodes the_boolsuffix and coerces spikes withu.math.asarray(spikes, dtype=bool), making the_floatpath permanently unreachable.
4. Dead Python paths removed in _fcn/binary.py#
The
'''...'''pseudo-code block documenting the removedarawdispatch. It sat mid-function after executable statements (so it was not a docstring) and contained invalid Python.The phantom backend string
'SRAW_MM_kernel'in both membership tests of_binary_fcnmm_uses_raw_batch_first. It is registered nowhere; passing it asbackend=raisesKernelFallbackExhaustedError, so the branch was unreachable.'cuda_raw'is retained.
5. _jit_uniform FFI module names aligned#
_jit_uniform/float.py registered unprefixed FFI module names (float_jitu, float_jitumv,
float_jitumm) while _jit_scalar and _jit_normal use the jit_<family>_ convention. The
kernix registry is process-global and a same-name/different-module clobber raises
KernelRegistrationError, so unprefixed names are a collision hazard. Renamed to
jit_uniform_jitu, jit_uniform_jitumv, jit_uniform_jitumm.
The XLACustomKernel('float_jitu', ...) primitive names were deliberately left unchanged —
they already match _jit_scalar (float_jitsmv) and _jit_normal (float_jitnmv), and renaming
them would alter jaxpr output and registry keys for no benefit.
Edge cases considered#
Orphaning a device kernel. Removing a host wrapper can strand the
__global__kernel it was the sole launcher of. Handled per-file; onlybinary_csrmv.cu’s warp kernels and the entirearawfamily were affected.Over-removal.
binary_fcnmm_gather_*(48 entries) superficially resembles the dead variants but is named by Python — retained.Cache invalidation. Header deletion and the module rename change compile cache keys; the first GPU run after this change recompiles. Expected, not a regression.
_autothreshold semantics. Removing explicit variants does not change which kernel_autoselects — the branch thresholds are untouched, so GPU numerics are unchanged.
Verification#
Completed:
Annotation count —
@BEannotations dropped 749 → 647 (exactly 102 removed).Name-set diff vs HEAD — 102 unique exported names removed, 0 added, and every removed name matched the intended dead-kernel pattern (no collateral removals).
Template resolution — all 51 Python
kernel_nametemplates with a literal stem still resolve to a surviving exported kernel.No orphaned device code — no
__global__kernel is left without a launcher, no launcher references a deleted kernel, and noDEFINE_/FFI_macro is defined-but-unused or used-but-undefined across the 8 edited files.Residual references —
attrs.h,curand_common,warp_reduce_max/min,ACC_T_,araw/ARAWandSRAW_MM_kernelare unreferenced package-wide.Tests —
pytest brainevent/→ 1574 passed, 0 failed, 201 skipped.Type gate — reproduced the CI
type_checkjob in an isolated venv with onlymypy==2.3.0(CI deliberately installs no runtime deps):Success: no issues found in 75 source files, exit 0. A local mypy run with runtime deps installed reports 204 pre-existing errors at lines untouched by this change; that configuration is not the gate.GPU validation — run on an RTX 3080 Laptop (driver 596.49, CUDA 13.2) with jax 0.11.0 + jaxlib CUDA and nvcc 13.1, after deleting
~/.cache/brainevent/so every kernel recompiled from source:pytest brainevent/ -m ""→ 3773 passed, 0 failed, 29 skipped (27m07s). This exercises thecuda_rawbackend for every edited module against thejax_raw/numbareference paths.
Regression caught during GPU validation#
The first GPU run failed 35 CSR tests with CompilationError from nvcc. Cause: the initial
removal pass deleted only the first line of each backslash-continued
DEFINE_CSRMV_NT_WARP_{HOMO,HETERO}(...) instantiation in binary_csrmv.cu, leaving 16 dangling
argument fragments such as READ_F32, WRITE_F32, warp_reduce_sum_f32, 0.0f) that bound to the
following instantiation and corrupted it.
Nothing in the CPU pipeline could have caught this — .cu sources are never compiled unless a GPU
kernel is actually lowered, so the 1574-test CPU suite, the annotation cross-check, and the
macro-definition audit all passed against broken CUDA. The file was reverted and redone with a
removal pass that follows line continuations, and a dangling-fragment detector was run across all
45 .cu files to confirm no other file was affected.
Takeaway for future .cu edits: any change to these sources must be validated on a GPU. The
CPU suite proves nothing about them.
Known follow-up (out of scope)#
csr_solve is imported in _csr/__init__.py, absent from that module’s __all__, not re-exported
from brainevent/__init__.py, yet listed in docs/reference/apis/operations.rst — a documented
API that is not importable from the package root.