Skip to content

Commit 5da5bbe

Browse files
authored
Use public pylibcudf APIs in graph_primtypes (#5036)
`graph_primtypes` currently uses private cuDF Python APIs to construct a cuDF Python column from a pointer to an RMM buffer. After rapidsai/cudf#18502 is merged, this can be constructed using public pylibcudf methods. Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - Rick Ratzel (https://github.com/rlratzel) - James Lamb (https://github.com/jameslamb) URL: #5036
1 parent 0dc1837 commit 5da5bbe

10 files changed

+118
-28
lines changed

ci/release/update-version.sh

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ DEPENDENCIES=(
5959
libcugraph-tests
6060
libraft
6161
librmm
62+
pylibcudf
6263
pylibcugraph
6364
pylibwholegraph
6465
pylibraft

conda/environments/all_cuda-118_arch-aarch64.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ dependencies:
4545
- pre-commit
4646
- pydantic
4747
- pydata-sphinx-theme
48+
- pylibcudf==25.6.*,>=0.0.0a0
4849
- pylibraft==25.6.*,>=0.0.0a0
4950
- pylibwholegraph==25.6.*,>=0.0.0a0
5051
- pytest

conda/environments/all_cuda-118_arch-x86_64.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ dependencies:
4545
- pre-commit
4646
- pydantic
4747
- pydata-sphinx-theme
48+
- pylibcudf==25.6.*,>=0.0.0a0
4849
- pylibraft==25.6.*,>=0.0.0a0
4950
- pylibwholegraph==25.6.*,>=0.0.0a0
5051
- pytest

conda/environments/all_cuda-128_arch-aarch64.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies:
5050
- pre-commit
5151
- pydantic
5252
- pydata-sphinx-theme
53+
- pylibcudf==25.6.*,>=0.0.0a0
5354
- pylibraft==25.6.*,>=0.0.0a0
5455
- pylibwholegraph==25.6.*,>=0.0.0a0
5556
- pytest

conda/environments/all_cuda-128_arch-x86_64.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies:
5050
- pre-commit
5151
- pydantic
5252
- pydata-sphinx-theme
53+
- pylibcudf==25.6.*,>=0.0.0a0
5354
- pylibraft==25.6.*,>=0.0.0a0
5455
- pylibwholegraph==25.6.*,>=0.0.0a0
5556
- pytest

conda/recipes/cugraph/recipe.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ requirements:
6060
- cython >=3.0.3
6161
- libcugraph =${{ version }}
6262
- pip
63+
- pylibcudf =${{ minor_version }}
6364
- pylibraft =${{ minor_version }}
6465
- python =${{ py_version }}
6566
- raft-dask =${{ minor_version }}
@@ -80,6 +81,7 @@ requirements:
8081
- dask-cudf =${{ minor_version }}
8182
- fsspec>=0.6.0
8283
- libcugraph =${{ version }}
84+
- pylibcudf =${{ minor_version }}
8385
- pylibcugraph =${{ version }}
8486
- pylibraft =${{ minor_version }}
8587
- python

dependencies.yaml

+27
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ files:
1818
- depends_on_libcudf
1919
- depends_on_libraft
2020
- depends_on_librmm
21+
- depends_on_pylibcudf
2122
- depends_on_pylibraft
2223
- depends_on_pylibwholegraph
2324
- depends_on_pytorch
@@ -122,6 +123,7 @@ files:
122123
- depends_on_dask_cuda
123124
- depends_on_dask_cudf
124125
- depends_on_libcugraph
126+
- depends_on_pylibcudf
125127
- depends_on_pylibcugraph
126128
- depends_on_pylibraft
127129
- depends_on_raft_dask
@@ -750,6 +752,31 @@ dependencies:
750752
- rmm-cu11==25.6.*,>=0.0.0a0
751753
- {matrix: null, packages: [*rmm_unsuffixed]}
752754

755+
depends_on_pylibcudf:
756+
common:
757+
- output_types: conda
758+
packages:
759+
- &pylibcudf_unsuffixed pylibcudf==25.6.*,>=0.0.0a0
760+
- output_types: requirements
761+
packages:
762+
# pip recognizes the index as a global option for the requirements.txt file
763+
- --extra-index-url=https://pypi.nvidia.com
764+
- --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple
765+
specific:
766+
- output_types: [requirements, pyproject]
767+
matrices:
768+
- matrix:
769+
cuda: "12.*"
770+
cuda_suffixed: "true"
771+
packages:
772+
- pylibcudf-cu12==25.6.*,>=0.0.0a0
773+
- matrix:
774+
cuda: "11.*"
775+
cuda_suffixed: "true"
776+
packages:
777+
- pylibcudf-cu11==25.6.*,>=0.0.0a0
778+
- {matrix: null, packages: [*pylibcudf_unsuffixed]}
779+
753780
depends_on_cudf:
754781
common:
755782
- output_types: conda

python/cugraph/cugraph/structure/graph_primtypes.pxd

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2019-2024, NVIDIA CORPORATION.
1+
# Copyright (c) 2019-2025, NVIDIA CORPORATION.
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -154,8 +154,17 @@ ctypedef GraphCOOView[int,int,double] GraphCOOViewDouble
154154
ctypedef GraphCSRView[int,int,float] GraphCSRViewFloat
155155
ctypedef GraphCSRView[int,int,double] GraphCSRViewDouble
156156

157-
cdef move_device_buffer_to_column(unique_ptr[device_buffer] device_buffer_unique_ptr, dtype)
158-
cdef move_device_buffer_to_series(unique_ptr[device_buffer] device_buffer_unique_ptr, dtype, series_name)
157+
cdef move_device_buffer_to_column(
158+
unique_ptr[device_buffer] device_buffer_unique_ptr,
159+
dtype,
160+
size_t itemsize,
161+
)
162+
cdef move_device_buffer_to_series(
163+
unique_ptr[device_buffer] device_buffer_unique_ptr,
164+
dtype,
165+
size_t itemsize,
166+
series_name,
167+
)
159168
cdef coo_to_df(GraphCOOPtrType graph)
160169
cdef csr_to_series(GraphCSRPtrType graph)
161170
cdef GraphCOOViewFloat get_coo_float_graph_view(input_graph, bool weighted=*)

python/cugraph/cugraph/structure/graph_primtypes.pyx

+71-25
Original file line numberDiff line numberDiff line change
@@ -16,61 +16,93 @@
1616
# cython: embedsignature = True
1717
# cython: language_level = 3
1818

19-
import numpy as np
2019
from libc.stdint cimport uintptr_t
2120
from libcpp.utility cimport move
2221

2322
from rmm.pylibrmm.device_buffer cimport DeviceBuffer
24-
from cudf.core.buffer import as_buffer
23+
import pylibcudf
2524
import cudf
2625

2726

2827
cdef move_device_buffer_to_column(
29-
unique_ptr[device_buffer] device_buffer_unique_ptr, dtype):
28+
unique_ptr[device_buffer] device_buffer_unique_ptr,
29+
dtype,
30+
size_t itemsize,
31+
):
3032
"""
3133
Transfers ownership of device_buffer_unique_ptr to a cuDF buffer which is
3234
used to construct a cudf column object, which is then returned. If the
3335
intermediate buffer is empty, the device_buffer_unique_ptr is still
3436
transfered but None is returned.
3537
"""
36-
buff = DeviceBuffer.c_from_unique_ptr(move(device_buffer_unique_ptr))
37-
buff = as_buffer(buff)
38-
if buff.nbytes != 0:
39-
column = cudf.core.column.build_column(buff, dtype=cudf.dtype(dtype))
40-
return column
38+
cdef size_t buff_size = device_buffer_unique_ptr.get().size()
39+
cdef DeviceBuffer buff = DeviceBuffer.c_from_unique_ptr(move(device_buffer_unique_ptr))
40+
cdef size_t col_size = buff_size // itemsize
41+
result_column = pylibcudf.Column.from_rmm_buffer(
42+
buff,
43+
dtype,
44+
col_size,
45+
[],
46+
)
47+
if buff_size != 0:
48+
return result_column
4149
return None
4250

4351

4452
cdef move_device_buffer_to_series(
45-
unique_ptr[device_buffer] device_buffer_unique_ptr, dtype, series_name):
53+
unique_ptr[device_buffer] device_buffer_unique_ptr,
54+
dtype,
55+
size_t itemsize,
56+
series_name
57+
):
4658
"""
4759
Transfers ownership of device_buffer_unique_ptr to a cuDF buffer which is
4860
used to construct a cudf.Series object with name series_name, which is then
4961
returned. If the intermediate buffer is empty, the device_buffer_unique_ptr
5062
is still transfered but None is returned.
5163
"""
52-
column = move_device_buffer_to_column(move(device_buffer_unique_ptr), dtype)
64+
column = move_device_buffer_to_column(
65+
move(device_buffer_unique_ptr),
66+
dtype,
67+
itemsize,
68+
)
5369
if column is not None:
54-
series = cudf.Series._from_data({series_name: column})
55-
return series
70+
return cudf.Series.from_pylibcudf(column, metadata={"name": series_name})
5671
return None
5772

