-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add support for the Arrow device capsule interfaces #15370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c4b80f1
911d3b7
7fd9863
a8bf16c
ff21354
4a3d906
6e0b4dc
f05f075
cf50a87
167762b
1cd438d
736da98
f015e2a
22c8a4c
ab46669
b57124f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,19 +15,21 @@ from libcpp.utility cimport move | |
|
|
||
| from pylibcudf.libcudf.column.column cimport column, column_contents | ||
| from pylibcudf.libcudf.column.column_factories cimport make_column_from_scalar | ||
| from pylibcudf.libcudf.interop cimport ArrowArray, ArrowSchema, arrow_column | ||
| from pylibcudf.libcudf.scalar.scalar cimport scalar, numeric_scalar | ||
| from pylibcudf.libcudf.types cimport size_type, size_of as cpp_size_of, bitmask_type | ||
| from pylibcudf.libcudf.utilities.traits cimport is_fixed_width | ||
| from pylibcudf.libcudf.copying cimport get_element | ||
|
|
||
| from pylibcudf.libcudf.interop cimport ( | ||
| ArrowArray, | ||
| ArrowSchema, | ||
| ArrowDeviceArray, | ||
| arrow_column, | ||
| column_metadata, | ||
| to_arrow_host_raw, | ||
| to_arrow_device_raw, | ||
| to_arrow_schema_raw, | ||
| ) | ||
| from pylibcudf.libcudf.scalar.scalar cimport scalar, numeric_scalar | ||
| from pylibcudf.libcudf.types cimport size_type, size_of as cpp_size_of, bitmask_type | ||
| from pylibcudf.libcudf.utilities.traits cimport is_fixed_width | ||
| from pylibcudf.libcudf.copying cimport get_element | ||
|
|
||
|
|
||
| from rmm.librmm.device_buffer cimport device_buffer | ||
| from rmm.pylibrmm.device_buffer cimport DeviceBuffer | ||
|
|
@@ -40,6 +42,7 @@ from .types cimport DataType, size_of, type_id | |
| from ._interop_helpers cimport ( | ||
| _release_schema, | ||
| _release_array, | ||
| _release_device_array, | ||
| _metadata_to_libcudf, | ||
| ) | ||
| from .null_mask cimport bitmask_allocation_size_bytes | ||
|
|
@@ -55,7 +58,12 @@ __all__ = ["Column", "ListColumnView", "is_c_contiguous"] | |
|
|
||
| class _ArrowLikeMeta(type): | ||
| def __subclasscheck__(cls, other): | ||
| return hasattr(other, "__arrow_c_array__") | ||
| # We cannot separate these types via singledispatch because the dispatch | ||
| # will often be ambiguous when objects expose multiple protocols. | ||
| return ( | ||
| hasattr(other, "__arrow_c_array__") | ||
| or hasattr(other, "__arrow_c_device_array__") | ||
| ) | ||
|
|
||
|
|
||
| class _ArrowLike(metaclass=_ArrowLikeMeta): | ||
|
|
@@ -207,32 +215,59 @@ cdef class Column: | |
|
|
||
| @_init.register(_ArrowLike) | ||
| def _(self, arrow_like): | ||
| schema, array = arrow_like.__arrow_c_array__() | ||
| cdef ArrowSchema* c_schema = ( | ||
| <ArrowSchema*>PyCapsule_GetPointer(schema, "arrow_schema") | ||
| ) | ||
| cdef ArrowArray* c_array = ( | ||
| <ArrowArray*>PyCapsule_GetPointer(array, "arrow_array") | ||
| ) | ||
|
|
||
| cdef _ArrowColumnHolder result = _ArrowColumnHolder() | ||
| cdef ArrowSchema* c_schema | ||
| cdef ArrowArray* c_array | ||
| cdef ArrowDeviceArray* c_device_array | ||
| cdef _ArrowColumnHolder result | ||
| cdef unique_ptr[arrow_column] c_result | ||
| with nogil: | ||
| c_result = make_unique[arrow_column]( | ||
| move(dereference(c_schema)), move(dereference(c_array)) | ||
| if hasattr(arrow_like, "__arrow_c_device_array__"): | ||
| schema, array = arrow_like.__arrow_c_device_array__() | ||
| c_schema = <ArrowSchema*>PyCapsule_GetPointer(schema, "arrow_schema") | ||
| c_device_array = ( | ||
| <ArrowDeviceArray*>PyCapsule_GetPointer(array, "arrow_device_array") | ||
| ) | ||
|
|
||
| result = _ArrowColumnHolder() | ||
| with nogil: | ||
| c_result = make_unique[arrow_column]( | ||
| move(dereference(c_schema)), move(dereference(c_device_array)) | ||
| ) | ||
| result.col.swap(c_result) | ||
|
|
||
| tmp = Column.from_column_view_of_arbitrary(result.col.get().view(), result) | ||
| self._init( | ||
| tmp.type(), | ||
| tmp.size(), | ||
| tmp.data(), | ||
| tmp.null_mask(), | ||
| tmp.null_count(), | ||
| tmp.offset(), | ||
| tmp.children(), | ||
| ) | ||
| elif hasattr(arrow_like, "__arrow_c_array__"): | ||
| schema, array = arrow_like.__arrow_c_array__() | ||
| c_schema = <ArrowSchema*>PyCapsule_GetPointer(schema, "arrow_schema") | ||
| c_array = <ArrowArray*>PyCapsule_GetPointer(array, "arrow_array") | ||
|
|
||
| result = _ArrowColumnHolder() | ||
| with nogil: | ||
| c_result = make_unique[arrow_column]( | ||
| move(dereference(c_schema)), move(dereference(c_array)) | ||
| ) | ||
| result.col.swap(c_result) | ||
|
|
||
| tmp = Column.from_column_view_of_arbitrary(result.col.get().view(), result) | ||
| self._init( | ||
| tmp.type(), | ||
| tmp.size(), | ||
| tmp.data(), | ||
| tmp.null_mask(), | ||
| tmp.null_count(), | ||
| tmp.offset(), | ||
| tmp.children(), | ||
| ) | ||
| tmp = Column.from_column_view_of_arbitrary(result.col.get().view(), result) | ||
| self._init( | ||
| tmp.type(), | ||
| tmp.size(), | ||
| tmp.data(), | ||
| tmp.null_mask(), | ||
| tmp.null_count(), | ||
| tmp.offset(), | ||
| tmp.children(), | ||
| ) | ||
| else: | ||
| raise ValueError("Invalid Arrow-like object") | ||
|
|
||
| cdef column_view view(self) nogil: | ||
| """Generate a libcudf column_view to pass to libcudf algorithms. | ||
|
|
@@ -752,12 +787,37 @@ cdef class Column: | |
|
|
||
| return PyCapsule_New(<void*>raw_host_array_ptr, "arrow_array", _release_array) | ||
|
|
||
| def _to_device_array(self): | ||
| cdef ArrowDeviceArray* raw_device_array_ptr | ||
| with nogil: | ||
| raw_device_array_ptr = to_arrow_device_raw(self.view(), self) | ||
|
|
||
| return PyCapsule_New( | ||
| <void*>raw_device_array_ptr, | ||
| "arrow_device_array", | ||
| _release_device_array | ||
| ) | ||
|
|
||
| def __arrow_c_array__(self, requested_schema=None): | ||
| if requested_schema is not None: | ||
| raise ValueError("pylibcudf.Column does not support alternative schema") | ||
|
|
||
| return self._to_schema(), self._to_host_array() | ||
|
|
||
| def __arrow_c_device_array__(self, requested_schema=None, **kwargs): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nearly identical to the method for table. Maybe factor out? Same for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we could consider consolidating more. I'm not sure what the best way to do that is right now. Maybe we need some more common helper functions for this. It gets a bit tricky with the Cython typing though. |
||
| if requested_schema is not None: | ||
| raise ValueError("pylibcudf.Column does not support alternative schema") | ||
|
|
||
| non_default_kwargs = [ | ||
| name for name, value in kwargs.items() if value is not None | ||
| ] | ||
| if non_default_kwargs: | ||
| raise NotImplementedError( | ||
| f"Received unsupported keyword argument(s): {non_default_kwargs}" | ||
| ) | ||
|
|
||
| return self._to_schema(), self._to_device_array() | ||
|
|
||
|
|
||
| cdef class ListColumnView: | ||
| """Accessor for methods of a Column that are specific to lists.""" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the changes in dependencies.yaml (I deleted a bunch of relevant comments).