diff --git a/ci/gpu/build.sh b/ci/gpu/build.sh index 18a8e940fa8..12cb8c5a25a 100755 --- a/ci/gpu/build.sh +++ b/ci/gpu/build.sh @@ -62,10 +62,16 @@ conda activate rapids export PATH=$(conda info --base)/envs/rapids/bin:$PATH gpuci_logger "Install dependencies" -gpuci_mamba_retry install -y \ - "libcudf=${MINOR_VERSION}" \ +# Assume libcudf and librmm will be installed via cudf and rmm respectively. +# This is done to prevent the following install scenario: +# libcudf = 22.04.00a220315, cudf = 22.04.00a220308 +# where cudf 220308 was chosen possibly because it has fewer/different +# dependencies and the corresponding recipes have specified these combinations +# should work when sometimes they do not. +# FIXME: remove testing label when gpuCI has the ability to move the pyraft +# label from testing to main. +gpuci_mamba_retry install -c rapidsai-nightly/label/testing -y \ "cudf=${MINOR_VERSION}" \ - "librmm=${MINOR_VERSION}" \ "rmm=${MINOR_VERSION}" \ "libraft-headers=${MINOR_VERSION}" \ "pyraft=${MINOR_VERSION}" \ diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 1de17223699..d96973c2bf0 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -348,6 +348,7 @@ endif() add_library(cugraph_c SHARED src/c_api/cugraph_api.cpp + src/c_api/resource_handle.cpp src/c_api/array.cpp src/c_api/error.cpp src/c_api/graph_sg.cpp diff --git a/cpp/cmake/thirdparty/get_raft.cmake b/cpp/cmake/thirdparty/get_raft.cmake index e00378e364a..8b75753db91 100644 --- a/cpp/cmake/thirdparty/get_raft.cmake +++ b/cpp/cmake/thirdparty/get_raft.cmake @@ -36,8 +36,9 @@ function(find_and_configure_raft) GIT_TAG ${PKG_PINNED_TAG} SOURCE_SUBDIR cpp OPTIONS - "BUILD_TESTS OFF" "RAFT_COMPILE_LIBRARIES OFF" + "BUILD_TESTS OFF" + "BUILD_BENCH OFF" ) if(raft_ADDED) diff --git a/cpp/include/cugraph_c/algorithms.h b/cpp/include/cugraph_c/algorithms.h index dd5a7d850fb..4654f0005c9 100644 --- a/cpp/include/cugraph_c/algorithms.h +++ b/cpp/include/cugraph_c/algorithms.h @@ -16,9 +16,9 @@ #pragma once -#include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/cpp/include/cugraph_c/array.h b/cpp/include/cugraph_c/array.h index 86ed6d9208b..925d2f34ea5 100644 --- a/cpp/include/cugraph_c/array.h +++ b/cpp/include/cugraph_c/array.h @@ -16,26 +16,26 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { #endif typedef struct { - int align_; + int32_t align_; } cugraph_type_erased_device_array_t; typedef struct { - int align_; + int32_t align_; } cugraph_type_erased_device_array_view_t; typedef struct { - int align_; + int32_t align_; } cugraph_type_erased_host_array_t; typedef struct { - int align_; + int32_t align_; } cugraph_type_erased_host_array_view_t; /** diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index f7c5d2737c8..c5b639ae73c 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -26,21 +27,8 @@ extern "C" { #endif -typedef enum bool_ { FALSE = 0, TRUE = 1 } bool_t; - -typedef int8_t byte_t; - -typedef enum data_type_id_ { INT32 = 0, INT64, FLOAT32, FLOAT64, NTYPES } data_type_id_t; - -/* sizes in Bytes for data_type_id_t*/ -extern int data_type_sz[]; - /* C stub declarations */ -typedef struct cugraph_resource_handle_ { - int align_; -} cugraph_resource_handle_t; - typedef struct cugraph_graph_envelope_ { int align_; } cugraph_graph_envelope_t; @@ -160,12 +148,6 @@ cugraph_error_code_t cugraph_update_host_buffer(const cugraph_resource_handle_t* byte_t* ptr_h_dst, const cugraph_device_buffer_t* ptr_src); -/* raft::handle_t allocator (for now; possibly a more encompassing handle in the future)*/ -cugraph_resource_handle_t* cugraph_create_resource_handle(void); - -/* raft::handle_t deallocator*/ -void cugraph_free_resource_handle(cugraph_resource_handle_t* p_handle); - #ifdef __cplusplus } #endif diff --git a/cpp/include/cugraph_c/error.h b/cpp/include/cugraph_c/error.h index 9cbf454a233..3482171fb27 100644 --- a/cpp/include/cugraph_c/error.h +++ b/cpp/include/cugraph_c/error.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -31,7 +33,7 @@ typedef enum cugraph_error_code_ { } cugraph_error_code_t; typedef struct cugraph_error_ { - int align_; + int32_t align_; } cugraph_error_t; /** diff --git a/cpp/include/cugraph_c/graph.h b/cpp/include/cugraph_c/graph.h index 6c64c317d17..092c3c4b91a 100644 --- a/cpp/include/cugraph_c/graph.h +++ b/cpp/include/cugraph_c/graph.h @@ -24,7 +24,7 @@ extern "C" { #endif typedef struct { - int align_; + int32_t align_; } cugraph_graph_t; typedef struct { @@ -32,6 +32,7 @@ typedef struct { bool_t is_multigraph; } cugraph_graph_properties_t; +// FIXME: Add support for specifying isloated vertices /** * @brief Construct an SG graph * @@ -73,6 +74,7 @@ cugraph_error_code_t cugraph_sg_graph_create(const cugraph_resource_handle_t* ha // but didn't want to confuse with original cugraph_free_graph void cugraph_sg_graph_free(cugraph_graph_t* graph); +// FIXME: Add support for specifying isloated vertices /** * @brief Construct an MG graph * @@ -94,20 +96,16 @@ void cugraph_sg_graph_free(cugraph_graph_t* graph); * be populated if error code is not CUGRAPH_SUCCESS * @return error code */ -cugraph_error_code_t cugraph_mg_graph_create( - const cugraph_resource_handle_t* handle, - const cugraph_graph_properties_t* properties, - const cugraph_type_erased_device_array_view_t* src, - const cugraph_type_erased_device_array_view_t* dst, - const cugraph_type_erased_device_array_view_t* weights, - const cugraph_type_erased_host_array_view_t* vertex_partition_offsets, - const cugraph_type_erased_host_array_view_t* segment_offsets, - bool_t store_transposed, - size_t num_vertices, - size_t num_edges, - bool_t check, - cugraph_graph_t** graph, - cugraph_error_t** error); +cugraph_error_code_t cugraph_mg_graph_create(const cugraph_resource_handle_t* handle, + const cugraph_graph_properties_t* properties, + const cugraph_type_erased_device_array_view_t* src, + const cugraph_type_erased_device_array_view_t* dst, + const cugraph_type_erased_device_array_view_t* weights, + bool_t store_transposed, + size_t num_edges, + bool_t check, + cugraph_graph_t** graph, + cugraph_error_t** error); /** * @brief Destroy an MG graph diff --git a/cpp/include/cugraph_c/resource_handle.h b/cpp/include/cugraph_c/resource_handle.h new file mode 100644 index 00000000000..27ed03c3028 --- /dev/null +++ b/cpp/include/cugraph_c/resource_handle.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum bool_ { FALSE = 0, TRUE = 1 } bool_t; + +typedef int8_t byte_t; + +typedef enum data_type_id_ { INT32 = 0, INT64, FLOAT32, FLOAT64, NTYPES } data_type_id_t; + +/* sizes in Bytes for data_type_id_t*/ +extern size_t data_type_sz[]; + +typedef struct cugraph_resource_handle_ { + int32_t align_; +} cugraph_resource_handle_t; + +// FIXME: Don't really want a raft handle here. We really want to be able to +// configure the resource handle ourselves. But that requires a bunch +// of logic that's currently only available in python. +/** + * @brief Construct a resource handle + * + * @param [in] raft_handle Handle for accessing resources + * If NULL, we will create a raft handle + * internally + * + * @return A graph resource handle + */ +cugraph_resource_handle_t* cugraph_create_resource_handle(void* raft_handle); + +/** + * @brief get rank from resource handle + * + * If the resource handle has been configured for multi-gpu, this will return + * the rank for this worker. If the resource handle has not been configured for + * multi-gpu this will always return 0. + * + * @param [in] handle Handle for accessing resources + * @return rank + */ +int cugraph_resource_handle_get_rank(const cugraph_resource_handle_t* handle); + +/** + * @brief Free resources in the resource handle + * + * @param [in] handle Handle for accessing resources + */ +void cugraph_free_resource_handle(cugraph_resource_handle_t* handle); + +#ifdef __cplusplus +} +#endif diff --git a/cpp/src/c_api/array.cpp b/cpp/src/c_api/array.cpp index c6e6d8ac262..3d5671143dd 100644 --- a/cpp/src/c_api/array.cpp +++ b/cpp/src/c_api/array.cpp @@ -16,8 +16,7 @@ #include #include - -#include +#include namespace cugraph { namespace c_api { @@ -41,18 +40,18 @@ extern "C" cugraph_error_code_t cugraph_type_erased_device_array_create( *error = nullptr; try { - raft::handle_t const* raft_handle = reinterpret_cast(handle); - - if (!raft_handle) { + if (!handle) { *error = reinterpret_cast( new cugraph::c_api::cugraph_error_t{"invalid resource handle"}); return CUGRAPH_INVALID_HANDLE; } + auto p_handle = reinterpret_cast(handle); + size_t n_bytes = n_elems * (::data_type_sz[dtype]); auto ret_value = new cugraph::c_api::cugraph_type_erased_device_array_t( - n_elems, n_bytes, dtype, raft_handle->get_stream()); + n_elems, n_bytes, dtype, p_handle->handle_->get_stream()); *array = reinterpret_cast(ret_value); return CUGRAPH_SUCCESS; @@ -140,14 +139,14 @@ extern "C" cugraph_error_code_t cugraph_type_erased_host_array_create( *error = nullptr; try { - raft::handle_t const* raft_handle = reinterpret_cast(handle); - - if (!raft_handle) { + if (!handle) { *error = reinterpret_cast( new cugraph::c_api::cugraph_error_t{"invalid resource handle"}); return CUGRAPH_INVALID_HANDLE; } + auto p_handle = reinterpret_cast(handle); + size_t n_bytes = n_elems * (::data_type_sz[dtype]); *array = reinterpret_cast( @@ -233,20 +232,20 @@ extern "C" cugraph_error_code_t cugraph_type_erased_device_array_view_copy_from_ *error = nullptr; try { - raft::handle_t const* raft_handle = reinterpret_cast(handle); - auto internal_pointer = - reinterpret_cast(dst); - - if (!raft_handle) { + if (!handle) { *error = reinterpret_cast( new cugraph::c_api::cugraph_error_t{"invalid resource handle"}); return CUGRAPH_INVALID_HANDLE; } + auto p_handle = reinterpret_cast(handle); + auto internal_pointer = + reinterpret_cast(dst); + raft::update_device(reinterpret_cast(internal_pointer->data_), h_src, internal_pointer->num_bytes(), - raft_handle->get_stream()); + p_handle->handle_->get_stream()); return CUGRAPH_SUCCESS; } catch (std::exception const& ex) { @@ -265,20 +264,20 @@ extern "C" cugraph_error_code_t cugraph_type_erased_device_array_view_copy_to_ho *error = nullptr; try { - raft::handle_t const* raft_handle = reinterpret_cast(handle); - auto internal_pointer = - reinterpret_cast(src); - - if (!raft_handle) { + if (!handle) { *error = reinterpret_cast( new cugraph::c_api::cugraph_error_t{"invalid resource handle"}); return CUGRAPH_INVALID_HANDLE; } + auto p_handle = reinterpret_cast(handle); + auto internal_pointer = + reinterpret_cast(src); + raft::update_host(h_dst, reinterpret_cast(internal_pointer->data_), internal_pointer->num_bytes(), - raft_handle->get_stream()); + p_handle->handle_->get_stream()); return CUGRAPH_SUCCESS; } catch (std::exception const& ex) { @@ -297,13 +296,13 @@ extern "C" cugraph_error_code_t cugraph_type_erased_device_array_view_copy( *error = nullptr; try { - raft::handle_t const* raft_handle = reinterpret_cast(handle); + auto p_handle = reinterpret_cast(handle); auto internal_pointer_dst = reinterpret_cast(dst); auto internal_pointer_src = reinterpret_cast(src); - if (!raft_handle) { + if (!handle) { *error = reinterpret_cast( new cugraph::c_api::cugraph_error_t{"invalid resource handle"}); return CUGRAPH_INVALID_HANDLE; @@ -318,7 +317,7 @@ extern "C" cugraph_error_code_t cugraph_type_erased_device_array_view_copy( raft::copy(reinterpret_cast(internal_pointer_dst->data_), reinterpret_cast(internal_pointer_src->data_), internal_pointer_src->num_bytes(), - raft_handle->get_stream()); + p_handle->handle_->get_stream()); return CUGRAPH_SUCCESS; } catch (std::exception const& ex) { diff --git a/cpp/src/c_api/bfs.cpp b/cpp/src/c_api/bfs.cpp index 9bfe7273ecf..d00ffae803f 100644 --- a/cpp/src/c_api/bfs.cpp +++ b/cpp/src/c_api/bfs.cpp @@ -19,14 +19,13 @@ #include #include #include +#include #include #include #include #include -#include - namespace cugraph { namespace c_api { @@ -40,7 +39,7 @@ struct bfs_functor : public abstract_functor { bool do_expensive_check_; cugraph_paths_result_t* result_{}; - bfs_functor(cugraph_resource_handle_t const* handle, + bfs_functor(::cugraph_resource_handle_t const* handle, ::cugraph_graph_t* graph, ::cugraph_type_erased_device_array_view_t* sources, bool direction_optimizing, @@ -48,7 +47,7 @@ struct bfs_functor : public abstract_functor { bool compute_predecessors, bool do_expensive_check) : abstract_functor(), - handle_(*reinterpret_cast(handle)), + handle_(*reinterpret_cast(handle)->handle_), graph_(reinterpret_cast(graph)), sources_(reinterpret_cast(sources)), direction_optimizing_(direction_optimizing), diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index dc81223f8fe..e8914937297 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,7 +78,7 @@ cugraph_error_code_t extract_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_devic } // namespace helpers extern "C" { -int data_type_sz[] = {4, 8, 4, 8}; +size_t data_type_sz[] = {4, 8, 4, 8}; } bool_t runtime_assert(bool_t statement_truth_value, const char* error_msg) @@ -349,18 +349,3 @@ extern "C" cugraph_error_code_t cugraph_update_host_buffer(const cugraph_resourc } return status; } - -extern "C" cugraph_resource_handle_t* cugraph_create_resource_handle(void) -{ - try { - return reinterpret_cast(new raft::handle_t{}); - } catch (...) { - return nullptr; - } -} - -extern "C" void cugraph_free_resource_handle(cugraph_resource_handle_t* p_handle) -{ - raft::handle_t* p_raft_handle = reinterpret_cast(p_handle); - delete p_raft_handle; -} diff --git a/cpp/src/c_api/extract_paths.cpp b/cpp/src/c_api/extract_paths.cpp index 1b7f5e214a6..f7a5bda9eff 100644 --- a/cpp/src/c_api/extract_paths.cpp +++ b/cpp/src/c_api/extract_paths.cpp @@ -19,14 +19,13 @@ #include #include #include +#include #include #include #include #include -#include - namespace cugraph { namespace c_api { @@ -43,13 +42,13 @@ struct extract_paths_functor : public abstract_functor { cugraph_type_erased_device_array_view_t const* destinations_; cugraph_extract_paths_result_t* result_{}; - extract_paths_functor(cugraph_resource_handle_t const* handle, + extract_paths_functor(::cugraph_resource_handle_t const* handle, ::cugraph_graph_t* graph, ::cugraph_type_erased_device_array_view_t const* sources, ::cugraph_paths_result_t const* paths_result, ::cugraph_type_erased_device_array_view_t const* destinations) : abstract_functor(), - handle_(*reinterpret_cast(handle)), + handle_(*reinterpret_cast(handle)->handle_), graph_(reinterpret_cast(graph)), sources_( reinterpret_cast(sources)), diff --git a/cpp/src/c_api/graph_mg.cpp b/cpp/src/c_api/graph_mg.cpp index b2448e46796..c9041ccbfc3 100644 --- a/cpp/src/c_api/graph_mg.cpp +++ b/cpp/src/c_api/graph_mg.cpp @@ -14,13 +14,167 @@ * limitations under the License. */ +#include +#include +#include +#include #include -// FIXME: assume that this function will directly call -// create_graph_from_edgelist() instead of invoking a graph constructor, in -// which case, some parameters here (e.g. vertex_partition_offsets, -// segment_offsets) are related to implementation details and unnecessary if -// this function calls create_graph_from_edgelist(). +#include +#include +#include +#include +#include + +#include + +namespace { + +struct create_graph_functor : public cugraph::c_api::abstract_functor { + raft::handle_t const& handle_; + cugraph_graph_properties_t const* properties_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* src_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* dst_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* weights_; + bool_t renumber_; + bool_t check_; + data_type_id_t edge_type_; + cugraph::c_api::cugraph_graph_t* result_{}; + + create_graph_functor(raft::handle_t const& handle, + cugraph_graph_properties_t const* properties, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* src, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* dst, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* weights, + bool_t renumber, + bool_t check, + data_type_id_t edge_type) + : abstract_functor(), + properties_(properties), + handle_(handle), + src_(src), + dst_(dst), + weights_(weights), + renumber_(renumber), + check_(check), + edge_type_(edge_type) + { + } + + template + void operator()() + { + if constexpr (!multi_gpu || !cugraph::is_candidate::value) { + unsupported(); + } else { + std::optional> new_number_map; + + rmm::device_uvector edgelist_rows(src_->size_, handle_.get_stream()); + rmm::device_uvector edgelist_cols(dst_->size_, handle_.get_stream()); + + raft::copy( + edgelist_rows.data(), src_->as_type(), src_->size_, handle_.get_stream()); + raft::copy( + edgelist_cols.data(), dst_->as_type(), dst_->size_, handle_.get_stream()); + + std::optional> edgelist_weights = + weights_ + ? std::make_optional(rmm::device_uvector(weights_->size_, handle_.get_stream())) + : std::nullopt; + + if (edgelist_weights) { + raft::copy(edgelist_weights->data(), + weights_->as_type(), + weights_->size_, + handle_.get_stream()); + } + + // Here's the error. If store_transposed is true then this needs to be flipped... + std::tie(store_transposed ? edgelist_cols : edgelist_rows, + store_transposed ? edgelist_rows : edgelist_cols, + edgelist_weights) = + cugraph::detail::shuffle_edgelist_by_gpu_id( + handle_, + std::move(store_transposed ? edgelist_cols : edgelist_rows), + std::move(store_transposed ? edgelist_rows : edgelist_cols), + std::move(edgelist_weights)); + + auto graph = + new cugraph::graph_t(handle_); + + rmm::device_uvector* number_map = + new rmm::device_uvector(0, handle_.get_stream()); + + std::tie(*graph, new_number_map) = cugraph:: + create_graph_from_edgelist( + handle_, + std::nullopt, + std::move(edgelist_rows), + std::move(edgelist_cols), + std::move(edgelist_weights), + cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, + renumber_, + check_); + + if (renumber_) { + *number_map = std::move(new_number_map.value()); + } else { + number_map->resize(graph->get_number_of_vertices(), handle_.get_stream()); + cugraph::detail::sequence_fill(handle_.get_stream(), + number_map->data(), + number_map->size(), + graph->view().get_local_vertex_first()); + } + + // Set up return + auto result = + new cugraph::c_api::cugraph_graph_t{src_->type_, + edge_type_, + weights_ ? weights_->type_ : data_type_id_t::FLOAT32, + store_transposed, + multi_gpu, + graph, + number_map}; + + result_ = reinterpret_cast(result); + } + } +}; + +struct destroy_graph_functor : public cugraph::c_api::abstract_functor { + void* graph_; + void* number_map_; + + destroy_graph_functor(void* graph, void* number_map) + : abstract_functor(), graph_(graph), number_map_(number_map) + { + } + + template + void operator()() + { + auto internal_graph_pointer = + reinterpret_cast*>( + graph_); + + delete internal_graph_pointer; + + auto internal_number_map_pointer = + reinterpret_cast*>(number_map_); + + delete internal_number_map_pointer; + } +}; + +} // namespace extern "C" cugraph_error_code_t cugraph_mg_graph_create( const cugraph_resource_handle_t* handle, @@ -28,17 +182,95 @@ extern "C" cugraph_error_code_t cugraph_mg_graph_create( const cugraph_type_erased_device_array_view_t* src, const cugraph_type_erased_device_array_view_t* dst, const cugraph_type_erased_device_array_view_t* weights, - const cugraph_type_erased_host_array_view_t* vertex_partition_offsets, - const cugraph_type_erased_host_array_view_t* segment_offsets, bool_t store_transposed, - size_t num_vertices, size_t num_edges, bool_t check, cugraph_graph_t** graph, cugraph_error_t** error) { + constexpr bool multi_gpu = true; + constexpr size_t int32_threshold{std::numeric_limits::max()}; + *graph = nullptr; - return CUGRAPH_NOT_IMPLEMENTED; + *error = nullptr; + + auto p_handle = reinterpret_cast(handle); + auto p_src = + reinterpret_cast(src); + auto p_dst = + reinterpret_cast(dst); + auto p_weights = + reinterpret_cast(weights); + + CAPI_EXPECTS(p_src->size_ == p_dst->size_, + CUGRAPH_INVALID_INPUT, + "Invalid input arguments: src size != dst size.", + *error); + CAPI_EXPECTS(p_src->type_ == p_dst->type_, + CUGRAPH_INVALID_INPUT, + "Invalid input arguments: src type != dst type.", + *error); + + CAPI_EXPECTS(!weights || (p_weights->size_ == p_src->size_), + CUGRAPH_INVALID_INPUT, + "Invalid input arguments: src size != weights size.", + *error); + + data_type_id_t edge_type; + data_type_id_t weight_type; + + if (num_edges < int32_threshold) { + edge_type = p_src->type_; + } else { + edge_type = data_type_id_t::INT64; + } + + if (!weights) { + weight_type = p_weights->type_; + } else { + weight_type = data_type_id_t::FLOAT32; + } + + create_graph_functor functor( + *p_handle->handle_, properties, p_src, p_dst, p_weights, bool_t::TRUE, check, edge_type); + + try { + cugraph::dispatch::vertex_dispatcher(cugraph::c_api::dtypes_mapping[p_src->type_], + cugraph::c_api::dtypes_mapping[edge_type], + cugraph::c_api::dtypes_mapping[weight_type], + store_transposed, + multi_gpu, + functor); + + if (functor.error_code_ != CUGRAPH_SUCCESS) { + *error = reinterpret_cast(functor.error_.release()); + return functor.error_code_; + } + + *graph = reinterpret_cast(functor.result_); + } catch (std::exception const& ex) { + *error = reinterpret_cast(new cugraph::c_api::cugraph_error_t{ex.what()}); + return CUGRAPH_UNKNOWN_ERROR; + } + + return CUGRAPH_SUCCESS; } -extern "C" void cugraph_mg_graph_free(cugraph_graph_t* ptr_graph) {} +extern "C" void cugraph_mg_graph_free(cugraph_graph_t* ptr_graph) +{ + if (ptr_graph != NULL) { + auto internal_pointer = reinterpret_cast(ptr_graph); + + destroy_graph_functor functor(internal_pointer->graph_, internal_pointer->number_map_); + + cugraph::dispatch::vertex_dispatcher( + cugraph::c_api::dtypes_mapping[internal_pointer->vertex_type_], + cugraph::c_api::dtypes_mapping[internal_pointer->edge_type_], + cugraph::c_api::dtypes_mapping[internal_pointer->weight_type_], + internal_pointer->store_transposed_, + internal_pointer->multi_gpu_, + functor); + + delete internal_pointer; + } +} diff --git a/cpp/src/c_api/graph_sg.cpp b/cpp/src/c_api/graph_sg.cpp index 6546e135bce..36fd299c969 100644 --- a/cpp/src/c_api/graph_sg.cpp +++ b/cpp/src/c_api/graph_sg.cpp @@ -23,30 +23,28 @@ #include #include #include - -#include +#include #include -namespace cugraph { -namespace c_api { +namespace { -struct create_graph_functor : public abstract_functor { +struct create_graph_functor : public cugraph::c_api::abstract_functor { raft::handle_t const& handle_; cugraph_graph_properties_t const* properties_; - c_api::cugraph_type_erased_device_array_view_t const* src_; - c_api::cugraph_type_erased_device_array_view_t const* dst_; - c_api::cugraph_type_erased_device_array_view_t const* weights_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* src_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* dst_; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* weights_; bool_t renumber_; bool_t check_; data_type_id_t edge_type_; - c_api::cugraph_graph_t* result_{}; + cugraph::c_api::cugraph_graph_t* result_{}; create_graph_functor(raft::handle_t const& handle, cugraph_graph_properties_t const* properties, - c_api::cugraph_type_erased_device_array_view_t const* src, - c_api::cugraph_type_erased_device_array_view_t const* dst, - c_api::cugraph_type_erased_device_array_view_t const* weights, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* src, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* dst, + cugraph::c_api::cugraph_type_erased_device_array_view_t const* weights, bool_t renumber, bool_t check, data_type_id_t edge_type) @@ -76,12 +74,6 @@ struct create_graph_functor : public abstract_functor { // FIXME: Need an implementation here. } - auto graph = - new cugraph::graph_t(handle_); - - rmm::device_uvector* number_map = - new rmm::device_uvector(0, handle_.get_stream()); - std::optional> new_number_map; rmm::device_uvector edgelist_rows(src_->size_, handle_.get_stream()); @@ -104,14 +96,20 @@ struct create_graph_functor : public abstract_functor { handle_.get_stream()); } - std::tie(*graph, new_number_map) = + auto graph = + new cugraph::graph_t(handle_); + + rmm::device_uvector* number_map = + new rmm::device_uvector(0, handle_.get_stream()); + + std::tie(*graph, new_number_map) = cugraph:: create_graph_from_edgelist( handle_, std::nullopt, std::move(edgelist_rows), std::move(edgelist_cols), std::move(edgelist_weights), - graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, + cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, renumber_, check_); @@ -135,12 +133,12 @@ struct create_graph_functor : public abstract_functor { graph, number_map}; - result_ = reinterpret_cast(result); + result_ = reinterpret_cast(result); } } }; -struct destroy_graph_functor : public abstract_functor { +struct destroy_graph_functor : public cugraph::c_api::abstract_functor { void* graph_; void* number_map_; @@ -169,8 +167,7 @@ struct destroy_graph_functor : public abstract_functor { } }; -} // namespace c_api -} // namespace cugraph +} // namespace extern "C" cugraph_error_code_t cugraph_sg_graph_create( const cugraph_resource_handle_t* handle, @@ -185,15 +182,12 @@ extern "C" cugraph_error_code_t cugraph_sg_graph_create( cugraph_error_t** error) { constexpr bool multi_gpu = false; - // FIXME: There could be a case where the vertex_t is int64_t but the number - // of edges is less than 2^31-1. The if statement below could then be modified - // to catch this case. constexpr size_t int32_threshold{std::numeric_limits::max()}; *graph = nullptr; *error = nullptr; - auto p_handle = reinterpret_cast(handle); + auto p_handle = reinterpret_cast(handle); auto p_src = reinterpret_cast(src); auto p_dst = @@ -219,7 +213,7 @@ extern "C" cugraph_error_code_t cugraph_sg_graph_create( data_type_id_t weight_type; if (p_src->size_ < int32_threshold) { - edge_type = data_type_id_t::INT32; + edge_type = p_src->type_; } else { edge_type = data_type_id_t::INT64; } @@ -230,8 +224,8 @@ extern "C" cugraph_error_code_t cugraph_sg_graph_create( weight_type = data_type_id_t::FLOAT32; } - cugraph::c_api::create_graph_functor functor( - *p_handle, properties, p_src, p_dst, p_weights, renumber, check, edge_type); + ::create_graph_functor functor( + *p_handle->handle_, properties, p_src, p_dst, p_weights, renumber, check, edge_type); try { cugraph::dispatch::vertex_dispatcher(cugraph::c_api::dtypes_mapping[p_src->type_], @@ -259,8 +253,7 @@ extern "C" void cugraph_sg_graph_free(cugraph_graph_t* ptr_graph) { auto internal_pointer = reinterpret_cast(ptr_graph); - cugraph::c_api::destroy_graph_functor functor(internal_pointer->graph_, - internal_pointer->number_map_); + destroy_graph_functor functor(internal_pointer->graph_, internal_pointer->number_map_); cugraph::dispatch::vertex_dispatcher( cugraph::c_api::dtypes_mapping[internal_pointer->vertex_type_], diff --git a/cpp/src/c_api/pagerank.cpp b/cpp/src/c_api/pagerank.cpp index 4dbeaadf448..c369b4b0442 100644 --- a/cpp/src/c_api/pagerank.cpp +++ b/cpp/src/c_api/pagerank.cpp @@ -18,14 +18,13 @@ #include #include +#include #include #include #include #include -#include - #include namespace cugraph { @@ -50,7 +49,7 @@ struct pagerank_functor : public abstract_functor { cugraph_pagerank_result_t* result_{}; pagerank_functor( - cugraph_resource_handle_t const* handle, + ::cugraph_resource_handle_t const* handle, ::cugraph_graph_t* graph, ::cugraph_type_erased_device_array_view_t const* precomputed_vertex_out_weight_sums, ::cugraph_type_erased_device_array_view_t* personalization_vertices, @@ -61,7 +60,7 @@ struct pagerank_functor : public abstract_functor { bool has_initial_guess, bool do_expensive_check) : abstract_functor(), - handle_(*reinterpret_cast(handle)), + handle_(*reinterpret_cast(handle)->handle_), graph_(reinterpret_cast(graph)), precomputed_vertex_out_weight_sums_( reinterpret_cast( @@ -106,9 +105,9 @@ struct pagerank_functor : public abstract_functor { auto number_map = reinterpret_cast*>(graph_->number_map_); - rmm::device_uvector vertex_ids(graph->get_number_of_vertices(), + rmm::device_uvector vertex_ids(graph_view.get_number_of_local_vertices(), handle_.get_stream()); - rmm::device_uvector pageranks(graph->get_number_of_vertices(), + rmm::device_uvector pageranks(graph_view.get_number_of_local_vertices(), handle_.get_stream()); if (personalization_vertices_ != nullptr) { diff --git a/cpp/src/c_api/random_walks.cpp b/cpp/src/c_api/random_walks.cpp index 079821813e8..288fe00d2a7 100644 --- a/cpp/src/c_api/random_walks.cpp +++ b/cpp/src/c_api/random_walks.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -25,8 +26,6 @@ #include #include -#include - namespace cugraph { namespace c_api { @@ -48,7 +47,7 @@ struct node2vec_functor : public abstract_functor { double q_{0}; cugraph_random_walk_result_t* result_{nullptr}; - node2vec_functor(cugraph_resource_handle_t const* handle, + node2vec_functor(::cugraph_resource_handle_t const* handle, ::cugraph_graph_t* graph, ::cugraph_type_erased_device_array_view_t const* sources, size_t max_depth, @@ -56,7 +55,7 @@ struct node2vec_functor : public abstract_functor { double p, double q) : abstract_functor(), - handle_(*reinterpret_cast(handle)), + handle_(*reinterpret_cast(handle)->handle_), graph_(reinterpret_cast(graph)), sources_( reinterpret_cast(sources)), diff --git a/cpp/src/c_api/resource_handle.cpp b/cpp/src/c_api/resource_handle.cpp new file mode 100644 index 00000000000..767a6f0add6 --- /dev/null +++ b/cpp/src/c_api/resource_handle.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +extern "C" cugraph_resource_handle_t* cugraph_create_resource_handle(void* raft_handle) +{ + try { + return reinterpret_cast( + new cugraph::c_api::cugraph_resource_handle_t(raft_handle)); + } catch (...) { + return nullptr; + } +} + +extern "C" void cugraph_free_resource_handle(cugraph_resource_handle_t* handle) +{ + auto internal = reinterpret_cast(handle); + if (internal->allocated_) delete internal->handle_; + delete internal; +} + +extern "C" int cugraph_resource_handle_get_rank(const cugraph_resource_handle_t* handle) +{ + auto internal = reinterpret_cast(handle); + auto& comm = internal->handle_->get_comms(); + return static_cast(comm.get_rank()); +} diff --git a/cpp/src/c_api/resource_handle.hpp b/cpp/src/c_api/resource_handle.hpp new file mode 100644 index 00000000000..6154c1f806b --- /dev/null +++ b/cpp/src/c_api/resource_handle.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace cugraph { +namespace c_api { + +struct cugraph_resource_handle_t { + raft::handle_t* handle_{nullptr}; + bool allocated_{false}; + + cugraph_resource_handle_t(void* raft_handle) + { + if (raft_handle == nullptr) { + handle_ = new raft::handle_t{}; + allocated_ = true; + } else { + handle_ = reinterpret_cast(raft_handle); + } + } +}; + +} // namespace c_api +} // namespace cugraph diff --git a/cpp/src/c_api/sssp.cpp b/cpp/src/c_api/sssp.cpp index 0e0a232ff9a..fb4cfa301ad 100644 --- a/cpp/src/c_api/sssp.cpp +++ b/cpp/src/c_api/sssp.cpp @@ -19,14 +19,13 @@ #include #include #include +#include #include #include #include #include -#include - namespace cugraph { namespace c_api { @@ -39,14 +38,14 @@ struct sssp_functor : public abstract_functor { bool do_expensive_check_; cugraph_paths_result_t* result_{}; - sssp_functor(cugraph_resource_handle_t const* handle, + sssp_functor(::cugraph_resource_handle_t const* handle, ::cugraph_graph_t* graph, size_t source, double cutoff, bool compute_predecessors, bool do_expensive_check) : abstract_functor(), - handle_(*reinterpret_cast(handle)), + handle_(*reinterpret_cast(handle)->handle_), graph_(reinterpret_cast(graph)), source_(source), cutoff_(cutoff), diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index a4c89b76ce4..0b487abe2bf 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -252,6 +252,40 @@ function(ConfigureCTest CMAKE_TEST_NAME) EXCLUDE_FROM_ALL) endfunction() +function(ConfigureCTestMG CMAKE_TEST_NAME) + add_executable(${CMAKE_TEST_NAME} ${ARGN}) + + target_link_libraries(${CMAKE_TEST_NAME} + PRIVATE + cugraph::cugraph_c + cugraph_c_testutil + GTest::gtest + GTest::gtest_main + NCCL::NCCL + MPI::MPI_CXX + ) + + add_test(NAME ${CMAKE_TEST_NAME} + COMMAND ${MPIEXEC_EXECUTABLE} + "--noprefix" + ${MPIEXEC_NUMPROC_FLAG} + ${GPU_COUNT} + ${MPIEXEC_PREFLAGS} + ${CMAKE_TEST_NAME} + ${MPIEXEC_POSTFLAGS}) + + set_target_properties( + ${CMAKE_TEST_NAME} + PROPERTIES INSTALL_RPATH "\$ORIGIN/../../../lib") + + install( + TARGETS ${CMAKE_TEST_NAME} + COMPONENT testing + DESTINATION bin/gtests/libcugraph_c + EXCLUDE_FROM_ALL) +endfunction() + + ################################################################################################### # - set rapids dataset path ---------------------------------------------------------------------- @@ -573,6 +607,11 @@ if(BUILD_CUGRAPH_MG_TESTS) ########################################################################################### # - MG GATHER_UTILS tests ----------------------------------------------------------------- ConfigureTestMG(MG_GATHER_UTILS_TEST sampling/detail/mg_gather_utils.cu) + + ########################################################################################### + # - MG C API tests ------------------------------------------------------------------------ + ConfigureCTestMG(MG_CAPI_CREATE_GRAPH c_api/mg_create_graph_test.c c_api/mg_test_utils.cpp) + ConfigureCTestMG(MG_CAPI_PAGERANK c_api/mg_pagerank_test.c c_api/mg_test_utils.cpp) else() message(FATAL_ERROR "OpenMPI NOT found, cannot build MG tests.") endif() @@ -585,7 +624,7 @@ endif() # - common C API test utils ----------------------------------------------------------------------------- add_library(cugraph_c_testutil STATIC - c_api/test_utils.c) + c_api/test_utils.cpp) target_compile_options(cugraph_c_testutil PUBLIC "$<$:${CUGRAPH_CXX_FLAGS}>" @@ -606,9 +645,12 @@ target_link_libraries(cugraph_c_testutil ) -ConfigureCTest(CAPI_CREATE_SG_GRAPH_ENVELOPE_TEST c_api/create_sg_graph_envelope_test.c) +# FIXME: Disabling these tests, they test an older version of the API which +# will be deleted in this release. Leaving them here to help me remember :-) +#ConfigureCTest(CAPI_CREATE_SG_GRAPH_ENVELOPE_TEST c_api/create_sg_graph_envelope_test.c) +#ConfigureCTest(CAPI_RANDOM_WALKS_TEST c_api/random_walks_test.c) + ConfigureCTest(CAPI_CREATE_GRAPH_TEST c_api/create_graph_test.c) -ConfigureCTest(CAPI_RANDOM_WALKS_TEST c_api/random_walks_test.c) ConfigureCTest(CAPI_PAGERANK_TEST c_api/pagerank_test.c) ConfigureCTest(CAPI_BFS_TEST c_api/bfs_test.c) ConfigureCTest(CAPI_SSSP_TEST c_api/sssp_test.c) diff --git a/cpp/tests/c_api/bfs_test.c b/cpp/tests/c_api/bfs_test.c index 4f4b1e6e67d..05493209221 100644 --- a/cpp/tests/c_api/bfs_test.c +++ b/cpp/tests/c_api/bfs_test.c @@ -48,7 +48,7 @@ int generic_bfs_test(vertex_t* h_src, cugraph_type_erased_device_array_t* p_sources = NULL; cugraph_type_erased_device_array_view_t* p_source_view = NULL; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); ret_code = create_test_graph( diff --git a/cpp/tests/c_api/c_test_utils.h b/cpp/tests/c_api/c_test_utils.h index 3e71b3c0f39..2cfc80fbdc1 100644 --- a/cpp/tests/c_api/c_test_utils.h +++ b/cpp/tests/c_api/c_test_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#include #include +#include #include #include @@ -28,15 +28,19 @@ } \ } +#ifdef __cplusplus +extern "C" { +#endif + /* * Runs the function pointed to by "test" and returns the return code. Also * prints reporting info (using "test_name"): pass/fail and run time, to stdout. * * Intended to be used by the RUN_TEST macro. */ -int run_test(int (*test)(), const char* test_name); +int run_sg_test(int (*test)(), const char* test_name); -#define RUN_TEST(test_name) run_test(test_name, #test_name) +#define RUN_TEST(test_name) run_sg_test(test_name, #test_name) int nearlyEqual(float a, float b, float epsilon); int create_test_graph(const cugraph_resource_handle_t* p_handle, @@ -47,3 +51,10 @@ int create_test_graph(const cugraph_resource_handle_t* p_handle, bool_t store_transposed, cugraph_graph_t** p_graph, cugraph_error_t** ret_error); + +void* create_raft_handle(int prows); +void free_raft_handle(void* raft_handle); + +#ifdef __cplusplus +} +#endif diff --git a/cpp/tests/c_api/create_graph_test.c b/cpp/tests/c_api/create_graph_test.c index 63837b52074..97c1533e38b 100644 --- a/cpp/tests/c_api/create_graph_test.c +++ b/cpp/tests/c_api/create_graph_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ int test_create_sg_graph_simple() data_type_id_t edge_tid = INT32; data_type_id_t weight_tid = FLOAT32; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); cugraph_type_erased_device_array_t* src; diff --git a/cpp/tests/c_api/create_sg_graph_envelope_test.c b/cpp/tests/c_api/create_sg_graph_envelope_test.c index e6e6c91d1a2..14a5ac3cf1c 100644 --- a/cpp/tests/c_api/create_sg_graph_envelope_test.c +++ b/cpp/tests/c_api/create_sg_graph_envelope_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ int test_create_sg_graph_simple() data_type_id_t edge_tid = INT32; data_type_id_t weight_tid = FLOAT32; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); runtime_assert(p_handle != NULL, "resource handle creation failed."); ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); diff --git a/cpp/tests/c_api/extract_paths_test.c b/cpp/tests/c_api/extract_paths_test.c index 3f9ea8e3911..2509af088ec 100644 --- a/cpp/tests/c_api/extract_paths_test.c +++ b/cpp/tests/c_api/extract_paths_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ int generic_bfs_test_with_extract_paths(vertex_t* h_src, cugraph_type_erased_device_array_view_t* p_sources_view = NULL; cugraph_type_erased_device_array_view_t* p_destinations_view = NULL; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); ret_code = create_test_graph( diff --git a/cpp/tests/c_api/mg_create_graph_test.c b/cpp/tests/c_api/mg_create_graph_test.c new file mode 100644 index 00000000000..94ce23e4235 --- /dev/null +++ b/cpp/tests/c_api/mg_create_graph_test.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "c_test_utils.h" /* RUN_TEST */ +#include "mg_test_utils.h" /* RUN_TEST */ + +#include + +#include +#include +#include + +/* + * Simple check of creating a graph from a COO on device memory. + */ +int test_create_mg_graph_simple(const cugraph_resource_handle_t* handle) +{ + int test_ret_value = 0; + + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; + + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + cugraph_error_t* ret_error; + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + + cugraph_graph_t* p_graph = NULL; + cugraph_graph_properties_t properties; + + properties.is_symmetric = FALSE; + properties.is_multigraph = FALSE; + + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; + + cugraph_type_erased_device_array_t* src; + cugraph_type_erased_device_array_t* dst; + cugraph_type_erased_device_array_t* wgt; + cugraph_type_erased_device_array_view_t* src_view; + cugraph_type_erased_device_array_view_t* dst_view; + cugraph_type_erased_device_array_view_t* wgt_view; + + int my_rank = cugraph_resource_handle_get_rank(handle); + + for (int i = 0; i < num_edges; ++i) { + h_src[i] += 10 * my_rank; + h_dst[i] += 10 * my_rank; + } + + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, vertex_tid, &src, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src create failed."); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, cugraph_error_message(ret_error)); + + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, vertex_tid, &dst, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst create failed."); + + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, weight_tid, &wgt, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt create failed."); + + src_view = cugraph_type_erased_device_array_view(src); + dst_view = cugraph_type_erased_device_array_view(dst); + wgt_view = cugraph_type_erased_device_array_view(wgt); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, src_view, (byte_t*)h_src, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, dst_view, (byte_t*)h_dst, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst copy_from_host failed."); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, wgt_view, (byte_t*)h_wgt, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt copy_from_host failed."); + + ret_code = cugraph_mg_graph_create(handle, + &properties, + src_view, + dst_view, + wgt_view, + FALSE, + num_edges, + TRUE, + &p_graph, + &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "graph creation failed."); + + cugraph_mg_graph_free(p_graph); + + cugraph_type_erased_device_array_view_free(wgt_view); + cugraph_type_erased_device_array_view_free(dst_view); + cugraph_type_erased_device_array_view_free(src_view); + cugraph_type_erased_device_array_free(wgt); + cugraph_type_erased_device_array_free(dst); + cugraph_type_erased_device_array_free(src); + + cugraph_error_free(ret_error); + + return test_ret_value; +} + +/******************************************************************************/ + +int main(int argc, char** argv) +{ + // Set up MPI: + int comm_rank; + int comm_size; + int num_gpus_per_node; + cudaError_t status; + int mpi_status; + int result = 0; + cugraph_resource_handle_t* handle = NULL; + cugraph_error_t* ret_error; + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + int prows = 1; + + C_MPI_TRY(MPI_Init(&argc, &argv)); + C_MPI_TRY(MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank)); + C_MPI_TRY(MPI_Comm_size(MPI_COMM_WORLD, &comm_size)); + C_CUDA_TRY(cudaGetDeviceCount(&num_gpus_per_node)); + C_CUDA_TRY(cudaSetDevice(comm_rank % num_gpus_per_node)); + +#if 0 + // TODO: Need something a bit more sophisticated for bigger systems + prows = (int)sqrt((double)comm_size); + while (comm_size % prows != 0) { + --prows; + } + + ret_code = cugraph_resource_handle_init_comms(handle, prows, &ret_error); + TEST_ASSERT(result, ret_code == CUGRAPH_SUCCESS, "handle create failed."); + TEST_ASSERT(result, ret_code == CUGRAPH_SUCCESS, cugraph_error_message(ret_error)); +#endif + + void* raft_handle = create_raft_handle(prows); + handle = cugraph_create_resource_handle(raft_handle); + + if (result == 0) { + result |= RUN_MG_TEST(test_create_mg_graph_simple, handle); + + cugraph_free_resource_handle(handle); + } + + free_raft_handle(raft_handle); + + C_MPI_TRY(MPI_Finalize()); + + return result; +} diff --git a/cpp/tests/c_api/mg_pagerank_test.c b/cpp/tests/c_api/mg_pagerank_test.c new file mode 100644 index 00000000000..453b493b484 --- /dev/null +++ b/cpp/tests/c_api/mg_pagerank_test.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "c_test_utils.h" /* RUN_TEST */ +#include "mg_test_utils.h" /* RUN_TEST */ + +#include +#include + +#include + +typedef int32_t vertex_t; +typedef int32_t edge_t; +typedef float weight_t; + +int generic_pagerank_test(const cugraph_resource_handle_t* handle, + vertex_t* h_src, + vertex_t* h_dst, + weight_t* h_wgt, + weight_t* h_result, + size_t num_vertices, + size_t num_edges, + bool_t store_transposed, + double alpha, + double epsilon, + size_t max_iterations) +{ + int test_ret_value = 0; + + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + cugraph_error_t* ret_error; + + cugraph_graph_t* p_graph = NULL; + cugraph_pagerank_result_t* p_result = NULL; + + ret_code = create_mg_test_graph( + handle, h_src, h_dst, h_wgt, num_edges, store_transposed, &p_graph, &ret_error); + + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "create_test_graph failed."); + + ret_code = cugraph_pagerank( + handle, p_graph, NULL, alpha, epsilon, max_iterations, FALSE, FALSE, &p_result, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_pagerank failed."); + + cugraph_type_erased_device_array_view_t* vertices; + cugraph_type_erased_device_array_view_t* pageranks; + + vertices = cugraph_pagerank_result_get_vertices(p_result); + pageranks = cugraph_pagerank_result_get_pageranks(p_result); + + vertex_t h_vertices[num_vertices]; + weight_t h_pageranks[num_vertices]; + + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_vertices, vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_pageranks, pageranks, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + + size_t num_local_vertices = cugraph_type_erased_device_array_view_size(vertices); + + for (int i = 0; (i < num_local_vertices) && (test_ret_value == 0); ++i) { + TEST_ASSERT(test_ret_value, + nearlyEqual(h_result[h_vertices[i]], h_pageranks[i], 0.001), + "pagerank results don't match"); + } + + cugraph_type_erased_device_array_view_free(pageranks); + cugraph_type_erased_device_array_view_free(vertices); + cugraph_pagerank_result_free(p_result); + cugraph_sg_graph_free(p_graph); + cugraph_error_free(ret_error); + + return test_ret_value; +} + +int test_pagerank(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + weight_t h_result[] = {0.0915528, 0.168382, 0.0656831, 0.191468, 0.120677, 0.362237}; + + double alpha = 0.95; + double epsilon = 0.0001; + size_t max_iterations = 20; + + // Pagerank wants store_transposed = TRUE + return generic_pagerank_test(handle, + h_src, + h_dst, + h_wgt, + h_result, + num_vertices, + num_edges, + TRUE, + alpha, + epsilon, + max_iterations); +} + +int test_pagerank_with_transpose(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + weight_t h_result[] = {0.0915528, 0.168382, 0.0656831, 0.191468, 0.120677, 0.362237}; + + double alpha = 0.95; + double epsilon = 0.0001; + size_t max_iterations = 20; + + // Pagerank wants store_transposed = TRUE + // This call will force cugraph_pagerank to transpose the graph + // But we're passing src/dst backwards so the results will be the same + return generic_pagerank_test(handle, + h_src, + h_dst, + h_wgt, + h_result, + num_vertices, + num_edges, + FALSE, + alpha, + epsilon, + max_iterations); +} + +int test_pagerank_4(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 3; + size_t num_vertices = 4; + + vertex_t h_src[] = {0, 1, 2}; + vertex_t h_dst[] = {1, 2, 3}; + weight_t h_wgt[] = {1.f, 1.f, 1.f}; + weight_t h_result[] = { + 0.11615584790706635f, 0.21488840878009796f, 0.29881080985069275f, 0.37014490365982056f}; + + double alpha = 0.85; + double epsilon = 1.0e-6; + size_t max_iterations = 500; + + return generic_pagerank_test(handle, + h_src, + h_dst, + h_wgt, + h_result, + num_vertices, + num_edges, + FALSE, + alpha, + epsilon, + max_iterations); +} + +int test_pagerank_4_with_transpose(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 3; + size_t num_vertices = 4; + + vertex_t h_src[] = {0, 1, 2}; + vertex_t h_dst[] = {1, 2, 3}; + weight_t h_wgt[] = {1.f, 1.f, 1.f}; + weight_t h_result[] = { + 0.11615584790706635f, 0.21488840878009796f, 0.29881080985069275f, 0.37014490365982056f}; + + double alpha = 0.85; + double epsilon = 1.0e-6; + size_t max_iterations = 500; + + return generic_pagerank_test(handle, + h_src, + h_dst, + h_wgt, + h_result, + num_vertices, + num_edges, + TRUE, + alpha, + epsilon, + max_iterations); +} + +/******************************************************************************/ + +int main(int argc, char** argv) +{ + // Set up MPI: + int comm_rank; + int comm_size; + int num_gpus_per_node; + cudaError_t status; + int mpi_status; + int result = 0; + cugraph_resource_handle_t* handle = NULL; + cugraph_error_t* ret_error; + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + int prows = 1; + + C_MPI_TRY(MPI_Init(&argc, &argv)); + C_MPI_TRY(MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank)); + C_MPI_TRY(MPI_Comm_size(MPI_COMM_WORLD, &comm_size)); + C_CUDA_TRY(cudaGetDeviceCount(&num_gpus_per_node)); + C_CUDA_TRY(cudaSetDevice(comm_rank % num_gpus_per_node)); + +#if 0 + // TODO: Need something a bit more sophisticated for bigger systems + prows = (int)sqrt((double)comm_size); + while (comm_size % prows != 0) { + --prows; + } + + ret_code = cugraph_resource_handle_init_comms(handle, prows, &ret_error); + TEST_ASSERT(result, ret_code == CUGRAPH_SUCCESS, "handle create failed."); + TEST_ASSERT(result, ret_code == CUGRAPH_SUCCESS, cugraph_error_message(ret_error)); +#endif + + void* raft_handle = create_raft_handle(prows); + handle = cugraph_create_resource_handle(raft_handle); + + if (result == 0) { + result |= RUN_MG_TEST(test_pagerank, handle); + result |= RUN_MG_TEST(test_pagerank_with_transpose, handle); + result |= RUN_MG_TEST(test_pagerank_4, handle); + result |= RUN_MG_TEST(test_pagerank_4_with_transpose, handle); + + cugraph_free_resource_handle(handle); + } + + free_raft_handle(raft_handle); + + C_MPI_TRY(MPI_Finalize()); + + return result; +} diff --git a/cpp/tests/c_api/mg_test_utils.cpp b/cpp/tests/c_api/mg_test_utils.cpp new file mode 100644 index 00000000000..3b687df21de --- /dev/null +++ b/cpp/tests/c_api/mg_test_utils.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include + +extern "C" int run_mg_test(int (*test)(const cugraph_resource_handle_t*), + const char* test_name, + const cugraph_resource_handle_t* handle) +{ + int ret_val = 0; + time_t start_time, end_time; + int rank = 0; + + rank = cugraph_resource_handle_get_rank(handle); + + if (rank == 0) { + printf("RUNNING: %s...", test_name); + fflush(stdout); + + time(&start_time); + } + + ret_val = test(handle); + + if (rank == 0) { + time(&end_time); + + printf("done (%f seconds).", difftime(end_time, start_time)); + if (ret_val == 0) { + printf(" - passed\n"); + } else { + printf(" - FAILED\n"); + } + fflush(stdout); + } + + return ret_val; +} + +extern "C" void* create_raft_handle(int prows) +{ + raft::handle_t* handle = new raft::handle_t{}; + raft::comms::initialize_mpi_comms(handle, MPI_COMM_WORLD); + + cugraph::partition_2d::subcomm_factory_t + subcomm_factory(*handle, prows); + + return handle; +} + +extern "C" void free_raft_handle(void* raft_handle) +{ + raft::handle_t* handle = reinterpret_cast(raft_handle); + delete handle; +} + +/* + * Simple function to create an MG test graph from COO arrays. COO is + * assumed to be defined entirely on rank 0 and will be shuffled to + * the proper location. + */ +extern "C" int create_mg_test_graph(const cugraph_resource_handle_t* handle, + int32_t* h_src, + int32_t* h_dst, + float* h_wgt, + size_t num_edges, + bool_t store_transposed, + cugraph_graph_t** p_graph, + cugraph_error_t** ret_error) +{ + int test_ret_value = 0; + cugraph_error_code_t ret_code; + cugraph_graph_properties_t properties; + + properties.is_symmetric = FALSE; + properties.is_multigraph = FALSE; + + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; + + cugraph_type_erased_device_array_t* src; + cugraph_type_erased_device_array_t* dst; + cugraph_type_erased_device_array_t* wgt; + cugraph_type_erased_device_array_view_t* src_view; + cugraph_type_erased_device_array_view_t* dst_view; + cugraph_type_erased_device_array_view_t* wgt_view; + + int rank = 0; + + rank = cugraph_resource_handle_get_rank(handle); + + if (rank == 0) { + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, vertex_tid, &src, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src create failed."); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, cugraph_error_message(*ret_error)); + + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, vertex_tid, &dst, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst create failed."); + + ret_code = + cugraph_type_erased_device_array_create(handle, num_edges, weight_tid, &wgt, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt create failed."); + } else { + ret_code = cugraph_type_erased_device_array_create(handle, 0, vertex_tid, &src, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src create failed."); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, cugraph_error_message(*ret_error)); + + ret_code = cugraph_type_erased_device_array_create(handle, 0, vertex_tid, &dst, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst create failed."); + + ret_code = cugraph_type_erased_device_array_create(handle, 0, weight_tid, &wgt, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt create failed."); + } + + src_view = cugraph_type_erased_device_array_view(src); + dst_view = cugraph_type_erased_device_array_view(dst); + wgt_view = cugraph_type_erased_device_array_view(wgt); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, src_view, (byte_t*)h_src, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, dst_view, (byte_t*)h_dst, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst copy_from_host failed."); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, wgt_view, (byte_t*)h_wgt, ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt copy_from_host failed."); + + ret_code = cugraph_mg_graph_create(handle, + &properties, + src_view, + dst_view, + wgt_view, + store_transposed, + num_edges, + FALSE, + p_graph, + ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "graph creation failed."); + + cugraph_type_erased_device_array_view_free(wgt_view); + cugraph_type_erased_device_array_view_free(dst_view); + cugraph_type_erased_device_array_view_free(src_view); + cugraph_type_erased_device_array_free(wgt); + cugraph_type_erased_device_array_free(dst); + cugraph_type_erased_device_array_free(src); + + return test_ret_value; +} diff --git a/cpp/tests/c_api/mg_test_utils.h b/cpp/tests/c_api/mg_test_utils.h new file mode 100644 index 00000000000..ec6507c0a69 --- /dev/null +++ b/cpp/tests/c_api/mg_test_utils.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +#define C_MPI_TRY(call) \ + do { \ + int status = call; \ + if (MPI_SUCCESS != status) { \ + int mpi_error_string_lenght = 0; \ + char mpi_error_string[MPI_MAX_ERROR_STRING]; \ + MPI_Error_string(status, mpi_error_string, &mpi_error_string_lenght); \ + printf("MPI call='%s' at file=%s line=%d failed with %s ", \ + #call, \ + __FILE__, \ + __LINE__, \ + mpi_error_string); \ + exit(1); \ + } \ + } while (0) + +#define C_CUDA_TRY(call) \ + do { \ + cudaError_t const status = call; \ + if (status != cudaSuccess) { \ + cudaGetLastError(); \ + printf( \ + "CUDA error encountered at: " \ + "call='%s', Reason=%s:%s", \ + #call, \ + cudaGetErrorName(status), \ + cudaGetErrorString(status)); \ + exit(1); \ + } \ + } while (0) + +int run_mg_test(int (*test)(const cugraph_resource_handle_t*), + const char* test_name, + const cugraph_resource_handle_t* rank); + +#define RUN_MG_TEST(test_name, handle) run_mg_test(test_name, #test_name, handle) + +int create_mg_test_graph(const cugraph_resource_handle_t* p_handle, + int32_t* h_src, + int32_t* h_dst, + float* h_wgt, + size_t num_edges, + bool_t store_transposed, + cugraph_graph_t** p_graph, + cugraph_error_t** ret_error); diff --git a/cpp/tests/c_api/node2vec_test.c b/cpp/tests/c_api/node2vec_test.c index 61d96ee7b10..9436ea29427 100644 --- a/cpp/tests/c_api/node2vec_test.c +++ b/cpp/tests/c_api/node2vec_test.c @@ -51,7 +51,7 @@ int generic_node2vec_test(vertex_t* h_src, cugraph_type_erased_device_array_t* p_sources = NULL; cugraph_type_erased_device_array_view_t* p_source_view = NULL; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); ret_code = create_test_graph( diff --git a/cpp/tests/c_api/pagerank_test.c b/cpp/tests/c_api/pagerank_test.c index f8a9e71afb0..98e54d321bc 100644 --- a/cpp/tests/c_api/pagerank_test.c +++ b/cpp/tests/c_api/pagerank_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ int generic_pagerank_test(vertex_t* h_src, cugraph_graph_t* p_graph = NULL; cugraph_pagerank_result_t* p_result = NULL; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); ret_code = create_test_graph( diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 766e9c87c74..be500b2cd91 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NVIDIA CORPORATION. + * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ int test_random_walks_1() cugraph_unique_ptr_t* p_sampling_strategy = NULL; vertex_t h_start[] = {0, 2}; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); runtime_assert(p_handle != NULL, "resource handle creation failed."); ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); @@ -224,7 +224,7 @@ int test_random_walks_2() edge_t h_sizes[NUM_PATHS]; vertex_t h_paths[NUM_PATHS * MAX_DEPTH]; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); runtime_assert(p_handle != NULL, "resource handle creation failed."); ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); @@ -349,7 +349,7 @@ int test_random_walks_3() dbuf_start.data_ = NULL; dbuf_start.size_ = 0; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); runtime_assert(p_handle != NULL, "resource handle creation failed."); ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); diff --git a/cpp/tests/c_api/sssp_test.c b/cpp/tests/c_api/sssp_test.c index 4b210d3bcc7..e9cec74a7b5 100644 --- a/cpp/tests/c_api/sssp_test.c +++ b/cpp/tests/c_api/sssp_test.c @@ -48,7 +48,7 @@ int generic_sssp_test(vertex_t* h_src, cugraph_graph_t* p_graph = NULL; cugraph_paths_result_t* p_result = NULL; - p_handle = cugraph_create_resource_handle(); + p_handle = cugraph_create_resource_handle(NULL); TEST_ASSERT(test_ret_value, p_handle != NULL, "resource handle creation failed."); ret_code = create_test_graph( diff --git a/cpp/tests/c_api/test_utils.c b/cpp/tests/c_api/test_utils.cpp similarity index 81% rename from cpp/tests/c_api/test_utils.c rename to cpp/tests/c_api/test_utils.cpp index 95a765f6b2b..c09ed4725ce 100644 --- a/cpp/tests/c_api/test_utils.c +++ b/cpp/tests/c_api/test_utils.cpp @@ -18,7 +18,7 @@ #include -int nearlyEqual(float a, float b, float epsilon) +extern "C" int nearlyEqual(float a, float b, float epsilon) { // FIXME: There is a better test than this, // perhaps use the gtest comparison for consistency @@ -29,14 +29,14 @@ int nearlyEqual(float a, float b, float epsilon) /* * Simple check of creating a graph from a COO on device memory. */ -int create_test_graph(const cugraph_resource_handle_t* p_handle, - int32_t* h_src, - int32_t* h_dst, - float* h_wgt, - size_t num_edges, - bool_t store_transposed, - cugraph_graph_t** p_graph, - cugraph_error_t** ret_error) +extern "C" int create_test_graph(const cugraph_resource_handle_t* p_handle, + int32_t* h_src, + int32_t* h_dst, + float* h_wgt, + size_t num_edges, + bool_t store_transposed, + cugraph_graph_t** p_graph, + cugraph_error_t** ret_error) { int test_ret_value = 0; cugraph_error_code_t ret_code; @@ -73,16 +73,16 @@ int create_test_graph(const cugraph_resource_handle_t* p_handle, dst_view = cugraph_type_erased_device_array_view(dst); wgt_view = cugraph_type_erased_device_array_view(wgt); - ret_code = - cugraph_type_erased_device_array_view_copy_from_host(p_handle, src_view, (byte_t*)h_src, ret_error); + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + p_handle, src_view, (byte_t*)h_src, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); - ret_code = - cugraph_type_erased_device_array_view_copy_from_host(p_handle, dst_view, (byte_t*)h_dst, ret_error); + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + p_handle, dst_view, (byte_t*)h_dst, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst copy_from_host failed."); - ret_code = - cugraph_type_erased_device_array_view_copy_from_host(p_handle, wgt_view, (byte_t*)h_wgt, ret_error); + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + p_handle, wgt_view, (byte_t*)h_wgt, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt copy_from_host failed."); ret_code = cugraph_sg_graph_create(p_handle, @@ -113,7 +113,7 @@ int create_test_graph(const cugraph_resource_handle_t* p_handle, * * Intended to be used by the RUN_TEST macro. */ -int run_test(int (*test)(), const char* test_name) +extern "C" int run_sg_test(int (*test)(), const char* test_name) { int ret_val = 0; time_t start_time, end_time; @@ -122,7 +122,9 @@ int run_test(int (*test)(), const char* test_name) fflush(stdout); time(&start_time); + ret_val = test(); + time(&end_time); printf("done (%f seconds).", difftime(end_time, start_time)); diff --git a/python/pylibcugraph/pylibcugraph/_cugraph_c/algorithms.pxd b/python/pylibcugraph/pylibcugraph/_cugraph_c/algorithms.pxd index e60db32924f..72474a4a5fa 100644 --- a/python/pylibcugraph/pylibcugraph/_cugraph_c/algorithms.pxd +++ b/python/pylibcugraph/pylibcugraph/_cugraph_c/algorithms.pxd @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, cugraph_resource_handle_t, ) diff --git a/python/pylibcugraph/pylibcugraph/_cugraph_c/array.pxd b/python/pylibcugraph/pylibcugraph/_cugraph_c/array.pxd index 91998d477d3..c399b67d3ca 100644 --- a/python/pylibcugraph/pylibcugraph/_cugraph_c/array.pxd +++ b/python/pylibcugraph/pylibcugraph/_cugraph_c/array.pxd @@ -18,7 +18,7 @@ from pylibcugraph._cugraph_c.error cimport ( cugraph_error_code_t, cugraph_error_t, ) -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( cugraph_resource_handle_t, data_type_id_t, byte_t, diff --git a/python/pylibcugraph/pylibcugraph/_cugraph_c/graph.pxd b/python/pylibcugraph/pylibcugraph/_cugraph_c/graph.pxd index 8cc4b06093e..e5313f710c1 100644 --- a/python/pylibcugraph/pylibcugraph/_cugraph_c/graph.pxd +++ b/python/pylibcugraph/pylibcugraph/_cugraph_c/graph.pxd @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, cugraph_resource_handle_t, ) diff --git a/python/pylibcugraph/pylibcugraph/_cugraph_c/cugraph_api.pxd b/python/pylibcugraph/pylibcugraph/_cugraph_c/resource_handle.pxd similarity index 78% rename from python/pylibcugraph/pylibcugraph/_cugraph_c/cugraph_api.pxd rename to python/pylibcugraph/pylibcugraph/_cugraph_c/resource_handle.pxd index 276b8062849..f00d0f72616 100644 --- a/python/pylibcugraph/pylibcugraph/_cugraph_c/cugraph_api.pxd +++ b/python/pylibcugraph/pylibcugraph/_cugraph_c/resource_handle.pxd @@ -17,7 +17,7 @@ from libc.stdint cimport int8_t -cdef extern from "cugraph_c/cugraph_api.h": +cdef extern from "cugraph_c/resource_handle.h": ctypedef enum bool_t: FALSE @@ -34,8 +34,16 @@ cdef extern from "cugraph_c/cugraph_api.h": ctypedef struct cugraph_resource_handle_t: pass + # FIXME: the void* raft_handle arg will change in a future release cdef cugraph_resource_handle_t* \ - cugraph_create_resource_handle() + cugraph_create_resource_handle( + void* raft_handle + ) + + cdef int \ + cugraph_resource_handle_get_rank( + const cugraph_resource_handle_t* handle + ) cdef void \ cugraph_free_resource_handle( diff --git a/python/pylibcugraph/pylibcugraph/graphs.pyx b/python/pylibcugraph/pylibcugraph/graphs.pyx index 0a011622880..c6038650869 100644 --- a/python/pylibcugraph/pylibcugraph/graphs.pyx +++ b/python/pylibcugraph/pylibcugraph/graphs.pyx @@ -16,7 +16,7 @@ from libc.stdint cimport uintptr_t -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, cugraph_resource_handle_t, data_type_id_t, diff --git a/python/pylibcugraph/pylibcugraph/node2vec.pyx b/python/pylibcugraph/pylibcugraph/node2vec.pyx index be2b0259f2a..ec45b234d92 100644 --- a/python/pylibcugraph/pylibcugraph/node2vec.pyx +++ b/python/pylibcugraph/pylibcugraph/node2vec.pyx @@ -16,7 +16,7 @@ from libc.stdint cimport uintptr_t -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, data_type_id_t, cugraph_resource_handle_t, diff --git a/python/pylibcugraph/pylibcugraph/pagerank.pyx b/python/pylibcugraph/pylibcugraph/pagerank.pyx index 8c51b6cd578..0c46d2f97b7 100644 --- a/python/pylibcugraph/pylibcugraph/pagerank.pyx +++ b/python/pylibcugraph/pylibcugraph/pagerank.pyx @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, data_type_id_t, cugraph_resource_handle_t, diff --git a/python/pylibcugraph/pylibcugraph/resource_handle.pxd b/python/pylibcugraph/pylibcugraph/resource_handle.pxd index 341110acc82..a150b7eb841 100644 --- a/python/pylibcugraph/pylibcugraph/resource_handle.pxd +++ b/python/pylibcugraph/pylibcugraph/resource_handle.pxd @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( cugraph_resource_handle_t, ) diff --git a/python/pylibcugraph/pylibcugraph/resource_handle.pyx b/python/pylibcugraph/pylibcugraph/resource_handle.pyx index 7e78262bbc4..a323751f2fb 100644 --- a/python/pylibcugraph/pylibcugraph/resource_handle.pyx +++ b/python/pylibcugraph/pylibcugraph/resource_handle.pyx @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( cugraph_create_resource_handle, cugraph_free_resource_handle, ) @@ -26,7 +26,7 @@ cdef class EXPERIMENTAL__ResourceHandle: the corresponding pointer to a cugraph_resource_handle_t """ def __cinit__(self): - self.c_resource_handle_ptr = cugraph_create_resource_handle() + self.c_resource_handle_ptr = cugraph_create_resource_handle(NULL) # FIXME: check for error def __dealloc__(self): diff --git a/python/pylibcugraph/pylibcugraph/sssp.pyx b/python/pylibcugraph/pylibcugraph/sssp.pyx index 9300965ae9a..fdac4c0697d 100644 --- a/python/pylibcugraph/pylibcugraph/sssp.pyx +++ b/python/pylibcugraph/pylibcugraph/sssp.pyx @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( bool_t, data_type_id_t, cugraph_resource_handle_t, diff --git a/python/pylibcugraph/pylibcugraph/utils.pxd b/python/pylibcugraph/pylibcugraph/utils.pxd index 32fa94f697b..1a357f048d4 100644 --- a/python/pylibcugraph/pylibcugraph/utils.pxd +++ b/python/pylibcugraph/pylibcugraph/utils.pxd @@ -14,7 +14,7 @@ # Have cython use python 3 syntax # cython: language_level = 3 -from pylibcugraph._cugraph_c.cugraph_api cimport ( +from pylibcugraph._cugraph_c.resource_handle cimport ( data_type_id_t, cugraph_resource_handle_t, )