afnumpy icon indicating copy to clipboard operation
afnumpy copied to clipboard

Feature request

Open aryabhatt opened this issue 8 years ago • 9 comments

Hi,

Could you overload the ndarray constructor, so that one can a pass raw pointer on device to create an instance, along with shape, dtype etc?

--dinesh

aryabhatt avatar Mar 17 '16 15:03 aryabhatt

You can pass raw arrayfire arrays, and take advantage of them to achieve what you want:

import arrayfire
import numpy
import afnumpy
import ctypes

# I'm assuming device_ptr is the raw pointer, pointing to a float array of size [1024,1024]
s = arrayfire.Array()
ndims = 2
dims = numpy.zeros(ndims,dtype=numpy.int64)
dims[0] = 1024
dims[1] = 1024
arrayfire.backend.get().af_device_array(ctypes.pointer(s.arr),
                                            ctypes.c_void_p(device_ptr),
                                            ndims, ctypes.c_void_p(dims.ctypes.data),
                                            arrayfire.Dtype.f32.value)
arrayfire.backend.get().af_retain_array(ctypes.pointer(s.arr),s.arr)
A = afnumpy.multiarray.ndarray(dims, dtype=dtype, af_array=s)
# Now it's safe to delete s

But I agree that a simpler way would be desirable. I'll try to add one that fits well with the rest of the interface.

FilipeMaia avatar Mar 18 '16 09:03 FilipeMaia

I am trying to create a afnumpy array from C as a return object. I have to create arrayfire array before I can do this. I would be nicer, if a method could take a buffer on device (plus other meta data) and create an afnumpy object.

aryabhatt avatar Mar 19 '16 19:03 aryabhatt

I've made it possible to call afnumpy.array() on an arrayfire array. I'll probably try to add a cuda_buffer argument to ndarray to pass raw device memory.

FilipeMaia avatar Mar 29 '16 21:03 FilipeMaia

Thanks a lot.

aryabhatt avatar Mar 29 '16 22:03 aryabhatt

Commit 59ae6b2 adds a buffer_type argument to the ndarray constructor making it possible to pass raw pointers directly. buffer_type defaults to python in which case buffer is a normal python buffer, but it can also be cpu, opencl or cuda, in which case buffer should be a pointer to memory of the corresponding type. In case of raw pointers the buffer_type must match the active arrayfire backend or an exception is raised.

Example usage:

import arrayfire as af
import afnumpy as afnp
a = af.randu(3,2)
shape = a.dims()[::-1]
c = afnp.ndarray(shape, dtype='f', buffer=a.raw_ptr(), buffer_type=af.get_active_backend())
print a
# The next line also modifies a, as they share the same memory
c[0,0] = -1
print a

FilipeMaia avatar Apr 02 '16 20:04 FilipeMaia

Hi Filipe,

Thanks a lot. I like that you put the "buffer_type" as the last argument.

regards --dinesh

On Sat, Apr 2, 2016 at 1:32 PM, Filipe Maia [email protected] wrote:

Commit 59ae6b2 https://github.com/FilipeMaia/afnumpy/commit/59ae6b2f8e096fe373bd9ffb0a57fd03b4cb3f30 adds a buffer_type argument to the ndarray constructor making it possible to pass raw pointers directly. buffer_type defaults to python in which case buffer is a normal python buffer, but it can also be cpu, opencl or cuda, in which case buffer should be a pointer to memory of the corresponding type. In case of raw pointers the buffer_type must match the active arrayfire backend or an exception is raised.

Example usage:

import arrayfire as afimport afnumpy as afnp a = af.randu(3,2) shape = a.dims()[::-1] c = afnp.ndarray(shape, dtype='f', buffer=a.raw_ptr(), buffer_type=af.get_active_backend())print a# The next line also modifies a, as they share the same memory c[0,0] = -1print a

— You are receiving this because you modified the open/close state. Reply to this email directly or view it on GitHub https://github.com/FilipeMaia/afnumpy/issues/20#issuecomment-204802086

aryabhatt avatar Apr 04 '16 16:04 aryabhatt

Hi Filipe,

I am working on C-API for Afnumpy. I am returning afnumpy array constructed using the

  afnumpy.ndarray(shape, buffer=ptr  buffer_type='cuda') 

arguments, with buffer being allocated inside the C-code. When the returned array goes out of scope, it seems the memory is not being released.

Does that sound normal to you?

  PyObject * args = PyTuple_New(1); 
  PyTuple_SetItem(args, 0, shape); 
  PyObject * kwargs = PyDict_New();
  PyObject * key = Py_BuildValue("s", "buffer");
  PyObject * val = PyLong_FromVoidPtr(buffer);
  PyDict_SetItem(kwargs, key, val);
  key = Py_BuildValue("s", "buffer_type");
  val = Py_BuildValue("s", "cuda");
  PyDict_SetItem(kwargs, key, val);
  key = Py_BuildValue("s", "dtype");
  PyDict_SetItem(kwargs, key, af_type);
  PyObject *out = PyObject_Call(ndarray, args, kwargs);`

aryabhatt avatar Oct 27 '16 04:10 aryabhatt

Yes this is how it currently works as people often want to continue to do work on the memory after the array is deleted. This is the same behaviour as with numpy when buffers are passed.

FilipeMaia avatar Oct 27 '16 17:10 FilipeMaia

I can understand the usefulness of increasing the reference count. Unfortunately, it is causing lots of problem for us. Since the af_array created the constructor has no external reference, there is no way to explicitly release it. Will it be possible to make either of the following modifications?

  1. Remove the af_retain_array in the constructor. It is unlikely that someone would want to create an Afnumpy array from a C pointer, within Python.
  2. Accept an optional boolean, which allows Afnumpy array steal the ownership or not. This will not be elegant since constructor already has so many arguments.
  3. Define a factory method, which will allow me to create an Afnumpy array from C.

aryabhatt avatar Oct 28 '16 05:10 aryabhatt