Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2f62cb1
initial
brandon-b-miller Mar 7, 2025
ec6bf1e
pass compute sanitizer on the python side
brandon-b-miller Mar 17, 2025
f52a15c
clean
brandon-b-miller Mar 19, 2025
4df687b
merge/resolve
brandon-b-miller Mar 19, 2025
01be5c2
reset files
brandon-b-miller Mar 19, 2025
0b23a09
check all ptx files in maybe_link_nrt
brandon-b-miller Mar 19, 2025
dd568e7
detect nrt in all linked ptx files
brandon-b-miller Mar 19, 2025
af9045d
read_file
brandon-b-miller Mar 24, 2025
f2e9b29
tests, fill out headerA
brandon-b-miller Mar 31, 2025
e4008d0
merge/resolve
brandon-b-miller Mar 31, 2025
e65088f
temp file
brandon-b-miller Mar 31, 2025
e1e6cc1
Merge branch 'main' into support-cudf-strings
brandon-b-miller Apr 2, 2025
5bd9b7a
move and rename read_file
brandon-b-miller Apr 2, 2025
e3042a6
Update numba_cuda/numba/cuda/tests/nrt/test_nrt.py
brandon-b-miller Apr 2, 2025
501b4da
get_include() in tests
brandon-b-miller Apr 2, 2025
ff478f4
handle LinkableCode
brandon-b-miller Apr 2, 2025
43b647b
convert to LinkableCode
brandon-b-miller Apr 7, 2025
297c43b
Merge branch 'main' into support-cudf-strings
brandon-b-miller Apr 7, 2025
eab1d9e
Revert "convert to LinkableCode"
brandon-b-miller Apr 7, 2025
5c0d87d
merge/resolve/pacify ruff
brandon-b-miller Apr 8, 2025
0dff0b6
style
brandon-b-miller Apr 8, 2025
11a014a
LinkableCode accepts nrt parameter
brandon-b-miller Apr 9, 2025
02ae604
merge/resolve
brandon-b-miller Apr 14, 2025
03cfd92
reorder steps in pynvjitlink wheel test job
brandon-b-miller Apr 14, 2025
613db4a
Update numba_cuda/numba/cuda/dispatcher.py
brandon-b-miller Apr 14, 2025
b05fbe8
dont leak memory, cleanup
brandon-b-miller Apr 15, 2025
5134e6c
cache nrt source
brandon-b-miller Apr 15, 2025
4e1329d
Merge branch 'main' into support-cudf-strings
brandon-b-miller Apr 21, 2025
a2aa31e
small fix
brandon-b-miller Apr 21, 2025
2edbe6a
reorder test build steps
brandon-b-miller Apr 21, 2025
47a45b4
Merge branch 'main' into support-cudf-strings
brandon-b-miller Apr 30, 2025
34b710d
partially address reviews
brandon-b-miller Apr 30, 2025
bd3da22
go back to regex check
brandon-b-miller Apr 30, 2025
dc9680b
small fix
brandon-b-miller Apr 30, 2025
71c280b
preserve nrt library through serialization
brandon-b-miller May 2, 2025
eaebb9a
pass full test suite with nrt and nvidia binding
brandon-b-miller May 2, 2025
d8469de
merge/resolve
brandon-b-miller May 2, 2025
dd35975
Merge remote-tracking branch 'NVIDIA/main' into support-cudf-strings
gmarkall May 3, 2025
ff12e16
drop autodetection of NRT in user supplied raw file paths
brandon-b-miller May 6, 2025
d893d2b
Apply suggestions from code review
brandon-b-miller May 6, 2025
e8659aa
Merge branch 'main' into support-cudf-strings
brandon-b-miller May 7, 2025
ad0a0a7
simplify and update docstring
brandon-b-miller May 7, 2025
19c6a56
small bugfix
brandon-b-miller May 7, 2025
50b61ac
reoder steps in final CI script
brandon-b-miller May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion numba_cuda/numba/cuda/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


