[Numpy-discussion] Getting C-function pointers from Python to C

Travis Oliphant travis at continuum.io
Mon Apr 9 20:57:42 EDT 2012


On Apr 9, 2012, at 7:21 PM, Nathaniel Smith wrote:

> ...isn't this an operation that will be performed once per compiled function? Is the overhead of the easy, robust method (calling ctypes.cast) actually measurable as compared to, you know, running an optimizing compiler?
> 
> 

Yes, there can be significant overhead.   The compiler is run once and creates the function.   This function is then potentially used many, many times.    Also, it is entirely conceivable that the "build" step happens at a separate "compilation" time, and Numba actually loads a pre-compiled version of the function from disk which it then uses at run-time.    

I have been playing with a version of this using scipy.integrate and unfortunately the overhead of ctypes.cast is rather significant --- to the point of making the code-path using these function pointers to be useless when without the ctypes.cast overhed the speed up is 3-5x. 

In general, I think NumPy will need its own simple function-pointer object to use when handing over raw-function pointers between Python and C.   SciPy can then re-use this object which also has a useful C-API for things like signature checking.    I have seen that ctypes is nice but very slow and without a compelling C-API. 


The kind of new C-level cfuncptr object I imagine has attributes: 

	void *func_ptr;
	char *signature string  /* something like 'dd->d' to indicate a function that takes two doubles and returns a double */

methods would be:

	from_ctypes  (classmethod)
	to_ctypes 
	
and simple inline functions to get the function pointer and the signature. 
	
> I mean, I doubt there'd be any real problem with adding this extra API to numpy, but it does seem like there might be higher priority targets :-)
> 
> 

Not if you envision doing a lot of code-development using Numba ;-)

-Travis




> On Apr 10, 2012 1:12 AM, "Travis Oliphant" <teoliphant at gmail.com> wrote:
> Hi all,
> 
> Some of you are aware of Numba.   Numba allows you to create the equivalent of C-function's dynamically from Python.   One purpose of this system is to allow NumPy to take these functions and use them in operations like ufuncs, generalized ufuncs, file-reading, fancy-indexing, and so forth.  There are actually many use-cases that one can imagine for such things.
> 
> One question is how do you pass this function pointer to the C-side.    On the Python side, Numba allows you to get the raw integer address of the equivalent C-function pointer that it just created out of the Python code.    One can think of this as a 32- or 64-bit integer that you can cast to a C-function pointer.
> 
> Now, how should this C-function pointer be passed from Python to NumPy?   One approach is just to pass it as an integer --- in other words have an API in C that accepts an integer as the first argument that the internal function interprets as a C-function pointer.
> 
> This is essentially what ctypes does when creating a ctypes function pointer out of:
> 
>  func = ctypes.CFUNCTYPE(restype, *argtypes)(integer)
> 
> Of course the problem with this is that you can easily hand it integers which don't make sense and which will cause a segfault when control is passed to this "function"
> 
> We could also piggy-back on-top of Ctypes and assume that a ctypes function-pointer object is passed in.   This allows some error-checking at least and also has the benefit that one could use ctypes to access a c-function library where these functions were defined. I'm leaning towards this approach.
> 
> Now, the issue is how to get the C-function pointer (that npy_intp integer) back and hand it off internally.   Unfortunately, ctypes does not make it very easy to get this address (that I can see).    There is no ctypes C-API, for example.    There are two potential options:
> 
>        1) Create an API for such Ctypes function pointers in NumPy and use the ctypes object structure.  If ctypes were to ever change it's object structure we would have to adapt this API.
> 
>        Something like this is what is envisioned here:
> 
>             typedef struct {
>                        PyObject_HEAD
>                        char *b_ptr;
>             } _cfuncptr_object;
> 
>        then the function pointer is:
> 
>            (*((void **)(((_sp_cfuncptr_object *)(obj))->b_ptr)))
> 
>        which could be wrapped-up into a nice little NumPy C-API call like
> 
>        void * Npy_ctypes_funcptr(obj)
> 
> 
>        2) Use the Python API of ctypes to do the same thing.   This has the advantage of not needing to mirror the simple _cfuncptr_object structure in NumPy but it is *much* slower to get the address.   It basically does the equivalent of
> 
>        ctypes.cast(obj, ctypes.c_void_p).value
> 
> 
>        There is working code for this in the ctypes_callback branch of my scipy fork on github.
> 
> 
> I would like to propose two things:
> 
>        * creating a Npy_ctypes_funcptr(obj) function in the C-API of NumPy and
>        * implement it with the simple pointer dereference above (option #1)
> 
> 
> Thoughts?
> 
> -Travis
> 
> 
> 
> 
> 
> 
> 
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20120409/da077c7c/attachment.html>


More information about the NumPy-Discussion mailing list