5873

5974
cdef coo_to_df(GraphCOOPtrType graph):
6075
# FIXME: this function assumes columns named "src" and "dst" and can only
6176
# be used for SG graphs due to that assumption.
6277
contents = move(graph.get()[0].release())
63-
src = move_device_buffer_to_column(move(contents.src_indices), "int32")
64-
dst = move_device_buffer_to_column(move(contents.dst_indices), "int32")
78+
src = move_device_buffer_to_series(
79+
move(contents.src_indices),
80+
pylibcudf.DataType(pylibcudf.TypeId.INT32),
81+
4,
82+
None,
83+
)
84+
dst = move_device_buffer_to_series(
85+
move(contents.dst_indices),
86+
pylibcudf.DataType(pylibcudf.TypeId.INT32),
87+
4,
88+
None,
89+
)
6590

6691
if GraphCOOPtrType is GraphCOOPtrFloat:
67-
weight_type = "float32"
92+
weight_type = pylibcudf.DataType(pylibcudf.TypeId.FLOAT32)
93+
itemsize = 4
6894
elif GraphCOOPtrType is GraphCOOPtrDouble:
69-
weight_type = "float64"
95+
weight_type = pylibcudf.DataType(pylibcudf.TypeId.FLOAT64)
96+
itemsize = 8
7097
else:
7198
raise TypeError("Invalid GraphCOOPtrType")
7299

