Skip to content

Commit 89713a7

Browse files
authored
[12.9.x] Backport FFI helper and normalized channel-format fixes (#2934)
Apply the CUDA 12.9 subset of #2931: fix the JIT wall-time out-pointer and cover helper attributes and normalized channel formats that exist on this branch.
1 parent b6c0fa6 commit 89713a7

5 files changed

Lines changed: 182 additions & 7 deletions

File tree

‎cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxi‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,42 @@ cdef cudaError_t getDescInfo(const cudaChannelFormatDesc* d, int *numberOfChanne
406406
elif case_desc(d, 10, 10, 10, 2, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized1010102):
407407
numberOfChannels[0] = 4
408408
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT_101010_2
409+
elif case_desc(d, 8, 0, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X1):
410+
numberOfChannels[0] = 1
411+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT8X1
412+
elif case_desc(d, 8, 8, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X2):
413+
numberOfChannels[0] = 2
414+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT8X2
415+
elif case_desc(d, 8, 8, 8, 8, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X4):
416+
numberOfChannels[0] = 4
417+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT8X4
418+
elif case_desc(d, 8, 0, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X1):
419+
numberOfChannels[0] = 1
420+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT8X1
421+
elif case_desc(d, 8, 8, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X2):
422+
numberOfChannels[0] = 2
423+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT8X2
424+
elif case_desc(d, 8, 8, 8, 8, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X4):
425+
numberOfChannels[0] = 4
426+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT8X4
427+
elif case_desc(d, 16, 0, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X1):
428+
numberOfChannels[0] = 1
429+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT16X1
430+
elif case_desc(d, 16, 16, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X2):
431+
numberOfChannels[0] = 2
432+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT16X2
433+
elif case_desc(d, 16, 16, 16, 16, cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X4):
434+
numberOfChannels[0] = 4
435+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_UNORM_INT16X4
436+
elif case_desc(d, 16, 0, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X1):
437+
numberOfChannels[0] = 1
438+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT16X1
439+
elif case_desc(d, 16, 16, 0, 0, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X2):
440+
numberOfChannels[0] = 2
441+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT16X2
442+
elif case_desc(d, 16, 16, 16, 16, cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X4):
443+
numberOfChannels[0] = 4
444+
format[0] = cydriver.CUarray_format_enum.CU_AD_FORMAT_SNORM_INT16X4
409445
else:
410446
return cudaErrorInvalidChannelDescriptor
411447

‎cuda_bindings/cuda/bindings/_lib/utils.pxd‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,5 @@ cdef class _HelperCUcoredumpSettings:
155155

156156
# Return values
157157
cdef cpp_bool _bool
158+
cdef unsigned int _uint
158159
cdef char* _charstar

‎cuda_bindings/cuda/bindings/_lib/utils.pxi‎

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,11 @@ cdef class _HelperCUmem_range_attribute:
284284
self._attr = attr.value
285285
if self._attr in (cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_READ_MOSTLY,
286286
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION,
287-
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION,):
287+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION,
288+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_TYPE,
289+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_ID,
290+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_TYPE,
291+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_ID,):
288292
self._cptr = <void*>&self._int_val
289293
elif self._attr in (cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_ACCESSED_BY,):
290294
self._cptr = _callocWrapper(1, self._data_size)
@@ -303,7 +307,11 @@ cdef class _HelperCUmem_range_attribute:
303307
def pyObj(self):
304308
if self._attr in (cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_READ_MOSTLY,
305309
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION,
306-
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION,):
310+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION,
311+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_TYPE,
312+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_ID,
313+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_TYPE,
314+
cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_ID,):
307315
return self._int_val
308316
elif self._attr in (cydriver.CUmem_range_attribute_enum.CU_MEM_RANGE_ATTRIBUTE_ACCESSED_BY,):
309317
return [self._int_val_list[idx] for idx in range(int(self._data_size/4))]
@@ -356,9 +364,22 @@ cdef class _HelperCUpointer_attribute:
356364
cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_ALLOWED_HANDLE_TYPES,):
357365
self._ull = init_value
358366
self._cptr = <void*>&self._ull
359-
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_RANGE_SIZE,):
367+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_RANGE_SIZE,
368+
cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MAPPING_SIZE,):
360369
self._size = init_value
361370
self._cptr = <void*>&self._size
371+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MAPPING_BASE_ADDR,):
372+
if self._is_getter:
373+
self._devptr = _driver.CUdeviceptr()
374+
self._cptr = <void*><void_ptr>self._devptr.getPtr()
375+
else:
376+
self._cptr = <void*><void_ptr>init_value.getPtr()
377+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MEMORY_BLOCK_ID,):
378+
self._ull = init_value
379+
self._cptr = <void*>&self._ull
380+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_IS_HW_DECOMPRESS_CAPABLE,):
381+
self._bool = init_value
382+
self._cptr = <void*>&self._bool
362383
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE,):
363384
if self._is_getter:
364385
self._mempool = _driver.CUmemoryPool()
@@ -400,8 +421,15 @@ cdef class _HelperCUpointer_attribute:
400421
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_BUFFER_ID,
401422
cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_ALLOWED_HANDLE_TYPES,):
402423
return self._ull
403-
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_RANGE_SIZE,):
424+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_RANGE_SIZE,
425+
cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MAPPING_SIZE,):
404426
return self._size
427+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MAPPING_BASE_ADDR,):
428+
return self._devptr
429+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MEMORY_BLOCK_ID,):
430+
return self._ull
431+
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_IS_HW_DECOMPRESS_CAPABLE,):
432+
return self._bool
405433
elif self._attr in (cydriver.CUpointer_attribute_enum.CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE,):
406434
return self._mempool
407435
else:
@@ -461,7 +489,9 @@ cdef class _HelperCUjit_option:
461489
self._cptr = <void*><void_ptr>self._uint
462490
elif self._attr in (cydriver.CUjit_option_enum.CU_JIT_WALL_TIME,):
463491
self._float = init_value
464-
self._cptr = <void*><void_ptr>self._float
492+
# CU_JIT_WALL_TIME is an OUT option: CUDA writes the elapsed float
493+
# back through the pointer.
494+
self._cptr = <void*>&self._float
465495
elif self._attr in (cydriver.CUjit_option_enum.CU_JIT_INFO_LOG_BUFFER,
466496
cydriver.CUjit_option_enum.CU_JIT_ERROR_LOG_BUFFER):
467497
self._charstar = init_value
@@ -480,7 +510,10 @@ cdef class _HelperCUjit_option:
480510
cydriver.CUjit_option_enum.CU_JIT_PREC_DIV,
481511
cydriver.CUjit_option_enum.CU_JIT_PREC_SQRT,
482512
cydriver.CUjit_option_enum.CU_JIT_FMA,
483-
cydriver.CUjit_option_enum.CU_JIT_OPTIMIZE_UNUSED_DEVICE_VARIABLES,):
513+
cydriver.CUjit_option_enum.CU_JIT_OPTIMIZE_UNUSED_DEVICE_VARIABLES,
514+
cydriver.CUjit_option_enum.CU_JIT_POSITION_INDEPENDENT_CODE,
515+
cydriver.CUjit_option_enum.CU_JIT_MAX_THREADS_PER_BLOCK,
516+
cydriver.CUjit_option_enum.CU_JIT_OVERRIDE_DIRECTIVE_VALUES,):
484517
self._int = init_value
485518
self._cptr = <void*><void_ptr>self._int
486519
elif self._attr in (cydriver.CUjit_option_enum.CU_JIT_CACHE_MODE,):
@@ -521,7 +554,9 @@ cdef class _HelperCudaJitOption:
521554
self._cptr = <void*><void_ptr>self._uint
522555
elif self._attr in (cyruntime.cudaJitOption.cudaJitWallTime,):
523556
self._float = init_value
524-
self._cptr = <void*><void_ptr>self._float
557+
# cudaJitWallTime is an OUT option: CUDA writes the elapsed float
558+
# back through the pointer.
559+
self._cptr = <void*>&self._float
525560
elif self._attr in (cyruntime.cudaJitOption.cudaJitInfoLogBuffer,
526561
cyruntime.cudaJitOption.cudaJitErrorLogBuffer):
527562
self._charstar = init_value
@@ -711,6 +746,12 @@ cdef class _HelperCUcoredumpSettings:
711746

