Passing pointer from c++ to python

Hi
To pass CPU pointer from c++ to python numpy I am using this code
np_arg = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(ND, dims, NPY_LONGDOUBLE, reinterpret_cast<void*>(c_arr)));

My question is how to pass c++ GPU pointer to python numba ?
Thanks

You need to wrap the pointer value in an object that implements the CUDA Array Interface. The interface needs more than just the pointer - it also needs to know the shape and type of the data so you will have to provide that in your implementation as well.

Here’s an example of a simple object implementing the interface. MyArray wraps a pointer obtained from cudaMalloc (though it could have come from anywhere, a C++ function, etc.):

from numba import cuda
from ctypes import CDLL, POINTER, byref, c_void_p, c_size_t
import cupy as cp


class MyArray:
    def __init__(self, shape, typestr, data):
        if isinstance(shape, int):
            shape = (shape,)

        self._shape = shape
        self._data = data
        self._typestr = typestr

    @property
    def __cuda_array_interface__(self):
        return {
            'shape': self._shape,
            'typestr': self._typestr,
            'data': (self._data, False),
            'version': 2
        }


# Use ctypes to get the cudaMalloc function from Python
cudart = CDLL('libcudart.so')
cudaMalloc = cudart.cudaMalloc
cudaMalloc.argtypes = [POINTER(c_void_p), c_size_t]

# Allocate some Numba-external memory with cudaMalloc
ptr = c_void_p()
float32_size = 4
nelems = 32
alloc_size = float32_size * nelems
cudaMalloc(byref(ptr), alloc_size)

# Wrap our memory in a CUDA Array Interface object
arr = MyArray(nelems, 'f4', ptr.value)


# Call a kernel on our object wrapping the pointer

@cuda.jit
def initialize(x):
    i = cuda.grid(1)
    if i < len(x):
        x[i] = 3.14


initialize[1, nelems](arr)


# Use CuPy for a convenient way to print our data to show that the kernel
# initialized it
print(cp.asarray(arr))

This produces:

[3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14
 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14 3.14
 3.14 3.14 3.14 3.14]

There is some more background on this in https://raw.githubusercontent.com/numba/nvidia-cuda-tutorial/main/session-3/session-3-with-notes.pdf (session 3 from the NVIDIA Numba CUDA tutorial) - see slides 33-35.

I’ve now added the above code as an example in that repo: nvidia-cuda-tutorial/cai_implementation.py at main · numba/nvidia-cuda-tutorial · GitHub

Hi Graham
Thanks for quick response.
I have code in c++ that create numpy.ndarray CPU pointer and send it to python .

np_arg = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(ND, dims, NPY_LONGDOUBLE, reinterpret_cast<void*>(c_arr)));
presult = PyObject_CallObject(pFunc, pArgs);

The pointer np_arg is numpy.ndarray type
I want to create in the c++ code numpy.ndarray GPU pointer and pass it to python ,what is the correct way?

I think I’m still not sure what you’re attempting to do. What do you mean by “numpy.ndarray GPU pointer”? Do you want a CUDA device array? Further down that page there are also ways to allocate Pinned Memory and Unified Memory, and for mapping an existing ndarray into GPU memory. Do any of these look like what you need?

Hi Graham
I want to send GPU vector from c++ to python numba.
to send CPU array is very easy
example

first declare and init
double c_arr[SIZE] = { 1, 2, 3, 4, 5,6,7,8,9};
second
np_arg = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNewFromData(1, &dims, getType(), reinterpret_cast<void*>(data)));
This line create numpy.ndarray
and then I can send it to python
presult = PyObject_CallObject(pFunc, pArgs);
Now is the problem
Instead of CPU double array c_arr[SIZE] = { 1, 2, 3, 4, 5,6,7,8,9};
I am creating GPU array
double * in_d;
cudaMalloc((void**)&in_d, SIZEsizeof(double));
cudaMemcpy(in_d, data, SIZE
sizeof(double), cudaMemcpyHostToDevice);
I want to send in_d to python
How can I do it?
Thanks
Razi

Perhaps you can create a Python int from the pointer with PyLong_FromVoidPtr() to send over to the Python side, then pass that to the constructor of a MyArray-like object (from the example above).

Thanks
it’s working fine

1 Like