73-
wgt = move_device_buffer_to_column(move(contents.edge_data), weight_type)
100+
wgt = move_device_buffer_to_series(
101+
move(contents.edge_data),
102+
weight_type,
103+
itemsize,
104+
None,
105+
)
74106

75107
df = cudf.DataFrame()
76108
df['src'] = src
@@ -83,20 +115,34 @@ cdef coo_to_df(GraphCOOPtrType graph):
83115

84116
cdef csr_to_series(GraphCSRPtrType graph):
85117
contents = move(graph.get()[0].release())
86-
csr_offsets = move_device_buffer_to_series(move(contents.offsets),
87-
"int32", "csr_offsets")
88-
csr_indices = move_device_buffer_to_series(move(contents.indices),
89-
"int32", "csr_indices")
118+
csr_offsets = move_device_buffer_to_series(
119+
move(contents.offsets),
120+
pylibcudf.DataType(pylibcudf.TypeId.INT32),
121+
4,
122+
"csr_offsets"
123+
)
124+
csr_indices = move_device_buffer_to_series(
125+
move(contents.indices),
126+
pylibcudf.DataType(pylibcudf.TypeId.INT32),
127+
4,
128+
"csr_indices"
129+
)
90130

91131
if GraphCSRPtrType is GraphCSRPtrFloat:
92-
weight_type = "float32"
132+
weight_type = pylibcudf.DataType(pylibcudf.TypeId.FLOAT32)
133+
itemsize = 4
93134
elif GraphCSRPtrType is GraphCSRPtrDouble:
94-
weight_type = "float64"
135+
weight_type = pylibcudf.DataType(pylibcudf.TypeId.FLOAT64)
136+
itemsize = 8
95137
else:
96138
raise TypeError("Invalid GraphCSRPtrType")
97139

98-
csr_weights = move_device_buffer_to_series(move(contents.edge_data),
99-
weight_type, "csr_weights")
140+
csr_weights = move_device_buffer_to_series(
141+
move(contents.edge_data),
142+
weight_type,
143+
itemsize,
144+
"csr_weights"
145+
)
100146

101147
return (csr_offsets, csr_indices, csr_weights)
102148

python/cugraph/pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dependencies = [
3232
"libcugraph==25.6.*,>=0.0.0a0",
3333
"numba>=0.59.1,<0.61.0a0",
3434
"numpy>=1.23,<3.0a0",
35+
"pylibcudf==25.6.*,>=0.0.0a0",
3536
"pylibcugraph==25.6.*,>=0.0.0a0",
3637
"pylibraft==25.6.*,>=0.0.0a0",
3738
"raft-dask==25.6.*,>=0.0.0a0",

0 commit comments

Comments
 (0)