def jit(func_or_sig=None, device=False, inline=False, link=[], debug=None,
opt=None, lineinfo=False, cache=False, **kws):
opt=None, lineinfo=False, cache=False, nrt=None, **kws):
"""
JIT compile a Python function for CUDA GPUs.

Expand Down Expand Up @@ -114,6 +114,7 @@ def _jit(func):
targetoptions['fastmath'] = fastmath
targetoptions['device'] = device
targetoptions['extensions'] = extensions
targetoptions['nrt'] = nrt

disp = CUDADispatcher(func, targetoptions=targetoptions)

Expand Down
33 changes: 16 additions & 17 deletions numba_cuda/numba/cuda/dispatcher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import numpy as np
import os
import re
import sys
import ctypes
import functools
Expand Down Expand Up @@ -115,8 +114,9 @@ class _Kernel(serialize.ReduceMixin):

@global_compiler_lock
def __init__(self, py_func, argtypes, link=None, debug=False,
lineinfo=False, inline=False, fastmath=False, extensions=None,
max_registers=None, lto=False, opt=True, device=False):
lineinfo=False, inline=False, fastmath=False,
extensions=None, max_registers=None, lto=False, opt=True,
device=False, nrt=None):

if device:
raise RuntimeError('Cannot compile a device function as a kernel')
Expand Down Expand Up @@ -179,6 +179,8 @@ def __init__(self, py_func, argtypes, link=None, debug=False,
if self.cooperative:
lib.needs_cudadevrt = True

self.nrt = nrt

def link_to_library_functions(library_functions, library_path,
prefix=None):
"""
Expand Down Expand Up @@ -234,21 +236,18 @@ def link_to_library_functions(library_functions, library_path,
self.reload_init = []

def maybe_link_nrt(self, link, tgt_ctx, asm):
if not tgt_ctx.enable_nrt:
if not tgt_ctx.enable_nrt or self.nrt is False:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want the nrt kwarg for the JIT decorator to take precedence over the global NRT setting for enabling it? I think this will never link the NRT if it is globally disabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation. I think the best behavior might be

  • kwarg takes precedence, allowing users definitive control over if the NRT code should be added to the link for a particular kernel
  • global flag enables the detection mechanism

But I'm not sure if numba's code generation will actually provide increfs/decrefs without enable_nrt set to true in the target context, is that correct? In that case we might be adding the refcounting functions to the link but not actually calling them.

The motivation for this kwarg is twofold: Where it came up was an edge case I observed in cuDF where an NRT managed object is created and immediately returned, such as in lambda string: return string. In this case it works out that NRT functions are used, but they only appear in the separately provided PTX file. The ASM that numba inspects when deciding to link NRT or not contains only the declarations for the parent functions that eventually call the NRT ones, so this defeats numba's NRT detection.

Overall I feel that unless the NRT detection is absolutely definitive somehow it might be more reliable to let the user decide when to link NRT. This has the drawback of creating two switches, one to enable the possiblity of NRT, and then a second one to actually add it to the link. But even that I think its a little better than somewhat shaky auto detection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ASM that numba inspects when deciding to link NRT or not contains only the declarations for the parent functions that eventually call the NRT ones, so this defeats numba's NRT detection.

Are you saying that numba-cuda doesn't link the NRT when it should? If so, then I would have seen that as a bug in numba-cuda?

Or, if it adds NRT to the asm when it's not necessary, we should be running the refcount pruning pass to elide those unnecessary NRT calls.

Is there a third situation I'm missing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re you saying that numba-cuda doesn't link the NRT when it should? If so, then I would have seen that as a bug in numba-cuda?

Yes, this is the case. It is the PTX file that is provided by cuDF that is not checked. The PTX from the numba side is checked, but doesn't contain the actual NRT calls - it only contains a call to a shim function that uses NRT functions within its implementation.

Initially I felt that since cuDF was somewhat burying the NRT calls maybe it should also be the one to signal to numba that the NRT implementations are also needed (or the same for any consuming library that does the same thing).

But I also see that it could be considered a bug in numba-cuda that all the input PTX files are not checked for NRT functions. What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we support using the NRT functions from external code, then ideally we should be checking for calls to NRT functions in external code rather than asking the user to do additional work - particularly if it requires signalling in the @cuda.jit decorator, because the person writing the jitted function can often be someone different to the person who implemented another library.

We've seen this problem with the link and extensions kwargs already, where libraries want to use these features, but then have to ask the users to remember to use them with no explicit connection between use of the library and the requirement to add the kwargs.

@brandon-b-miller brandon-b-miller Mar 19, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of the changes in 0b23a09 and dd568e7 ? Here we drop the kwarg and scan the ptx files at the expense of a double read of the same file, something theres probably an easy solution for.

@isVoid isVoid Apr 9, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for being late to the discussion.

particularly if it requires signalling in the @cuda.jit decorator, because the person writing the jitted function can often be someone different to the person who implemented another library.

If it's the library dev duty to specify nrt arg, how about adding it to the LinkableCode interface? The downside is that this cannot be specified if user would want to directly use a path to the link argument. Perhaps we can make that an unsupported case or simply deprecate passing in a raw path (and reintroduce it as a Path subclass to LinkableCode).

What let me to think of this is that 0b23a09 NRT discovery mechanism may not be able to handle binary format input such as LTOIR (disassembly could work but I think that's a too much price to pay).

I increasingly see that Numba as a compiler need to separate the duty from lib dev and lib user (kernel writer). And LinkableCode interface can be the perfect vehicle to separate those needs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's the library dev duty to specify nrt arg, how about adding it to the LinkableCode interface?

I think this sounds like a good idea.

The downside is that this cannot be specified if user would want to directly use a path to the link argument.

I think that's not too significant a downside. I see the provision of a path to link as a bit of a legacy anyway, because it's not very convenient - it's just what happened to be implemented first, a long time ago, perhaps before the API design had a lot of consideration.

Perhaps we can make that an unsupported case or simply deprecate passing in a raw path (and reintroduce it as a Path subclass to LinkableCode).

I think introducing a Path subclass might not fit exactly right, because the linker needs to know what type of object is being passed in. A helper function that determines the type based on the extension, reads it in, and then returns the appropriate LinkableCode subclass instance would probably be OK though. (Perhaps a class method LinkableCode.from_path(), maybe?).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Perhaps a class method LinkableCode.from_path(), maybe?).

I think that's a good design.

return

all_nrt = "|".join(self.NRT_functions)
pattern = (
r'\.extern\s+\.func\s+(?:\s*\(.+\)\s*)?('
+ all_nrt + r')\s*\([^)]*\)\s*;'
)

nrt_in_asm = re.findall(pattern, asm)

basedir = os.path.dirname(os.path.abspath(__file__))
if nrt_in_asm:
nrt_path = os.path.join(basedir, 'runtime', 'nrt.cu')
nrt_path = os.path.join(basedir, 'runtime', 'nrt.cu')

if self.nrt is True or (
self.nrt is None and any(fn in asm for fn in self.NRT_functions)
):
link.append(nrt_path)
if self.nrt is None:
self.nrt = True

@property
def library(self):
Expand All @@ -271,7 +270,7 @@ def argument_types(self):

@classmethod
def _rebuild(cls, cooperative, name, signature, codelibrary,
debug, lineinfo, call_helper, extensions):
debug, lineinfo, call_helper, extensions, nrt):
"""
Rebuild an instance.
"""
Expand All @@ -289,6 +288,7 @@ def _rebuild(cls, cooperative, name, signature, codelibrary,
instance.lineinfo = lineinfo
instance.call_helper = call_helper
instance.extensions = extensions
instance.nrt = nrt
return instance

def _reduce_states(self):
Expand All @@ -312,7 +312,7 @@ def bind(self):

if (
hasattr(self, "target_context")
and self.target_context.enable_nrt
and self.target_context.enable_nrt and self.nrt
and config.CUDA_NRT_STATS
):
rtsys.ensure_initialized()
Expand Down Expand Up @@ -721,7 +721,6 @@ class CUDADispatcher(Dispatcher, serialize.ReduceMixin):
def __init__(self, py_func, targetoptions, pipeline_class=CUDACompiler):
super().__init__(py_func, targetoptions=targetoptions,
pipeline_class=pipeline_class)

# The following properties are for specialization of CUDADispatchers. A
# specialized CUDADispatcher is one that is compiled for exactly one
# set of argument types, and bypasses some argument type checking for
Expand Down
16 changes: 2 additions & 14 deletions numba_cuda/numba/cuda/runtime/nrt.cu
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,8 @@
#include <cuda/atomic>

#include "memsys.cuh"
#include "nrt.cuh"

typedef void (*NRT_dtor_function)(void* ptr, size_t size, void* info);
typedef void (*NRT_dealloc_func)(void* ptr, void* dealloc_info);

typedef struct MemInfo NRT_MemInfo;

extern "C" {
struct MemInfo {
cuda::atomic<size_t, cuda::thread_scope_device> refct;
NRT_dtor_function dtor;
void* dtor_info;
void* data;
size_t size;
};
}

extern "C" __global__ void NRT_MemSys_set(NRT_MemSys *memsys_ptr)
{
Expand Down Expand Up @@ -177,6 +164,7 @@ extern "C" __device__ void NRT_decref(NRT_MemInfo* mi)
}
}


#endif

extern "C" __device__ void NRT_incref(NRT_MemInfo* mi)
Expand Down
23 changes: 23 additions & 0 deletions numba_cuda/numba/cuda/runtime/nrt.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <cuda/atomic>

typedef void (*NRT_dtor_function)(void* ptr, size_t size, void* info);
typedef void (*NRT_dealloc_func)(void* ptr, void* dealloc_info);

extern "C"
struct MemInfo {
cuda::atomic<size_t, cuda::thread_scope_device> refct;
NRT_dtor_function dtor;
void* dtor_info;
void* data;
size_t size;
};
typedef struct MemInfo NRT_MemInfo;

extern "C" __device__ void* NRT_Allocate(size_t size);
extern "C" __device__ void NRT_MemInfo_init(NRT_MemInfo* mi,
void* data,
size_t size,
NRT_dtor_function dtor,
void* dtor_info);
extern "C" __device__ void NRT_decref(NRT_MemInfo* mi);
extern "C" __device__ void NRT_print_refct(NRT_MemInfo* mi);