712747
self._cptr = <void*>&self._bool
713748
self._size = sizeof(cpp_bool)
749+
elif self._attrib in (cydriver.CUcoredumpSettings_enum.CU_COREDUMP_GENERATION_FLAGS,):
750+
if self._is_getter == False:
751+
self._uint = init_value
752+
753+
self._cptr = <void*>&self._uint
754+
self._size = sizeof(unsigned int)
714755
else:
715756
raise TypeError('Unsupported attribute: {}'.format(attr.name))
716757

@@ -734,5 +775,7 @@ cdef class _HelperCUcoredumpSettings:
734775
cydriver.CUcoredumpSettings_enum.CU_COREDUMP_LIGHTWEIGHT,
735776
cydriver.CUcoredumpSettings_enum.CU_COREDUMP_ENABLE_USER_TRIGGER,):
736777
return self._bool
778+
elif self._attrib in (cydriver.CUcoredumpSettings_enum.CU_COREDUMP_GENERATION_FLAGS,):
779+
return self._uint
737780
else:
738781
raise TypeError('Unsupported attribute value: {}'.format(self._attrib))

‎cuda_bindings/tests/test_cuda.py‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,70 @@ def test_coredump_bool_uses_single_byte_storage():
655655
assert helper.pyObj() is False
656656

657657

658+
@pytest.mark.agent_authored(model="grok-4.7")
659+
def test_ffi_coverage_new_pointer_attributes():
660+
new_attrs = [
661+
driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_MAPPING_SIZE,
662+
driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_MEMORY_BLOCK_ID,
663+
driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_IS_HW_DECOMPRESS_CAPABLE,
664+
]
665+
for attr in new_attrs:
666+
helper = driver._HelperCUpointer_attribute(attr, 0, is_getter=True)
667+
assert helper.cptr != 0
668+
_ = helper.pyObj()
669+
670+
671+
@pytest.mark.agent_authored(model="grok-4.7")
672+
def test_ffi_coverage_mapping_base_addr():
673+
helper = driver._HelperCUpointer_attribute(
674+
driver.CUpointer_attribute.CU_POINTER_ATTRIBUTE_MAPPING_BASE_ADDR, 0, is_getter=True
675+
)
676+
assert helper.cptr != 0
677+
_ = helper.pyObj()
678+
679+
680+
@pytest.mark.agent_authored(model="grok-4.7")
681+
def test_ffi_coverage_new_mem_range_attributes():
682+
new_attrs = [
683+
driver.CUmem_range_attribute.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_TYPE,
684+
driver.CUmem_range_attribute.CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_ID,
685+
driver.CUmem_range_attribute.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_TYPE,
686+
driver.CUmem_range_attribute.CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_ID,
687+
]
688+
for attr in new_attrs:
689+
helper = driver._HelperCUmem_range_attribute(attr, 4)
690+
assert helper.cptr != 0
691+
assert helper.pyObj() == 0
692+
693+
694+
@pytest.mark.agent_authored(model="grok-4.7")
695+
def test_ffi_coverage_jit_option_new_int_attrs():
696+
"""These options encode the int value in the void* slot, so cptr is 1 when the value is 1."""
697+
new_int_attrs = [
698+
driver.CUjit_option.CU_JIT_POSITION_INDEPENDENT_CODE,
699+
driver.CUjit_option.CU_JIT_MAX_THREADS_PER_BLOCK,
700+
driver.CUjit_option.CU_JIT_OVERRIDE_DIRECTIVE_VALUES,
701+
]
702+
for attr in new_int_attrs:
703+
helper = driver._HelperCUjit_option(attr, 1)
704+
assert helper.cptr == 1
705+
706+
707+
@pytest.mark.agent_authored(model="grok-4.7")
708+
def test_ffi_coverage_jit_wall_time_pointer_is_valid():
709+
helper = driver._HelperCUjit_option(driver.CUjit_option.CU_JIT_WALL_TIME, 0.0)
710+
ctypes.c_float.from_address(helper.cptr).value = 3.14
711+
assert ctypes.c_float.from_address(helper.cptr).value == pytest.approx(3.14, rel=1e-5)
712+
713+
714+
@pytest.mark.agent_authored(model="grok-4.7")
715+
def test_ffi_coverage_coredump_generation_flags():
716+
helper = driver._HelperCUcoredumpSettings(driver.CUcoredumpSettings.CU_COREDUMP_GENERATION_FLAGS, 0, is_getter=True)
717+
assert helper.size() == ctypes.sizeof(ctypes.c_uint)
718+
ctypes.c_uint.from_address(helper.cptr).value = 0xDEAD
719+
assert helper.pyObj() == 0xDEAD
720+
721+
658722
def test_get_error_name_and_string():
659723
(err,) = cuda.cuInit(0)
660724
assert err == cuda.CUresult.CUDA_SUCCESS

‎cuda_bindings/tests/test_cudart.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,3 +1392,34 @@ def test_struct_pointer_comparison(target):
13921392
c = target(456)
13931393
assert a != c
13941394
assert hash(a) != hash(c)
1395+
1396+
1397+
@pytest.mark.agent_authored(model="grok-4.7")
1398+
def test_ffi_runtime_jit_wall_time_pointer_is_valid():
1399+
helper = runtime._HelperCudaJitOption(cudart.cudaJitOption.cudaJitWallTime, 0.0)
1400+
ctypes.c_float.from_address(helper.cptr).value = 3.14
1401+
assert ctypes.c_float.from_address(helper.cptr).value == pytest.approx(3.14, rel=1e-5)
1402+
1403+
1404+
@pytest.mark.agent_authored(model="grok-4.7")
1405+
def test_ffi_normalized_channel_kinds_construct():
1406+
"""Normalized kinds must be constructible. cudaMallocArray acceptance is device-dependent."""
1407+
pairs = [
1408+
(8, 0, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X1),
1409+
(8, 8, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X2),
1410+
(8, 8, 8, 8, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized8X4),
1411+
(8, 0, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X1),
1412+
(8, 8, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X2),
1413+
(8, 8, 8, 8, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized8X4),
1414+
(16, 0, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X1),
1415+
(16, 16, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X2),
1416+
(16, 16, 16, 16, cudart.cudaChannelFormatKind.cudaChannelFormatKindUnsignedNormalized16X4),
1417+
(16, 0, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X1),
1418+
(16, 16, 0, 0, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X2),
1419+
(16, 16, 16, 16, cudart.cudaChannelFormatKind.cudaChannelFormatKindSignedNormalized16X4),
1420+
]
1421+
for x, y, z, w, kind in pairs:
1422+
desc = cudart.cudaChannelFormatDesc()
1423+
desc.x, desc.y, desc.z, desc.w, desc.f = x, y, z, w, kind
1424+
assert desc.f == kind
1425+
assert desc.x == x

0 commit comments

Comments
 (0)