From 03a20551f9059acbedbaaba0a744b884d5fe63f8 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 31 Aug 2021 15:09:57 -0500 Subject: [PATCH 01/48] Prepare extended API for RW. --- cpp/include/cugraph/algorithms.hpp | 10 +++--- cpp/include/cugraph/api_helpers.hpp | 43 +++++++++++++++++++++++++ cpp/src/sampling/random_walks.cu | 12 +++---- cpp/src/sampling/random_walks.cuh | 9 ++++-- cpp/src/sampling/rw_traversals.hpp | 3 +- cpp/tests/sampling/random_walks_test.cu | 10 ++++-- 6 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 cpp/include/cugraph/api_helpers.hpp diff --git a/cpp/include/cugraph/algorithms.hpp b/cpp/include/cugraph/algorithms.hpp index a117b396016..975bf473dff 100644 --- a/cpp/include/cugraph/algorithms.hpp +++ b/cpp/include/cugraph/algorithms.hpp @@ -15,6 +15,8 @@ */ #pragma once +#include + #include #include #include @@ -1344,8 +1346,8 @@ extract_ego(raft::handle_t const& handle, * (compressed) format; when padding is used the output is a matrix of vertex paths and a matrix of * edges paths (weights); in this case the matrices are stored in row major order; the vertex path * matrix is padded with `num_vertices` values and the weight matrix is padded with `0` values; - * @param selector_type identifier for sampling strategy: uniform, biased, etc.; possible - * values{0==uniform, 1==biased}; defaults to 0 == uniform; + * @param sampling_strategy pointer for sampling strategy: uniform, biased, etc.; possible + * values{0==uniform, 1==biased, 2==node2vec}; defaults to nullptr == uniform; * @return std::tuple, rmm::device_uvector, * rmm::device_uvector> Triplet of either padded or coalesced RW paths; in the coalesced * case (default), the return consists of corresponding vertex and edge weights for each, and @@ -1365,8 +1367,8 @@ random_walks(raft::handle_t const& handle, typename graph_t::vertex_type const* ptr_d_start, index_t num_paths, index_t max_depth, - bool use_padding = false, - int selector_type = 0); + bool use_padding = false, + std::unique_ptr sampling_strategy = nullptr); /** * @brief Finds (weakly-connected-)component IDs of each vertices in the input graph. diff --git a/cpp/include/cugraph/api_helpers.hpp b/cpp/include/cugraph/api_helpers.hpp new file mode 100644 index 00000000000..9aa82b03847 --- /dev/null +++ b/cpp/include/cugraph/api_helpers.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, 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. + */ + +// Andrei Schaffer, aschaffer@nvidia.com +// +// This is a collection of aggregates used by (parts of) the API defined in algorithms.hpp; +// These aggregates get propagated to the C-only API (which is why they're non-template aggregates) + +#pragma once + +namespace cugraph { + +enum class sampling_strategy_t : int { UNIFORM = 0, BIASED, NODE2VEC }; + +struct sampling_params_t { + sampling_params_t(void) {} + + sampling_params_t(int sampling_type, double p = 1.0, double q = 1.0) + : sampling_type_(static_cast(sampling_type)), p_(p), q_(q) + { + } + + sampling_strategy_t sampling_type_{sampling_strategy_t::UNIFORM}; + + // node2vec specific: + // + double p_; + double q_; +}; +} // namespace cugraph diff --git a/cpp/src/sampling/random_walks.cu b/cpp/src/sampling/random_walks.cu index bd6cc861cd2..7526f1b7674 100644 --- a/cpp/src/sampling/random_walks.cu +++ b/cpp/src/sampling/random_walks.cu @@ -31,7 +31,7 @@ template std:: int32_t num_paths, int32_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); template std:: tuple, rmm::device_uvector, rmm::device_uvector> @@ -41,7 +41,7 @@ template std:: int64_t num_paths, int64_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); template std:: tuple, rmm::device_uvector, rmm::device_uvector> @@ -51,7 +51,7 @@ template std:: int64_t num_paths, int64_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); //} // // SG FP64{ @@ -63,7 +63,7 @@ template std:: int32_t num_paths, int32_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); template std:: tuple, rmm::device_uvector, rmm::device_uvector> @@ -73,7 +73,7 @@ template std:: int64_t num_paths, int64_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); template std:: tuple, rmm::device_uvector, rmm::device_uvector> @@ -83,7 +83,7 @@ template std:: int64_t num_paths, int64_t max_depth, bool use_padding, - int selector_type); + std::unique_ptr sampling_strategy); //} template std:: diff --git a/cpp/src/sampling/random_walks.cuh b/cpp/src/sampling/random_walks.cuh index 159c1b455ea..72eb326fbe9 100644 --- a/cpp/src/sampling/random_walks.cuh +++ b/cpp/src/sampling/random_walks.cuh @@ -1073,7 +1073,7 @@ random_walks(raft::handle_t const& handle, index_t num_paths, index_t max_depth, bool use_padding, - int selector_type) + std::unique_ptr sampling_strategy) { using vertex_t = typename graph_t::vertex_type; using edge_t = typename graph_t::edge_type; @@ -1111,8 +1111,11 @@ random_walks(raft::handle_t const& handle, << "WARNING: Due to GPU memory availability, slower vertical traversal will be used.\n"; } + int selector_type{0}; + if (sampling_strategy) selector_type = static_cast(sampling_strategy->sampling_type_); + if (use_vertical_strategy) { - if (selector_type == static_cast(detail::sampling_t::BIASED)) { + if (selector_type == static_cast(sampling_strategy_t::BIASED)) { detail::biased_selector_t selector{handle, graph, real_t{0}}; auto quad_tuple = @@ -1138,7 +1141,7 @@ random_walks(raft::handle_t const& handle, std::move(std::get<2>(quad_tuple))); } } else { - if (selector_type == static_cast(detail::sampling_t::BIASED)) { + if (selector_type == static_cast(sampling_strategy_t::BIASED)) { detail::biased_selector_t selector{handle, graph, real_t{0}}; auto quad_tuple = diff --git a/cpp/src/sampling/rw_traversals.hpp b/cpp/src/sampling/rw_traversals.hpp index 3d3ffc4e161..8ccd1b8d76e 100644 --- a/cpp/src/sampling/rw_traversals.hpp +++ b/cpp/src/sampling/rw_traversals.hpp @@ -18,6 +18,7 @@ // #pragma once +#include #include #include #include @@ -44,8 +45,6 @@ namespace cugraph { namespace detail { -enum class sampling_t : int { UNIFORM = 0, BIASED }; // sampling strategy; others: NODE2VEC - template using device_vec_t = rmm::device_uvector; diff --git a/cpp/tests/sampling/random_walks_test.cu b/cpp/tests/sampling/random_walks_test.cu index 7c35440a9b5..10a417c921d 100644 --- a/cpp/tests/sampling/random_walks_test.cu +++ b/cpp/tests/sampling/random_walks_test.cu @@ -133,8 +133,14 @@ class Tests_RandomWalks edge_t max_depth{10}; if (trv_id == traversal_id_t::HORIZONTAL) { - auto ret_tuple = cugraph::random_walks( - handle, graph_view, d_start_view.begin(), num_paths, max_depth, false, sampling_id); + auto ret_tuple = + cugraph::random_walks(handle, + graph_view, + d_start_view.begin(), + num_paths, + max_depth, + false, + std::make_unique(sampling_id)); // check results: // From b7b87a242a5cd58403377427492b9d18adba6aad Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Thu, 2 Sep 2021 18:40:20 -0500 Subject: [PATCH 02/48] Preliminary RW type-erasure. Needs work. --- cpp/include/cugraph/visitors/rw_visitor.hpp | 74 ++++++++++ cpp/src/visitors/rw_visitor.cpp | 143 ++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 cpp/include/cugraph/visitors/rw_visitor.hpp create mode 100644 cpp/src/visitors/rw_visitor.cpp diff --git a/cpp/include/cugraph/visitors/rw_visitor.hpp b/cpp/include/cugraph/visitors/rw_visitor.hpp new file mode 100644 index 00000000000..15183f38a66 --- /dev/null +++ b/cpp/include/cugraph/visitors/rw_visitor.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021, 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 "erased_pack.hpp" +#include "graph_envelope.hpp" +#include "ret_terased.hpp" + +namespace cugraph { +namespace visitors { + +// primary empty template: +// +template +struct rw_visitor; + +// dummy out non-candidate instantiation paths: +// +template +struct rw_visitor)>> : visitor_t { + void visit_graph(graph_envelope_t::base_graph_t const&) override + { + // purposely empty + } + return_t const& get_result(void) const override + { + static return_t r{}; + return r; + } +}; + +template +struct rw_visitor::value>> : visitor_t { + rw_visitor(erased_pack_t& ep) : ep_(ep) {} + + void visit_graph(graph_envelope_t::base_graph_t const&) override; + + return_t const& get_result(void) const override { return result_; } + + private: + erased_pack_t& ep_; + return_t result_; +}; + +} // namespace visitors +} // namespace cugraph diff --git a/cpp/src/visitors/rw_visitor.cpp b/cpp/src/visitors/rw_visitor.cpp new file mode 100644 index 00000000000..d3248274651 --- /dev/null +++ b/cpp/src/visitors/rw_visitor.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2021, 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 + +namespace cugraph { +namespace visitors { +// +// wrapper code: +// +template +void rw_visitor::value>>:: + visit_graph(graph_envelope_t::base_graph_t const& graph) +{ + using index_t = edge_t; + using ptr_params_t = std::unique_ptr; + + // Note: this must be called only on: + // graph_view_t + // + if constexpr (st == false && mg == false) { + // unless algorithms only call virtual graph methods + // under the hood, the algos require this conversion: + // + graph_t const* p_g = + static_cast const*>(&graph); + + auto gview = p_g->view(); + + auto const& v_args = ep_.get_args(); + + // unpack bfs() args: + // + assert(v_args.size() == 6); + + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); + + vertex_t* p_d_start = static_cast(v_args[1]); + + index_t num_paths = *static_cast(v_args[2]); + + index_t max_depth = *static_cast(v_args[3]); + + bool use_padding = *static_cast(v_args[4]); + + ptr_params_t p_uniq_params = *static_cast(v_args[5]); + + // call algorithm + // + auto tpl_result = + random_walks(handle, gview, p_d_start, num_paths, max_depth, use_padding, p_uniq_params); + + result_ = return_t{tpl_result}; + } else { + CUGRAPH_FAIL( + "Unsupported RandomWalks algorithm (store_transposed == true or multi_gpu == true)."); + } +} + +// EIDir's: +// +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +//------ + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +//------ + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +template class rw_visitor; +template class rw_visitor; + +} // namespace visitors + +namespace api { +using namespace cugraph::visitors; +// wrapper: +// macro option: MAKE_WRAPPER(bfs) +// +return_t random_walks(graph_envelope_t const& g, erased_pack_t& ep) +{ + auto p_visitor = g.factory()->make_rw_visitor(ep); + + g.apply(*p_visitor); + + return_t ret{p_visitor->get_result()}; + + return ret; // RVO-ed; +} + +} // namespace api + +} // namespace cugraph From af0e21b721835a46d0c1993e337218750edebe2f Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Sat, 4 Sep 2021 13:31:54 -0500 Subject: [PATCH 03/48] Fixed typed-erased return to work with move-only semantics. Fixed visitor code flow for RW visitor. --- cpp/CMakeLists.txt | 1 + cpp/include/cugraph/visitors/bfs_visitor.hpp | 8 +++++ .../cugraph/visitors/graph_envelope.hpp | 8 +++++ cpp/include/cugraph/visitors/ret_terased.hpp | 30 +++++++++++++++---- cpp/include/cugraph/visitors/rw_visitor.hpp | 12 ++++++-- cpp/src/sampling/rw_traversals.hpp | 2 ++ cpp/src/visitors/bfs_visitor.cpp | 4 +-- cpp/src/visitors/rw_visitor.cpp | 12 ++++---- cpp/src/visitors/visitors_factory.cpp | 16 +++++++++- 9 files changed, 74 insertions(+), 19 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 803b01edeac..d01c1a7dbe3 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -205,6 +205,7 @@ add_library(cugraph SHARED src/visitors/graph_envelope.cpp src/visitors/visitors_factory.cpp src/visitors/bfs_visitor.cpp + src/visitors/rw_visitor.cpp ) set_target_properties(cugraph diff --git a/cpp/include/cugraph/visitors/bfs_visitor.hpp b/cpp/include/cugraph/visitors/bfs_visitor.hpp index 55a008dcff7..d16f506819a 100644 --- a/cpp/include/cugraph/visitors/bfs_visitor.hpp +++ b/cpp/include/cugraph/visitors/bfs_visitor.hpp @@ -56,6 +56,12 @@ struct bfs_visitor @@ -71,6 +77,8 @@ struct bfs_visitor make_louvain_visitor(erased_pack_t&) const = 0; virtual std::unique_ptr make_bfs_visitor(erased_pack_t&) const = 0; + + virtual std::unique_ptr make_rw_visitor(erased_pack_t&) const = 0; }; using pair_uniques_t = @@ -124,6 +126,8 @@ class visitor_t { virtual void visit_graph(graph_envelope_t::base_graph_t const&) = 0; virtual return_t const& get_result(void) const = 0; + + virtual return_t&& get_result(void) = 0; }; // convenience templatized base: @@ -162,6 +166,8 @@ struct dependent_factory_t make_louvain_visitor(erased_pack_t&) const override { return nullptr; } std::unique_ptr make_bfs_visitor(erased_pack_t&) const override { return nullptr; } + + std::unique_ptr make_rw_visitor(erased_pack_t&) const override { return nullptr; } }; template @@ -179,6 +185,8 @@ struct dependent_factory_t make_louvain_visitor(erased_pack_t&) const override; std::unique_ptr make_bfs_visitor(erased_pack_t&) const override; + + std::unique_ptr make_rw_visitor(erased_pack_t&) const override; }; // utility factory selector: diff --git a/cpp/include/cugraph/visitors/ret_terased.hpp b/cpp/include/cugraph/visitors/ret_terased.hpp index 19a7920e81b..f6ad88d8ede 100644 --- a/cpp/include/cugraph/visitors/ret_terased.hpp +++ b/cpp/include/cugraph/visitors/ret_terased.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace cugraph { namespace visitors { @@ -28,7 +29,7 @@ struct return_t { struct base_return_t { virtual ~base_return_t(void) {} - virtual void copy(return_t const&) = 0; + virtual void copy(return_t&&) = 0; virtual std::unique_ptr clone(void) const = 0; }; @@ -36,15 +37,25 @@ struct return_t { struct generic_return_t : base_return_t { generic_return_t(T const& t) : return_(t) {} - void copy(return_t const& r) override + generic_return_t(T&& t) : return_(std::move(t)) {} + + void copy(return_t&& r) override { - base_return_t const* p_B = static_cast(r.p_impl_.get()); - return_ = *(dynamic_cast(p_B)); + if constexpr (std::is_copy_constructible_v) { + base_return_t const* p_B = static_cast(r.p_impl_.get()); + return_ = *(dynamic_cast(p_B)); + } else { + base_return_t* p_B = static_cast(r.p_impl_.get()); + return_ = std::move(*(dynamic_cast(p_B))); + } } std::unique_ptr clone(void) const override { - return std::make_unique>(return_); + if constexpr (std::is_copy_constructible_v) + return std::make_unique>(return_); + else + throw std::runtime_error("ERROR: cannot clone object that is not copy constructible."); } T const& get(void) const { return return_; } @@ -60,6 +71,11 @@ struct return_t { { } + template + return_t(T&& t) : p_impl_(std::make_unique>(std::move(t))) + { + } + return_t(return_t const& r) : p_impl_{r.clone()} {} return_t& operator=(return_t const& r) @@ -84,7 +100,7 @@ struct return_t { } template - T get(void) const + T const& get(void) const { if (p_impl_) { generic_return_t const* p = static_cast const*>(p_impl_.get()); @@ -93,6 +109,8 @@ struct return_t { throw std::runtime_error("ERROR: nullptr impl."); } + void const* get_ptr(void) const { return static_cast(p_impl_.get()); } + private: std::unique_ptr p_impl_; }; diff --git a/cpp/include/cugraph/visitors/rw_visitor.hpp b/cpp/include/cugraph/visitors/rw_visitor.hpp index 15183f38a66..a641efd27ad 100644 --- a/cpp/include/cugraph/visitors/rw_visitor.hpp +++ b/cpp/include/cugraph/visitors/rw_visitor.hpp @@ -40,7 +40,8 @@ struct rw_visitor)>> : visitor_t { + std::enable_if_t<(!is_candidate::value)>> + : visitor_t { void visit_graph(graph_envelope_t::base_graph_t const&) override { // purposely empty @@ -50,6 +51,12 @@ struct rw_visitor @@ -58,12 +65,13 @@ struct rw_visitor::value>> : visitor_t { + std::enable_if_t::value>> : visitor_t { rw_visitor(erased_pack_t& ep) : ep_(ep) {} void visit_graph(graph_envelope_t::base_graph_t const&) override; return_t const& get_result(void) const override { return result_; } + return_t&& get_result(void) override { return std::move(result_); } private: erased_pack_t& ep_; diff --git a/cpp/src/sampling/rw_traversals.hpp b/cpp/src/sampling/rw_traversals.hpp index 8ccd1b8d76e..625f7074c7f 100644 --- a/cpp/src/sampling/rw_traversals.hpp +++ b/cpp/src/sampling/rw_traversals.hpp @@ -238,6 +238,8 @@ struct visitor_aggregate_weights_t : visitors::visitor_t { // visitors::return_t const& get_result(void) const override { return ret_unused_; } + visitors::return_t&& get_result(void) override { return std::move(ret_unused_); } + rmm::device_uvector&& get_aggregated_weights(void) { return std::move(d_aggregate_weights_); diff --git a/cpp/src/visitors/bfs_visitor.cpp b/cpp/src/visitors/bfs_visitor.cpp index 672cc35f00b..e18b65a7fb2 100644 --- a/cpp/src/visitors/bfs_visitor.cpp +++ b/cpp/src/visitors/bfs_visitor.cpp @@ -133,9 +133,7 @@ return_t bfs(graph_envelope_t const& g, erased_pack_t& ep) g.apply(*p_visitor); - return_t ret{p_visitor->get_result()}; - - return ret; // RVO-ed; + return p_visitor->get_result(); } } // namespace api diff --git a/cpp/src/visitors/rw_visitor.cpp b/cpp/src/visitors/rw_visitor.cpp index d3248274651..fe9c72ded3f 100644 --- a/cpp/src/visitors/rw_visitor.cpp +++ b/cpp/src/visitors/rw_visitor.cpp @@ -64,14 +64,14 @@ void rw_visitor(v_args[4]); - ptr_params_t p_uniq_params = *static_cast(v_args[5]); + ptr_params_t p_uniq_params = std::move(*static_cast(v_args[5])); // call algorithm // - auto tpl_result = - random_walks(handle, gview, p_d_start, num_paths, max_depth, use_padding, p_uniq_params); + auto tpl_result = random_walks( + handle, gview, p_d_start, num_paths, max_depth, use_padding, std::move(p_uniq_params)); - result_ = return_t{tpl_result}; + result_ = return_t{std::move(tpl_result)}; } else { CUGRAPH_FAIL( "Unsupported RandomWalks algorithm (store_transposed == true or multi_gpu == true)."); @@ -133,9 +133,7 @@ return_t random_walks(graph_envelope_t const& g, erased_pack_t& ep) g.apply(*p_visitor); - return_t ret{p_visitor->get_result()}; - - return ret; // RVO-ed; + return p_visitor->get_result(); } } // namespace api diff --git a/cpp/src/visitors/visitors_factory.cpp b/cpp/src/visitors/visitors_factory.cpp index c4238166c6a..898c3f7958d 100644 --- a/cpp/src/visitors/visitors_factory.cpp +++ b/cpp/src/visitors/visitors_factory.cpp @@ -18,6 +18,8 @@ // #include +#include + #include namespace cugraph { @@ -49,10 +51,22 @@ dependent_factory_t::value>>:: make_bfs_visitor(erased_pack_t& ep) const { - // return nullptr; // for now... return std::make_unique>(ep); } +template +std::unique_ptr dependent_factory_t< + vertex_t, + edge_t, + weight_t, + st, + mg, + std::enable_if_t::value>>::make_rw_visitor(erased_pack_t& + ep) const +{ + return std::make_unique>(ep); +} + // EIDir's: // template class dependent_factory_t; From 08a6ee772886b86c797fa1b22d12c89fbc261048 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 8 Sep 2021 15:48:33 -0500 Subject: [PATCH 04/48] RW visitor test. --- cpp/include/cugraph/visitors/erased_api.hpp | 10 + cpp/tests/CMakeLists.txt | 9 +- cpp/tests/visitors/rw_test.cu | 207 ++++++++++++++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 cpp/tests/visitors/rw_test.cu diff --git a/cpp/include/cugraph/visitors/erased_api.hpp b/cpp/include/cugraph/visitors/erased_api.hpp index b85ee84bff6..01fad35cef8 100644 --- a/cpp/include/cugraph/visitors/erased_api.hpp +++ b/cpp/include/cugraph/visitors/erased_api.hpp @@ -40,6 +40,16 @@ using namespace cugraph::visitors; */ return_t bfs(graph_envelope_t const& g, erased_pack_t& ep); +/** + * @brief Type-erased Random Walks wrapper. + * + * @param[in] g graph_envelope reference; + * @param[in] ep erased_pack_t pack of erased arguments, that the caller is responsible to set + * correctly; + * @return return set; + */ +return_t random_walks(graph_envelope_t const& g, erased_pack_t& ep); + // TODO: more to follow... } // namespace api diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index cf8cfd94c1c..245295e255e 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -405,7 +405,6 @@ set(SERIALIZATION_TEST_SRCS ConfigureTest(SERIALIZATION_TEST "${SERIALIZATION_TEST_SRCS}") - ################################################################################################### # - BFS Visitor tests ----------------------------------------------------------------------------- @@ -414,6 +413,14 @@ set(BFS_VISITOR_TEST_SRCS ConfigureTest(BFS_VISITOR_TEST "${BFS_VISITOR_TEST_SRCS}") +################################################################################################### +# - Random Walks Visitor tests -------------------------------------------------------------------- + +set(RW_VISITOR_TEST_SRCS + "${CMAKE_CURRENT_SOURCE_DIR}/visitors/rw_test.cu") + +ConfigureTest(RANDOM_WALKS_VISITOR_TEST "${RW_VISITOR_TEST_SRCS}") + ################################################################################################### # - MG tests -------------------------------------------------------------------------------------- diff --git a/cpp/tests/visitors/rw_test.cu b/cpp/tests/visitors/rw_test.cu new file mode 100644 index 00000000000..15bc1300e9e --- /dev/null +++ b/cpp/tests/visitors/rw_test.cu @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021, 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 +#include +#include + +#include +#include +#include +#include + +// visitor artifacts: +// +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace { // anonym. +template +void fill_start(raft::handle_t const& handle, + rmm::device_uvector& d_start, + index_t num_vertices) +{ + index_t num_paths = d_start.size(); + + thrust::transform(handle.get_thrust_policy(), + thrust::make_counting_iterator(0), + thrust::make_counting_iterator(num_paths), + + d_start.begin(), + [num_vertices] __device__(auto indx) { return indx % num_vertices; }); +} +} // namespace + +struct RandomWalks_Usecase { + std::string graph_file_full_path{}; + bool test_weighted{false}; + + RandomWalks_Usecase(std::string const& graph_file_path, bool test_weighted) + : test_weighted(test_weighted) + { + if ((graph_file_path.length() > 0) && (graph_file_path[0] != '/')) { + graph_file_full_path = cugraph::test::get_rapids_dataset_root_dir() + "/" + graph_file_path; + } else { + graph_file_full_path = graph_file_path; + } + }; +}; + +class Tests_RW_Visitor : public ::testing::TestWithParam { + public: + Tests_RW_Visitor() {} + static void SetupTestCase() {} + static void TearDownTestCase() {} + + virtual void SetUp() {} + virtual void TearDown() {} + + template + void run_current_test(RandomWalks_Usecase const& configuration) + { + using namespace cugraph::visitors; + using index_t = edge_t; + using algo_ret_t = std::tuple, + rmm::device_uvector, + rmm::device_uvector>; + using ptr_params_t = std::unique_ptr; + + raft::handle_t handle{}; + + // extract graph data from graph matrix file: + // + auto&& [d_src, d_dst, opt_d_w, num_vertices, is_sym] = + cugraph::test::read_edgelist_from_matrix_market_file( + handle, configuration.graph_file_full_path, configuration.test_weighted); + + cugraph::graph_properties_t graph_props{is_sym, false}; + edge_t num_edges = d_dst.size(); + + std::optional opt_ptr_w; + if (opt_d_w.has_value()) { opt_ptr_w = opt_d_w->data(); } + + // to be filled: + // + cugraph::edgelist_t edgelist{ + d_src.data(), d_dst.data(), opt_ptr_w, num_edges}; + bool sorted{false}; + bool check{false}; + + erased_pack_t ep_graph{&handle, &edgelist, &num_vertices, &graph_props, &sorted, &check}; + + DTypes vertex_tid = reverse_dmap_t::type_id; + DTypes edge_tid = reverse_dmap_t::type_id; + DTypes weight_tid = reverse_dmap_t::type_id; + bool st = false; + bool mg = false; + GTypes graph_tid = GTypes::GRAPH_T; + + graph_envelope_t graph_envelope{vertex_tid, edge_tid, weight_tid, st, mg, graph_tid, ep_graph}; + + auto const* p_graph = + dynamic_cast const*>( + graph_envelope.graph().get()); + + auto graph_view = p_graph->view(); + + index_t num_paths{10}; + index_t max_depth{10}; + rmm::device_uvector d_start(num_paths, handle.get_stream()); + + fill_start(handle, d_start, graph_view.get_number_of_vertices()); + + // visitors machinery: + // + // in a context where dependent types are known, + // type-erasing the graph is not necessary, + // hence the `_wrapper()` is not necessary; + // + + // packing visitor arguments = random walks algorithm arguments + // + vertex_t* p_d_start = d_start.data(); + bool use_padding{false}; + auto sampling = std::make_unique(0); + erased_pack_t ep{&handle, + p_d_start, + &num_paths, + &max_depth, + &use_padding, + &sampling}; // type-erased args for random_walks() + + // several options to run the : + // ( \in {bfs, random_walks, etc.}) + // + // (1.) if a graph object already exists, + // we can use it to make the appropriate + // visitor: + // + // auto v_uniq_ptr = make_visitor( + // *p_graph, + // [](graph_envelope_t::visitor_factory_t const& vfact, erased_pack_t& parg) { + // return vfact.make__visitor(parg); + // }, + // ep); + // p_graph->apply(*v_uniq_ptr); + + // (2.) if a graph object already exists, alternatively we can + // explicitly instantiate the factory and call its make method: + // + // dependent_factory_t visitor_factory{}; + // auto v_uniq_ptr = visitor_factory.make__visitor(ep) + // p_graph->apply(*v_uniq_ptr); + + // (3.) if only the `graph_envelope_t` object exists, + // we can invoke the algorithm via the wrapper: + // + return_t ret = cugraph::api::random_walks(graph_envelope, ep); + + // unpack type-erased result: + // + auto&& ret_tuple = ret.get(); + // check results: + // + bool test_all_paths = cugraph::test::host_check_rw_paths( + handle, graph_view, std::get<0>(ret_tuple), std::get<1>(ret_tuple), std::get<2>(ret_tuple)); + + ASSERT_TRUE(test_all_paths); + } +}; + +// FIXME: add tests for type combinations +TEST_P(Tests_RW_Visitor, CheckInt32Int32) { run_current_test(GetParam()); } + +INSTANTIATE_TEST_CASE_P(visitor_test, + Tests_RW_Visitor, + ::testing::Values(RandomWalks_Usecase("test/datasets/karate.mtx", true), + RandomWalks_Usecase("test/datasets/web-Google.mtx", + true))); + +CUGRAPH_TEST_PROGRAM_MAIN() From 03368273b80351ce3c24839d2f90bcffb33228fd Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Thu, 9 Sep 2021 15:52:51 -0500 Subject: [PATCH 05/48] Changed order of header inclusion to fix problematic warning. --- cpp/tests/visitors/rw_test.cu | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/tests/visitors/rw_test.cu b/cpp/tests/visitors/rw_test.cu index 15bc1300e9e..2917909f399 100644 --- a/cpp/tests/visitors/rw_test.cu +++ b/cpp/tests/visitors/rw_test.cu @@ -14,15 +14,15 @@ * limitations under the License. */ +#include +#include +#include + #include #include #include -#include -#include -#include - #include #include #include From 4e407520571fc59b0b945dfcd02903300d1d256e Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 14 Sep 2021 16:48:45 -0500 Subject: [PATCH 06/48] Proto C-API. --- cpp/CMakeLists.txt | 8 +++ cpp/include/cugraph/cugraph_api.h | 97 +++++++++++++++++++++++++++ cpp/src/visitors/cugraph_api.cpp | 108 ++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 cpp/include/cugraph/cugraph_api.h create mode 100644 cpp/src/visitors/cugraph_api.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index d01c1a7dbe3..bf0f6f6ae64 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -322,6 +322,14 @@ target_link_libraries(cugraph PRIVATE ${OpenMP_CXX_LIB_NAMES}) endif(OpenMP_CXX_FOUND) +##### C-only +##### { +add_library(cugraph_c + src/visitors/cugraph_api.cpp + ) + +target_link_libraries(cugraph_c PRIVATE cugraph) +##### } ################################################################################################### # - generate tests -------------------------------------------------------------------------------- diff --git a/cpp/include/cugraph/cugraph_api.h b/cpp/include/cugraph/cugraph_api.h new file mode 100644 index 00000000000..373f2fea86a --- /dev/null +++ b/cpp/include/cugraph/cugraph_api.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021, 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 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum cugraph_error_ { + CUGRAPH_SUCCESS, + CUGRAPH_ERROR_UNKNOWN, + CUGRAPH_INVALID_HANDLE +} cugraph_error_t; + +typedef int bool_t; + +/* C stub declarations */ + +typedef struct c_raft_handle_ { + int allign_; +} c_raft_handle_t; + +typedef struct c_graph_envelope_ { + int allign_; +} c_graph_envelope_t; + +typedef struct c_erased_device_array_ { + int allign_; +} c_device_array_t; + +typedef struct c_erased_unique_ptr_ { + int allign_; +} c_unique_ptr_t; + +typedef struct c_device_buffer_ { + void* data_; + size_t size_; /* in bytes */ +} c_device_buffer_t; + +/* C algorithm specific stubs: should go into separate corresponding headers */ + +typedef struct c_rw_ret_tuple_ { + c_device_buffer_t vertex_paths_; + c_device_buffer_t weight_paths_; + c_device_buffer_t sizes_; +} c_rw_ret_tuple_t; + +typedef struct c_rw_ret_ { + void* p_erased_ret; +} c_rw_ret_t; + +/* TODO: + * (1.) graph_envelope "cnstr" / "destr": + * + * c_graph_envelope_t* make_graph_envelope(...); + * free_graph_envelope(c_graph_envelope_t* ptr); + * + * (2.) type reconstruction extractors; + * e.g., for `return_t`: different extractors + * interpret return in a different (typed) way; + * + * Example: + * c_device_buffer_t* extract_rw_ret_vertex_path(c_type vertex_t_id, c_rw_ret_t* rw_result); + * c_device_buffer_t* extract_rw_ret_weight_path(c_type vertex_t_id, c_rw_ret_t* rw_result); + */ + +/* C algorithm specific wrapper declarations: : should go into separate corresponding headers */ + +cugraph_error_t c_random_walks(const c_raft_handle_t* ptr_handle, + c_graph_envelope_t* ptr_graph_envelope, + c_device_array_t* ptr_d_start, + size_t num_paths, + size_t max_depth, + bool_t flag_use_padding, + c_unique_ptr_t* ptr_sampling_strategy, + c_rw_ret_t* ret); + +#ifdef __cplusplus +} +#endif diff --git a/cpp/src/visitors/cugraph_api.cpp b/cpp/src/visitors/cugraph_api.cpp new file mode 100644 index 00000000000..eab267cae45 --- /dev/null +++ b/cpp/src/visitors/cugraph_api.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021, 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 + +#include + +#include + +extern "C" cugraph_error_t c_random_walks(const c_raft_handle_t* ptr_handle, + c_graph_envelope_t* ptr_graph_envelope, + c_device_array_t* ptr_d_start, + size_t num_paths, + size_t max_depth, + bool_t flag_use_padding, + c_unique_ptr_t* ptr_sampling_strategy, + c_rw_ret_t* ret) +{ + using namespace cugraph::visitors; + + using ptr_sampling_t = std::unique_ptr; + + cugraph_error_t status = CUGRAPH_SUCCESS; + + try { + // unpack C stub arguments: + // + graph_envelope_t* p_g_env = reinterpret_cast(ptr_graph_envelope); + + raft::handle_t const* p_raft_handle = reinterpret_cast(ptr_handle); + void* p_d_start = reinterpret_cast(ptr_d_start); + + bool use_padding = static_cast(flag_use_padding); + + ptr_sampling_t* p_uniq_sampling = reinterpret_cast(ptr_sampling_strategy); + + // pack type-erased algorithm arguments: + // + erased_pack_t ep{const_cast(p_raft_handle), + p_d_start, + &num_paths, + &max_depth, + &use_padding, + p_uniq_sampling}; + + // call algorithm: + // + return_t ret_erased = cugraph::api::random_walks(*p_g_env, ep); + +#ifdef _USE_CALLEE_TYPE_RECONSTR + // callee type-reconstruction: this function has the knoweldge + // and means to reconstruct the result: + // + using algo_ret_t = std::tuple, // requires dispatching + rmm::device_uvector, // requires dispatching + rmm::device_uvector>; // requires dispatching + + // unpack type-erased result: + // requires type reconstruction for vertex_t, edge_t, weight_t; + // + auto&& ret_tuple = ret_erased.get(); + + //(CAVEAT: must allocate, because returns are local to this function!) + // + { + rmm::device_buffer* p_d_vs = new rmm::device_buffer(std::get<0>(ret_tuple).release()); + ret->vertex_paths_ = {p_d_vs, p_d_vs->size()}; + } + { + rmm::device_buffer* p_d_ws = new rmm::device_buffer(std::get<1>(ret_tuple).release()); + ret->weight_paths_ = {p_d_ws, p_d_ws->size()}; + } + { + rmm::device_buffer* p_d_sz = new rmm::device_buffer(std::get<2>(ret_tuple).release()); + ret->sizes_ = {p_d_sz, p_d_sz->size()}; + } +#else + // caller deffered type-reconstruction: caller has the knoweldge + // and means to reconstruct the result: + // (CAVEAT: must allocate, because `ret_erased` is local to this function!) + // + ret->p_erased_ret = new return_t(std::move(ret_erased)); +#endif + + } catch (...) { + status = CUGRAPH_ERROR_UNKNOWN; + } + + return status; +} From 04110f622fa43ee3a652ef39a9795278537a3fa1 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 15 Sep 2021 11:00:44 -0500 Subject: [PATCH 07/48] Added a RW test utility function allowing raw pointers, for type-erasure / visitor testing. --- cpp/tests/sampling/random_walks_utils.cuh | 53 +++++++++++++++-------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/cpp/tests/sampling/random_walks_utils.cuh b/cpp/tests/sampling/random_walks_utils.cuh index df3bd08ce9b..f4e1fde10d8 100644 --- a/cpp/tests/sampling/random_walks_utils.cuh +++ b/cpp/tests/sampling/random_walks_utils.cuh @@ -88,10 +88,13 @@ template const& graph_view, - vector_test_t const& d_coalesced_v, - vector_test_t const& d_coalesced_w, - vector_test_t const& d_sizes, - index_t num_paths = 0) // only relevant for the padded case (in which case it must be non-zero) + vertex_t const* ptr_d_coalesced_v, + size_t num_path_vertices, + weight_t const* ptr_d_coalesced_w, + size_t num_path_edges, + index_t const* ptr_d_sizes, + size_t path_sizes, + index_t num_paths) { edge_t num_edges = graph_view.get_number_of_edges(); vertex_t num_vertices = graph_view.get_number_of_vertices(); @@ -110,22 +113,15 @@ bool host_check_rw_paths( if (values) { raft::update_host(v_vals.data(), *values, v_vals.size(), handle.get_stream()); } - std::vector v_coalesced(d_coalesced_v.size()); - std::vector w_coalesced(d_coalesced_w.size()); - std::vector v_sizes(d_sizes.size()); + std::vector v_coalesced(num_path_vertices); + std::vector w_coalesced(num_path_edges); + std::vector v_sizes(path_sizes); - raft::update_host(v_coalesced.data(), - cugraph::detail::raw_const_ptr(d_coalesced_v), - d_coalesced_v.size(), - handle.get_stream()); - raft::update_host(w_coalesced.data(), - cugraph::detail::raw_const_ptr(d_coalesced_w), - d_coalesced_w.size(), - handle.get_stream()); + raft::update_host(v_coalesced.data(), ptr_d_coalesced_v, num_path_vertices, handle.get_stream()); + raft::update_host(w_coalesced.data(), ptr_d_coalesced_w, num_path_edges, handle.get_stream()); if (v_sizes.size() > 0) { // coalesced case - raft::update_host( - v_sizes.data(), cugraph::detail::raw_const_ptr(d_sizes), d_sizes.size(), handle.get_stream()); + raft::update_host(v_sizes.data(), ptr_d_sizes, path_sizes, handle.get_stream()); } else { // padded case if (num_paths == 0) { std::cerr << "ERROR: padded case requires `num_paths` info.\n"; @@ -177,6 +173,29 @@ bool host_check_rw_paths( return true; } +// convenience trampoline function for when `device_uvector`'s are readily available; +// (e.g., returned by an algorithm); +// +template +bool host_check_rw_paths( + raft::handle_t const& handle, + cugraph::graph_view_t const& graph_view, + vector_test_t const& d_coalesced_v, + vector_test_t const& d_coalesced_w, + vector_test_t const& d_sizes, + index_t num_paths = 0) // only relevant for the padded case (in which case it must be non-zero) +{ + return host_check_rw_paths(handle, + graph_view, + d_coalesced_v.data(), + d_coalesced_v.size(), + d_coalesced_w.data(), + d_coalesced_w.size(), + d_sizes.data(), + d_sizes.size(), + num_paths); +} + template bool host_check_query_rw(raft::handle_t const& handle, vector_test_t const& d_v_sizes, From c74ac7c22cc7c8c98c2cb5553acf6cda13fdd5b4 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 15 Sep 2021 11:59:51 -0500 Subject: [PATCH 08/48] Type-erased return type to help the C-API avoid cascaded dispatch on return type. --- cpp/src/visitors/rw_visitor.cpp | 6 +++++- cpp/tests/visitors/rw_test.cu | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/cpp/src/visitors/rw_visitor.cpp b/cpp/src/visitors/rw_visitor.cpp index fe9c72ded3f..bc1d979d792 100644 --- a/cpp/src/visitors/rw_visitor.cpp +++ b/cpp/src/visitors/rw_visitor.cpp @@ -71,7 +71,11 @@ void rw_visitor(tpl_result).release(), + std::get<1>(tpl_result).release(), + std::get<2>(tpl_result).release()); + + result_ = return_t{std::move(tpl_erased_result)}; } else { CUGRAPH_FAIL( "Unsupported RandomWalks algorithm (store_transposed == true or multi_gpu == true)."); diff --git a/cpp/tests/visitors/rw_test.cu b/cpp/tests/visitors/rw_test.cu index 2917909f399..c924f011665 100644 --- a/cpp/tests/visitors/rw_test.cu +++ b/cpp/tests/visitors/rw_test.cu @@ -87,10 +87,16 @@ class Tests_RW_Visitor : public ::testing::TestWithParam { void run_current_test(RandomWalks_Usecase const& configuration) { using namespace cugraph::visitors; - using index_t = edge_t; - using algo_ret_t = std::tuple, + using index_t = edge_t; + +#ifdef _USE_UNERASED_RW_RET_ + using algo_ret_t = std::tuple, rmm::device_uvector, rmm::device_uvector>; +#else + using algo_ret_t = std::tuple; +#endif + using ptr_params_t = std::unique_ptr; raft::handle_t handle{}; @@ -186,10 +192,33 @@ class Tests_RW_Visitor : public ::testing::TestWithParam { // unpack type-erased result: // auto&& ret_tuple = ret.get(); + // check results: // +#ifdef _USE_UNERASED_RW_RET_ bool test_all_paths = cugraph::test::host_check_rw_paths( handle, graph_view, std::get<0>(ret_tuple), std::get<1>(ret_tuple), std::get<2>(ret_tuple)); +#else + rmm::device_buffer const& d_buf_vertices = std::get<0>(ret_tuple); + size_t num_path_vertices = d_buf_vertices.size() / sizeof(vertex_t); + + rmm::device_buffer const& d_buf_weights = std::get<1>(ret_tuple); + size_t num_path_edges = d_buf_weights.size() / sizeof(weight_t); + + rmm::device_buffer const& d_buf_sizes = std::get<2>(ret_tuple); + size_t path_sizes = d_buf_sizes.size() / sizeof(index_t); + + bool test_all_paths = + cugraph::test::host_check_rw_paths(handle, + graph_view, + static_cast(d_buf_vertices.data()), + num_path_vertices, + static_cast(d_buf_weights.data()), + num_path_edges, + static_cast(d_buf_sizes.data()), + path_sizes, + 0); +#endif ASSERT_TRUE(test_all_paths); } From 43e57327a0adadf138a05964b125382f804f6756 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Fri, 17 Sep 2021 14:02:10 -0500 Subject: [PATCH 09/48] C-API: file / build structure and first files. --- c/CMakeLists.txt | 58 +++++++++++++++++++ .../include/cugraph_c}/cugraph_api.h | 0 {cpp/src/visitors => c/src}/cugraph_api.cpp | 2 +- cpp/CMakeLists.txt | 11 +--- 4 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 c/CMakeLists.txt rename {cpp/include/cugraph => c/include/cugraph_c}/cugraph_api.h (100%) rename {cpp/src/visitors => c/src}/cugraph_api.cpp (99%) diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt new file mode 100644 index 00000000000..887de21d8bb --- /dev/null +++ b/c/CMakeLists.txt @@ -0,0 +1,58 @@ +#============================================================================= +# Copyright (c) 2018-2021, 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. +#============================================================================= + + +################################################################################################### +# - library targets ------------------------------------------------------------------------------- + +add_library(cugraph_c SHARED + src/cugraph_api.cpp + ) +add_library(cugraph::cugraph_c ALIAS cugraph_c) + +# Currently presuming we aren't calling any CUDA kernels in cugraph_c + +set_target_properties(cugraph_c + PROPERTIES BUILD_RPATH "\$ORIGIN" + INSTALL_RPATH "\$ORIGIN" + # set target compile options + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + INTERFACE_POSITION_INDEPENDENT_CODE ON +) + +target_compile_options(cugraph_c + PRIVATE "$<$:${CUGRAPH_CXX_FLAGS}>" +) + +################################################################################################### +# - include paths --------------------------------------------------------------------------------- +target_include_directories(cugraph_c + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_SOURCE_DIR}../cpp/src" + PUBLIC + "$" + "$" +) + +################################################################################################### +# - link libraries -------------------------------------------------------------------------------- +target_link_libraries(cugraph_c + PUBLIC + cugraph::cugraph +) + diff --git a/cpp/include/cugraph/cugraph_api.h b/c/include/cugraph_c/cugraph_api.h similarity index 100% rename from cpp/include/cugraph/cugraph_api.h rename to c/include/cugraph_c/cugraph_api.h diff --git a/cpp/src/visitors/cugraph_api.cpp b/c/src/cugraph_api.cpp similarity index 99% rename from cpp/src/visitors/cugraph_api.cpp rename to c/src/cugraph_api.cpp index eab267cae45..3b33b6f8d5c 100644 --- a/cpp/src/visitors/cugraph_api.cpp +++ b/c/src/cugraph_api.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index bc68e71fe68..c649db5afaf 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -335,14 +335,9 @@ target_link_libraries(cugraph PRIVATE ${OpenMP_CXX_LIB_NAMES}) endif() -##### C-only -##### { -add_library(cugraph_c - src/visitors/cugraph_api.cpp - ) - -target_link_libraries(cugraph_c PRIVATE cugraph) -##### } +################################################################################################### +# - add C-API library ------------------------------------------------------------------------------- +add_subdirectory(../c c) ################################################################################################### # - generate tests -------------------------------------------------------------------------------- From 2d4530949993fcf3ed2038a9f6b53c3c1c769ab6 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Sun, 19 Sep 2021 22:26:01 -0500 Subject: [PATCH 10/48] Updates to consolidate the libcugraph C API with the cpp source tree. --- build.sh | 2 + c/CMakeLists.txt | 58 ---------- cpp/CMakeLists.txt | 118 ++++++++++++++------- {c => cpp}/include/cugraph_c/cugraph_api.h | 0 {c/src => cpp/src/c_api}/cugraph_api.cpp | 0 5 files changed, 84 insertions(+), 94 deletions(-) delete mode 100644 c/CMakeLists.txt rename {c => cpp}/include/cugraph_c/cugraph_api.h (100%) rename {c/src => cpp/src/c_api}/cugraph_api.cpp (100%) diff --git a/build.sh b/build.sh index 102c7efafd4..d1d88b917b6 100755 --- a/build.sh +++ b/build.sh @@ -119,7 +119,9 @@ if hasArg uninstall; then # uninstall libcugraph if [[ "$INSTALL_PREFIX" != "" ]]; then rm -rf ${INSTALL_PREFIX}/include/cugraph + rm -rf ${INSTALL_PREFIX}/include/cugraph_c rm -f ${INSTALL_PREFIX}/lib/libcugraph.so + rm -f ${INSTALL_PREFIX}/lib/libcugraph_c.so fi # This may be redundant given the above, but can also be used in case # there are other installed files outside of the locations above. diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt deleted file mode 100644 index 887de21d8bb..00000000000 --- a/c/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -#============================================================================= -# Copyright (c) 2018-2021, 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. -#============================================================================= - - -################################################################################################### -# - library targets ------------------------------------------------------------------------------- - -add_library(cugraph_c SHARED - src/cugraph_api.cpp - ) -add_library(cugraph::cugraph_c ALIAS cugraph_c) - -# Currently presuming we aren't calling any CUDA kernels in cugraph_c - -set_target_properties(cugraph_c - PROPERTIES BUILD_RPATH "\$ORIGIN" - INSTALL_RPATH "\$ORIGIN" - # set target compile options - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - INTERFACE_POSITION_INDEPENDENT_CODE ON -) - -target_compile_options(cugraph_c - PRIVATE "$<$:${CUGRAPH_CXX_FLAGS}>" -) - -################################################################################################### -# - include paths --------------------------------------------------------------------------------- -target_include_directories(cugraph_c - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/src" - "${CMAKE_CURRENT_SOURCE_DIR}../cpp/src" - PUBLIC - "$" - "$" -) - -################################################################################################### -# - link libraries -------------------------------------------------------------------------------- -target_link_libraries(cugraph_c - PUBLIC - cugraph::cugraph -) - diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index c649db5afaf..f825e237157 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -49,18 +49,18 @@ list(APPEND usable_arch_values ${latest_arch}) set(CMAKE_CUDA_ARCHITECTURES ${usable_arch_values}) - # Write the version header rapids_cmake_write_version_file(include/cugraph/version_config.hpp) +rapids_cmake_write_version_file(include/cugraph_c/version_config.hpp) -################################################################################################### -# - build type ------------------------------------------------------------------------------------ +################################################################################ +# - build type ----------------------------------------------------------------- # Set a default build type if none was specified rapids_cmake_build_type(Release) -############################################################################## -# - User Options ------------------------------------------------------------ +################################################################################ +# - User Options -------------------------------------------------------------- option(BUILD_CUGRAPH_MG_TESTS "Build cuGraph multigpu algorithm tests" OFF) set(BLAS_LIBRARIES "" CACHE STRING "Location of BLAS library for FAISS build.") @@ -68,8 +68,8 @@ option(BUILD_STATIC_FAISS "Build the FAISS library for nearest neighbors search option(CMAKE_CUDA_LINEINFO "Enable the -lineinfo option for nvcc (useful for cuda-memcheck / profiler" OFF) option(BUILD_TESTS "Configure CMake to build tests" ON) -################################################################################################### -# - compiler options ------------------------------------------------------------------------------ +################################################################################ +# - compiler options ----------------------------------------------------------- rapids_find_package(CUDAToolkit REQUIRED BUILD_EXPORT_SET cugraph-exports @@ -103,8 +103,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug) list(APPEND CUGRAPH_CUDA_FLAGS -G -Xcompiler=-rdynamic) endif() -################################################################################################### -# - find openmp ----------------------------------------------------------------------------------- +################################################################################ +# - find openmp ---------------------------------------------------------------- find_package(OpenMP) if(OpenMP_FOUND) @@ -113,8 +113,8 @@ if(OpenMP_FOUND) endif() -################################################################################################### -# - find blas ------------------------------------------------------------------------------------- +################################################################################ +# - find blas ------------------------------------------------------------------ if(NOT DEFINED BLAS_LIBRARIES) find_package( BLAS REQUIRED ) @@ -122,13 +122,11 @@ else() message(STATUS "Manually setting BLAS to ${BLAS_LIBRARIES}") endif() -################################################################################################### -# - find CPM based dependencies ------------------------------------------------------------------ - +################################################################################ +# - find CPM based dependencies ----------------------------------------------- rapids_cpm_init() - include(cmake/thirdparty/get_thrust.cmake) include(cmake/thirdparty/get_faiss.cmake) include(cmake/thirdparty/get_nccl.cmake) @@ -145,9 +143,8 @@ if(BUILD_TESTS) include(cmake/thirdparty/get_gtest.cmake) endif() - -################################################################################################### -# - library targets ------------------------------------------------------------------------------- +################################################################################ +# - libcugraph library target -------------------------------------------------- add_library(cugraph SHARED src/detail/utility_wrappers.cu @@ -253,8 +250,9 @@ target_link_options(cugraph PRIVATE "${CUGRAPH_BINARY_DIR}/fatbin.ld") add_library(cugraph::cugraph ALIAS cugraph) -################################################################################################### -# - include paths --------------------------------------------------------------------------------- +################################################################################ +# - include paths -------------------------------------------------------------- + target_include_directories(cugraph PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty" @@ -265,8 +263,8 @@ target_include_directories(cugraph "$" ) -################################################################################################### -# - link libraries -------------------------------------------------------------------------------- +################################################################################ +# - link libraries ------------------------------------------------------------- target_link_libraries(cugraph PUBLIC rmm::rmm @@ -286,7 +284,7 @@ target_link_libraries(cugraph if(OpenMP_CXX_FOUND) target_link_libraries(cugraph PRIVATE -################################################################################################### +################################################################################ ### Use ${OpenMP_CXX_LIB_NAMES} instead of OpenMP::OpenMP_CXX to avoid the following warnings. ### ### Cannot generate a safe runtime search path for target TARGET_NAME @@ -335,20 +333,56 @@ target_link_libraries(cugraph PRIVATE ${OpenMP_CXX_LIB_NAMES}) endif() -################################################################################################### -# - add C-API library ------------------------------------------------------------------------------- -add_subdirectory(../c c) +################################################################################ +# - C-API library -------------------------------------------------------------- + +add_library(cugraph_c SHARED + src/c_api/cugraph_api.cpp + ) +add_library(cugraph::cugraph_c ALIAS cugraph_c) + +# Currently presuming we aren't calling any CUDA kernels in cugraph_c + +set_target_properties(cugraph_c + PROPERTIES BUILD_RPATH "\$ORIGIN" + INSTALL_RPATH "\$ORIGIN" + # set target compile options + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + INTERFACE_POSITION_INDEPENDENT_CODE ON +) + +target_compile_options(cugraph_c + PRIVATE "$<$:${CUGRAPH_CXX_FLAGS}>" +) + +################################################################################ +# - C-API include paths -------------------------------------------------------- +target_include_directories(cugraph_c + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src" + PUBLIC + "$" + "$" +) + +################################################################################ +# - C-API link libraries ------------------------------------------------------- +target_link_libraries(cugraph_c + PUBLIC + cugraph::cugraph +) -################################################################################################### -# - generate tests -------------------------------------------------------------------------------- +################################################################################ +# - generate tests ------------------------------------------------------------- if(BUILD_TESTS) include(CTest) add_subdirectory(tests) endif() -################################################################################################### -# - install targets ------------------------------------------------------------------------------- +################################################################################ +# - install targets ------------------------------------------------------------ rapids_cmake_install_lib_dir( lib_dir ) include(CPack) @@ -362,8 +396,20 @@ install(DIRECTORY include/cugraph/ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/cugraph/version_config.hpp DESTINATION include/cugraph) -################################################################################################ -# - install export ------------------------------------------------------------------------------- +install(TARGETS cugraph_c + DESTINATION ${lib_dir}) + +install(DIRECTORY include/cugraph_c/ + DESTINATION include/cugraph_c) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/cugraph_c/version_config.hpp + DESTINATION include/cugraph_c) + +################################################################################ +# - install export ------------------------------------------------------------- + +# FIXME: does the C-API need to be an exported target too? + set(doc_string [=[ Provide targets for cuGraph. @@ -386,8 +432,8 @@ thrust_create_target(cugraph::Thrust FROM_OPTIONS) FINAL_CODE_BLOCK code_string ) -################################################################################################ -# - build export ------------------------------------------------------------------------------- +################################################################################ +# - build export --------------------------------------------------------------- rapids_export(BUILD cugraph EXPORT_SET cugraph-exports GLOBAL_TARGETS cugraph @@ -396,8 +442,8 @@ rapids_export(BUILD cugraph FINAL_CODE_BLOCK code_string ) -################################################################################################### -# - make documentation ---------------------------------------------------------------------------- +################################################################################ +# - make documentation --------------------------------------------------------- # requires doxygen and graphviz to be installed # from build directory, run make docs_cugraph diff --git a/c/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h similarity index 100% rename from c/include/cugraph_c/cugraph_api.h rename to cpp/include/cugraph_c/cugraph_api.h diff --git a/c/src/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp similarity index 100% rename from c/src/cugraph_api.cpp rename to cpp/src/c_api/cugraph_api.cpp From 1833356e3e40a04409e627c94f8df0045213f132 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Mon, 20 Sep 2021 13:01:15 -0500 Subject: [PATCH 11/48] Changed GLOBAL_TARGETS to include cugraph_c. --- cpp/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index f825e237157..4c65f893f65 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -408,8 +408,6 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/cugraph_c/version_config.hpp ################################################################################ # - install export ------------------------------------------------------------- -# FIXME: does the C-API need to be an exported target too? - set(doc_string [=[ Provide targets for cuGraph. @@ -426,7 +424,7 @@ thrust_create_target(cugraph::Thrust FROM_OPTIONS) rapids_export(INSTALL cugraph EXPORT_SET cugraph-exports - GLOBAL_TARGETS cugraph + GLOBAL_TARGETS cugraph cugraph_c NAMESPACE cugraph:: DOCUMENTATION doc_string FINAL_CODE_BLOCK code_string @@ -436,7 +434,7 @@ thrust_create_target(cugraph::Thrust FROM_OPTIONS) # - build export --------------------------------------------------------------- rapids_export(BUILD cugraph EXPORT_SET cugraph-exports - GLOBAL_TARGETS cugraph + GLOBAL_TARGETS cugraph cugraph_c NAMESPACE cugraph:: DOCUMENTATION doc_string FINAL_CODE_BLOCK code_string From 569792a18a05f2472edd402c230aeb9dfc58cc1f Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 21 Sep 2021 15:15:57 -0500 Subject: [PATCH 12/48] Changed C-API prefix. --- cpp/include/cugraph_c/cugraph_api.h | 59 +++++++++++++++-------------- cpp/src/c_api/cugraph_api.cpp | 45 ++++------------------ 2 files changed, 38 insertions(+), 66 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 373f2fea86a..c9f5ce59894 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -33,64 +33,65 @@ typedef int bool_t; /* C stub declarations */ -typedef struct c_raft_handle_ { +typedef struct cugraph_raft_handle_ { int allign_; -} c_raft_handle_t; +} cugraph_raft_handle_t; -typedef struct c_graph_envelope_ { +typedef struct cugraph_graph_envelope_ { int allign_; -} c_graph_envelope_t; +} cugraph_graph_envelope_t; -typedef struct c_erased_device_array_ { +typedef struct cugraph_erased_device_array_ { int allign_; -} c_device_array_t; +} cugraph_device_array_t; -typedef struct c_erased_unique_ptr_ { +typedef struct cugraph_erased_unique_ptr_ { int allign_; -} c_unique_ptr_t; +} cugraph_unique_ptr_t; -typedef struct c_device_buffer_ { +typedef struct cugraph_device_buffer_ { void* data_; size_t size_; /* in bytes */ -} c_device_buffer_t; +} cugraph_device_buffer_t; /* C algorithm specific stubs: should go into separate corresponding headers */ -typedef struct c_rw_ret_tuple_ { - c_device_buffer_t vertex_paths_; - c_device_buffer_t weight_paths_; - c_device_buffer_t sizes_; -} c_rw_ret_tuple_t; +typedef struct cugraph_rw_ret_tuple_ { + cugraph_device_buffer_t vertex_paths_; + cugraph_device_buffer_t weight_paths_; + cugraph_device_buffer_t sizes_; +} cugraph_rw_ret_tuple_t; -typedef struct c_rw_ret_ { +typedef struct cugraph_rw_ret_ { void* p_erased_ret; -} c_rw_ret_t; +} cugraph_rw_ret_t; /* TODO: * (1.) graph_envelope "cnstr" / "destr": * - * c_graph_envelope_t* make_graph_envelope(...); - * free_graph_envelope(c_graph_envelope_t* ptr); + * cugraph_graph_envelope_t* make_graph_envelope(...); + * free_graph_envelope(cugraph_graph_envelope_t* ptr); * * (2.) type reconstruction extractors; * e.g., for `return_t`: different extractors * interpret return in a different (typed) way; * * Example: - * c_device_buffer_t* extract_rw_ret_vertex_path(c_type vertex_t_id, c_rw_ret_t* rw_result); - * c_device_buffer_t* extract_rw_ret_weight_path(c_type vertex_t_id, c_rw_ret_t* rw_result); + * cugraph_device_buffer_t* extract_rw_ret_vertex_path(cugraph_type vertex_t_id, + * cugraph_rw_ret_t* rw_result); cugraph_device_buffer_t* extract_rw_ret_weight_path(cugraph_type + * vertex_t_id, cugraph_rw_ret_t* rw_result); */ /* C algorithm specific wrapper declarations: : should go into separate corresponding headers */ -cugraph_error_t c_random_walks(const c_raft_handle_t* ptr_handle, - c_graph_envelope_t* ptr_graph_envelope, - c_device_array_t* ptr_d_start, - size_t num_paths, - size_t max_depth, - bool_t flag_use_padding, - c_unique_ptr_t* ptr_sampling_strategy, - c_rw_ret_t* ret); +cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, + cugraph_graph_envelope_t* ptr_graph_envelope, + cugraph_device_array_t* ptr_d_start, + size_t num_paths, + size_t max_depth, + bool_t flag_use_padding, + cugraph_unique_ptr_t* ptr_sampling_strategy, + cugraph_rw_ret_t* ret); #ifdef __cplusplus } diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 3b33b6f8d5c..e2cb8a04f92 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -25,14 +25,14 @@ #include -extern "C" cugraph_error_t c_random_walks(const c_raft_handle_t* ptr_handle, - c_graph_envelope_t* ptr_graph_envelope, - c_device_array_t* ptr_d_start, - size_t num_paths, - size_t max_depth, - bool_t flag_use_padding, - c_unique_ptr_t* ptr_sampling_strategy, - c_rw_ret_t* ret) +extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, + cugraph_graph_envelope_t* ptr_graph_envelope, + cugraph_device_array_t* ptr_d_start, + size_t num_paths, + size_t max_depth, + bool_t flag_use_padding, + cugraph_unique_ptr_t* ptr_sampling_strategy, + cugraph_rw_ret_t* ret) { using namespace cugraph::visitors; @@ -65,40 +65,11 @@ extern "C" cugraph_error_t c_random_walks(const c_raft_handle_t* ptr_handle, // return_t ret_erased = cugraph::api::random_walks(*p_g_env, ep); -#ifdef _USE_CALLEE_TYPE_RECONSTR - // callee type-reconstruction: this function has the knoweldge - // and means to reconstruct the result: - // - using algo_ret_t = std::tuple, // requires dispatching - rmm::device_uvector, // requires dispatching - rmm::device_uvector>; // requires dispatching - - // unpack type-erased result: - // requires type reconstruction for vertex_t, edge_t, weight_t; - // - auto&& ret_tuple = ret_erased.get(); - - //(CAVEAT: must allocate, because returns are local to this function!) - // - { - rmm::device_buffer* p_d_vs = new rmm::device_buffer(std::get<0>(ret_tuple).release()); - ret->vertex_paths_ = {p_d_vs, p_d_vs->size()}; - } - { - rmm::device_buffer* p_d_ws = new rmm::device_buffer(std::get<1>(ret_tuple).release()); - ret->weight_paths_ = {p_d_ws, p_d_ws->size()}; - } - { - rmm::device_buffer* p_d_sz = new rmm::device_buffer(std::get<2>(ret_tuple).release()); - ret->sizes_ = {p_d_sz, p_d_sz->size()}; - } -#else // caller deffered type-reconstruction: caller has the knoweldge // and means to reconstruct the result: // (CAVEAT: must allocate, because `ret_erased` is local to this function!) // ret->p_erased_ret = new return_t(std::move(ret_erased)); -#endif } catch (...) { status = CUGRAPH_ERROR_UNKNOWN; From 903e93ec29b6787fa6a3caf84b2213288d0581a6 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 21 Sep 2021 20:19:13 -0500 Subject: [PATCH 13/48] Prelim. graph reader visitor. --- .../cugraph/visitors/graph_reader_visitor.hpp | 82 ++++++++++ cpp/src/visitors/graph_reader_visitor.cpp | 150 ++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 cpp/include/cugraph/visitors/graph_reader_visitor.hpp create mode 100644 cpp/src/visitors/graph_reader_visitor.cpp diff --git a/cpp/include/cugraph/visitors/graph_reader_visitor.hpp b/cpp/include/cugraph/visitors/graph_reader_visitor.hpp new file mode 100644 index 00000000000..6fd332b7c42 --- /dev/null +++ b/cpp/include/cugraph/visitors/graph_reader_visitor.hpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021, 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 "erased_pack.hpp" +#include "graph_envelope.hpp" +#include "ret_terased.hpp" + +namespace cugraph { +namespace visitors { +// primary empty template: +// +template +struct graph_reader_visitor_t; + +// dummy out non-candidate instantiation paths: +// +template +struct graph_reader_visitor_t::value)>> + : visitor_t { + void visit_graph(graph_envelope_t::base_graph_t const&) override + { + // purposely empty + } + return_t const& get_result(void) const override + { + static return_t r{}; + return r; + } + + return_t&& get_result(void) override + { + static return_t r{}; + return std::move(r); + } +}; + +template +struct graph_reader_visitor_t::value>> + : visitor_t { + graph_reader_visitor_t(erased_pack_t& ep) : ep_(ep) {} + + void visit_graph(graph_envelope_t::base_graph_t const&) override; + + return_t const& get_result(void) const override { return result_; } + return_t&& get_result(void) override { return std::move(result_); } + + private: + erased_pack_t& ep_; + return_t result_; +}; + +} // namespace visitors +} // namespace cugraph diff --git a/cpp/src/visitors/graph_reader_visitor.cpp b/cpp/src/visitors/graph_reader_visitor.cpp new file mode 100644 index 00000000000..895964a2c91 --- /dev/null +++ b/cpp/src/visitors/graph_reader_visitor.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021, 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 + +namespace cugraph { +namespace visitors { +// +// wrapper code: +// +template +void graph_reader_visitor_t::value>>:: + visit_graph(graph_envelope_t::base_graph_t const& graph) +{ + using index_t = edge_t; + + // Note: this must be called only on: + // graph_view_t + // + if constexpr (st == false && mg == false) { + // unless algorithms only call virtual graph methods + // under the hood, the algos require this conversion: + // + graph_t const* p_g = + static_cast const*>(&graph); + + auto gview = p_g->view(); + + auto const& v_args = ep_.get_args(); + + // unpack bfs() args: + // + // assert(v_args.size() == ?); // raft::handle_t, char* path, bool is_weighted..., + + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); + + char const* p_path = static_cast(v_args[1]); + + bool is_weighted = *static_cast(v_args[2]); + + // TODO: + // + + // read graph: + // + + // create graph_envelope_t + + /// result_ = return_t{std::move(graph_envelope)}; + } else { + CUGRAPH_FAIL("Unsupported graph reader (store_transposed == true or multi_gpu == true)."); + } +} + +// EIDir's: +// +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +//------ + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +//------ + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +template class graph_reader_visitor_t; +template class graph_reader_visitor_t; + +} // namespace visitors + +namespace api { +using namespace cugraph::visitors; +// wrapper: +// +return_t graph_read_mm_file( + DTypes vertex_tid, DTypes edge_tid, DTypes weight_tid, bool st, bool mg, erased_pack_t& ep_reader) +{ + auto const& v_args = ep_reader.get_args(); + + // unpack args: + // + assert(v_args.size() > 0); // raft::handle_t, ... + + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); + + erased_pack_t ep_graph{const_cast(&handle)}; + GTypes graph_tid = GTypes::GRAPH_T; + + graph_envelope_t g{vertex_tid, edge_tid, weight_tid, st, mg, graph_tid, ep_graph}; + + auto p_visitor = g.factory()->make_graph_reader_visitor(ep_reader); + + g.apply(*p_visitor); + + return p_visitor->get_result(); +} + +} // namespace api + +} // namespace cugraph From fd85c380c0442e9378b157b9cc9e090d48629446 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 22 Sep 2021 12:01:39 -0500 Subject: [PATCH 14/48] Graph factory visitor. --- cpp/CMakeLists.txt | 1 + .../cugraph/visitors/graph_envelope.hpp | 9 ++ ...der_visitor.hpp => graph_make_visitor.hpp} | 28 ++-- cpp/src/visitors/graph_make_visitor.cpp | 145 +++++++++++++++++ cpp/src/visitors/graph_reader_visitor.cpp | 150 ------------------ cpp/src/visitors/visitors_factory.cpp | 14 ++ 6 files changed, 183 insertions(+), 164 deletions(-) rename cpp/include/cugraph/visitors/{graph_reader_visitor.hpp => graph_make_visitor.hpp} (73%) create mode 100644 cpp/src/visitors/graph_make_visitor.cpp delete mode 100644 cpp/src/visitors/graph_reader_visitor.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 4c65f893f65..a18336adb0e 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -216,6 +216,7 @@ add_library(cugraph SHARED src/visitors/visitors_factory.cpp src/visitors/bfs_visitor.cpp src/visitors/rw_visitor.cpp + src/visitors/graph_make_visitor.cpp ) set_target_properties(cugraph diff --git a/cpp/include/cugraph/visitors/graph_envelope.hpp b/cpp/include/cugraph/visitors/graph_envelope.hpp index 99475111d82..39f647ff66c 100755 --- a/cpp/include/cugraph/visitors/graph_envelope.hpp +++ b/cpp/include/cugraph/visitors/graph_envelope.hpp @@ -76,6 +76,8 @@ struct graph_envelope_t { virtual std::unique_ptr make_bfs_visitor(erased_pack_t&) const = 0; virtual std::unique_ptr make_rw_visitor(erased_pack_t&) const = 0; + + virtual std::unique_ptr make_graph_maker_visitor(erased_pack_t&) const = 0; }; using pair_uniques_t = @@ -168,6 +170,11 @@ struct dependent_factory_t make_bfs_visitor(erased_pack_t&) const override { return nullptr; } std::unique_ptr make_rw_visitor(erased_pack_t&) const override { return nullptr; } + + std::unique_ptr make_graph_maker_visitor(erased_pack_t&) const override + { + return nullptr; + } }; template @@ -187,6 +194,8 @@ struct dependent_factory_t make_bfs_visitor(erased_pack_t&) const override; std::unique_ptr make_rw_visitor(erased_pack_t&) const override; + + std::unique_ptr make_graph_maker_visitor(erased_pack_t&) const override; }; // utility factory selector: diff --git a/cpp/include/cugraph/visitors/graph_reader_visitor.hpp b/cpp/include/cugraph/visitors/graph_make_visitor.hpp similarity index 73% rename from cpp/include/cugraph/visitors/graph_reader_visitor.hpp rename to cpp/include/cugraph/visitors/graph_make_visitor.hpp index 6fd332b7c42..4b1c9f32fb1 100644 --- a/cpp/include/cugraph/visitors/graph_reader_visitor.hpp +++ b/cpp/include/cugraph/visitors/graph_make_visitor.hpp @@ -29,17 +29,17 @@ template -struct graph_reader_visitor_t; +struct graph_maker_visitor; // dummy out non-candidate instantiation paths: // template -struct graph_reader_visitor_t::value)>> +struct graph_maker_visitor::value)>> : visitor_t { void visit_graph(graph_envelope_t::base_graph_t const&) override { @@ -59,14 +59,14 @@ struct graph_reader_visitor_t -struct graph_reader_visitor_t::value>> +struct graph_maker_visitor::value>> : visitor_t { - graph_reader_visitor_t(erased_pack_t& ep) : ep_(ep) {} + graph_maker_visitor(erased_pack_t& ep) : ep_(ep) {} void visit_graph(graph_envelope_t::base_graph_t const&) override; diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp new file mode 100644 index 00000000000..8b44b4a8d30 --- /dev/null +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2021, 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 + +namespace cugraph { +namespace visitors { +// +// wrapper code: +// +template +void graph_maker_visitor::value>>:: + visit_graph(graph_envelope_t::base_graph_t const& graph) +{ + using index_t = edge_t; + + // unless algorithms only call virtual graph methods + // under the hood, the algos require this conversion: + // + graph_t const* p_g = + static_cast const*>(&graph); + + auto gview = p_g->view(); + + auto const& v_args = ep_.get_args(); + + // unpack bfs() args: + // + // assert(v_args.size() == ?); // raft::handle_t, char* path, bool is_weighted..., + + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); + + char const* p_path = static_cast(v_args[1]); + + bool is_weighted = *static_cast(v_args[2]); + + // TODO: + // + + // create graph_envelope_t + // graph_envelope_t* p_g_envl = new ...; + + /// result_ = return_t{p_g_envl}; +} + +// EIDir's: +// +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +//------ + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +//------ + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +template class graph_maker_visitor; +template class graph_maker_visitor; + +} // namespace visitors + +namespace api { +using namespace cugraph::visitors; +// wrapper: +// +return_t graph_create( + DTypes vertex_tid, DTypes edge_tid, DTypes weight_tid, bool st, bool mg, erased_pack_t& ep_cnstr) +{ + auto const& v_args = ep_cnstr.get_args(); + + // unpack args: + // + assert(v_args.size() > 0); // raft::handle_t, ... + + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); + + erased_pack_t ep_graph{const_cast(&handle)}; + GTypes graph_tid = GTypes::GRAPH_T; + + // first construct empty graph, + // to be able to resolve types at runtime (CDD): + // + graph_envelope_t g{vertex_tid, edge_tid, weight_tid, st, mg, graph_tid, ep_graph}; + + auto p_visitor = g.factory()->make_graph_maker_visitor(ep_cnstr); + + g.apply(*p_visitor); + + return p_visitor->get_result(); // envelopes raw pointer: graph_envelope_t* +} + +} // namespace api + +} // namespace cugraph diff --git a/cpp/src/visitors/graph_reader_visitor.cpp b/cpp/src/visitors/graph_reader_visitor.cpp deleted file mode 100644 index 895964a2c91..00000000000 --- a/cpp/src/visitors/graph_reader_visitor.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2021, 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 - -namespace cugraph { -namespace visitors { -// -// wrapper code: -// -template -void graph_reader_visitor_t::value>>:: - visit_graph(graph_envelope_t::base_graph_t const& graph) -{ - using index_t = edge_t; - - // Note: this must be called only on: - // graph_view_t - // - if constexpr (st == false && mg == false) { - // unless algorithms only call virtual graph methods - // under the hood, the algos require this conversion: - // - graph_t const* p_g = - static_cast const*>(&graph); - - auto gview = p_g->view(); - - auto const& v_args = ep_.get_args(); - - // unpack bfs() args: - // - // assert(v_args.size() == ?); // raft::handle_t, char* path, bool is_weighted..., - - // cnstr. args unpacking: - // - raft::handle_t const& handle = *static_cast(v_args[0]); - - char const* p_path = static_cast(v_args[1]); - - bool is_weighted = *static_cast(v_args[2]); - - // TODO: - // - - // read graph: - // - - // create graph_envelope_t - - /// result_ = return_t{std::move(graph_envelope)}; - } else { - CUGRAPH_FAIL("Unsupported graph reader (store_transposed == true or multi_gpu == true)."); - } -} - -// EIDir's: -// -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -//------ - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -//------ - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -template class graph_reader_visitor_t; -template class graph_reader_visitor_t; - -} // namespace visitors - -namespace api { -using namespace cugraph::visitors; -// wrapper: -// -return_t graph_read_mm_file( - DTypes vertex_tid, DTypes edge_tid, DTypes weight_tid, bool st, bool mg, erased_pack_t& ep_reader) -{ - auto const& v_args = ep_reader.get_args(); - - // unpack args: - // - assert(v_args.size() > 0); // raft::handle_t, ... - - // cnstr. args unpacking: - // - raft::handle_t const& handle = *static_cast(v_args[0]); - - erased_pack_t ep_graph{const_cast(&handle)}; - GTypes graph_tid = GTypes::GRAPH_T; - - graph_envelope_t g{vertex_tid, edge_tid, weight_tid, st, mg, graph_tid, ep_graph}; - - auto p_visitor = g.factory()->make_graph_reader_visitor(ep_reader); - - g.apply(*p_visitor); - - return p_visitor->get_result(); -} - -} // namespace api - -} // namespace cugraph diff --git a/cpp/src/visitors/visitors_factory.cpp b/cpp/src/visitors/visitors_factory.cpp index 898c3f7958d..ab859c61e85 100644 --- a/cpp/src/visitors/visitors_factory.cpp +++ b/cpp/src/visitors/visitors_factory.cpp @@ -18,6 +18,7 @@ // #include +#include #include #include @@ -67,6 +68,19 @@ std::unique_ptr dependent_factory_t< return std::make_unique>(ep); } +template +std::unique_ptr +dependent_factory_t::value>>:: + make_graph_maker_visitor(erased_pack_t& ep) const +{ + return std::make_unique>(ep); +} + // EIDir's: // template class dependent_factory_t; From 6a87781ccf9f4b3448eecfb44fdf8dafee7d1489 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 22 Sep 2021 16:31:07 -0500 Subject: [PATCH 15/48] SG Graph factory visitor. --- cpp/include/cugraph/visitors/ret_terased.hpp | 2 + cpp/src/visitors/graph_make_visitor.cpp | 83 ++++++++++++-------- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/cpp/include/cugraph/visitors/ret_terased.hpp b/cpp/include/cugraph/visitors/ret_terased.hpp index f6ad88d8ede..7f893567550 100644 --- a/cpp/include/cugraph/visitors/ret_terased.hpp +++ b/cpp/include/cugraph/visitors/ret_terased.hpp @@ -111,6 +111,8 @@ struct return_t { void const* get_ptr(void) const { return static_cast(p_impl_.get()); } + void* release(void) { return static_cast(p_impl_.release()); } + private: std::unique_ptr p_impl_; }; diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp index 8b44b4a8d30..7e512543798 100644 --- a/cpp/src/visitors/graph_make_visitor.cpp +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -31,37 +31,54 @@ void graph_maker_visitor::value>>:: visit_graph(graph_envelope_t::base_graph_t const& graph) { - using index_t = edge_t; - - // unless algorithms only call virtual graph methods - // under the hood, the algos require this conversion: - // - graph_t const* p_g = - static_cast const*>(&graph); - - auto gview = p_g->view(); - - auto const& v_args = ep_.get_args(); - - // unpack bfs() args: - // - // assert(v_args.size() == ?); // raft::handle_t, char* path, bool is_weighted..., - - // cnstr. args unpacking: - // - raft::handle_t const& handle = *static_cast(v_args[0]); - - char const* p_path = static_cast(v_args[1]); - - bool is_weighted = *static_cast(v_args[2]); - - // TODO: - // - - // create graph_envelope_t - // graph_envelope_t* p_g_envl = new ...; - - /// result_ = return_t{p_g_envl}; + if constexpr (mg == false) { + auto const& v_args = ep_.get_args(); + + auto num_args = v_args.size(); + assert(num_args > 7); + + // cnstr. args unpacking: + // + raft::handle_t* ptr_handle = static_cast(v_args[0]); + vertex_t const* p_src = static_cast(v_args[1]); + vertex_t const* p_dst = static_cast(v_args[2]); + weight_t const* p_weights = static_cast(v_args[3]); + edge_t num_edges = *static_cast(v_args[4]); + vertex_t num_vertices = *static_cast(v_args[5]); + bool sorted = *static_cast(v_args[6]); + bool check = *static_cast(v_args[7]); + + bool is_sym{false}; + bool is_multigraph{false}; + + if (num_args > 8) { + is_sym = *static_cast(v_args[8]); + if (num_args > 9) is_multigraph = *static_cast(v_args[9]); + } + + cugraph::graph_properties_t graph_props{is_sym, is_multigraph}; + + std::optional opt_ptr_w; + if (p_weights) { opt_ptr_w = p_weights; } + + cugraph::edgelist_t edgelist{p_src, p_dst, opt_ptr_w, num_edges}; + + erased_pack_t ep_graph{ptr_handle, &edgelist, &num_vertices, &graph_props, &sorted, &check}; + + DTypes vertex_tid = reverse_dmap_t::type_id; + DTypes edge_tid = reverse_dmap_t::type_id; + DTypes weight_tid = reverse_dmap_t::type_id; + bool st_id = st; + bool mg_id = mg; + GTypes graph_tid = GTypes::GRAPH_T; + + graph_envelope_t graph_envelope{ + vertex_tid, edge_tid, weight_tid, st_id, mg_id, graph_tid, ep_graph}; + + result_ = return_t{std::move(graph_envelope)}; + } else { + CUGRAPH_FAIL("Graph factory visitor not currently supported (multi_gpu == true)."); + } } // EIDir's: @@ -137,7 +154,9 @@ return_t graph_create( g.apply(*p_visitor); - return p_visitor->get_result(); // envelopes raw pointer: graph_envelope_t* + return p_visitor->get_result(); // envelopes: graph_envelope_t + // conversion to raw pointer: + // reinterpret_cast(p_visitor->get_result().release()); } } // namespace api From fc00dd4001814adbac67b69c2717aeeac63740cb Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 22 Sep 2021 18:32:44 -0500 Subject: [PATCH 16/48] Fixed graph factory call to satisfy the graph_meta_t contract. --- cpp/src/visitors/graph_make_visitor.cpp | 14 +++++++------- cpp/tests/visitors/rw_test.cu | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp index 7e512543798..7b768c100a1 100644 --- a/cpp/src/visitors/graph_make_visitor.cpp +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -35,7 +35,7 @@ void graph_maker_visitor 7); + assert(num_args > 6); // cnstr. args unpacking: // @@ -45,15 +45,14 @@ void graph_maker_visitor(v_args[3]); edge_t num_edges = *static_cast(v_args[4]); vertex_t num_vertices = *static_cast(v_args[5]); - bool sorted = *static_cast(v_args[6]); - bool check = *static_cast(v_args[7]); + bool check = *static_cast(v_args[6]); bool is_sym{false}; bool is_multigraph{false}; - if (num_args > 8) { - is_sym = *static_cast(v_args[8]); - if (num_args > 9) is_multigraph = *static_cast(v_args[9]); + if (num_args > 7) { + is_sym = *static_cast(v_args[7]); + if (num_args > 8) is_multigraph = *static_cast(v_args[8]); } cugraph::graph_properties_t graph_props{is_sym, is_multigraph}; @@ -63,7 +62,8 @@ void graph_maker_visitor edgelist{p_src, p_dst, opt_ptr_w, num_edges}; - erased_pack_t ep_graph{ptr_handle, &edgelist, &num_vertices, &graph_props, &sorted, &check}; + cugraph::graph_meta_t meta{num_vertices, graph_props, std::nullopt}; + erased_pack_t ep_graph{ptr_handle, &edgelist, &meta, &check}; DTypes vertex_tid = reverse_dmap_t::type_id; DTypes edge_tid = reverse_dmap_t::type_id; diff --git a/cpp/tests/visitors/rw_test.cu b/cpp/tests/visitors/rw_test.cu index 10117ebf8f1..3445978533a 100644 --- a/cpp/tests/visitors/rw_test.cu +++ b/cpp/tests/visitors/rw_test.cu @@ -117,10 +117,11 @@ class Tests_RW_Visitor : public ::testing::TestWithParam { // cugraph::edgelist_t edgelist{ d_src.data(), d_dst.data(), opt_ptr_w, num_edges}; - bool sorted{false}; + bool check{false}; - erased_pack_t ep_graph{&handle, &edgelist, &num_vertices, &graph_props, &sorted, &check}; + cugraph::graph_meta_t meta{num_vertices, graph_props, std::nullopt}; + erased_pack_t ep_graph{&handle, &edgelist, &meta, &check}; DTypes vertex_tid = reverse_dmap_t::type_id; DTypes edge_tid = reverse_dmap_t::type_id; From a0752dadc35c726903b35f4a9a908698f8e7a2c3 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Thu, 23 Sep 2021 09:44:23 -0500 Subject: [PATCH 17/48] Added graph envelope factory to the erased API. --- cpp/include/cugraph/visitors/erased_api.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cpp/include/cugraph/visitors/erased_api.hpp b/cpp/include/cugraph/visitors/erased_api.hpp index 01fad35cef8..1003245ce58 100644 --- a/cpp/include/cugraph/visitors/erased_api.hpp +++ b/cpp/include/cugraph/visitors/erased_api.hpp @@ -50,6 +50,21 @@ return_t bfs(graph_envelope_t const& g, erased_pack_t& ep); */ return_t random_walks(graph_envelope_t const& g, erased_pack_t& ep); +/** + * @brief Type-erased graph-envelope wrapper. + * + * @param[in] vertex_tid `vertex_t` type id; + * @param[in] edge_tid `edge_t` type id; + * @param[in] weight_tid `weight_t` type id; + * @param[in] st `store_transpose`; + * @param[in] mg `multi_gpu`; + * @param[in] ep erased_pack_t pack of constructor erased arguments, that the caller is responsible + * to set correctly; + * @return return a type-erased unique_ptr; + */ +return_t graph_create( + DTypes vertex_tid, DTypes edge_tid, DTypes weight_tid, bool st, bool mg, erased_pack_t& ep_cnstr); + // TODO: more to follow... } // namespace api From 7a0cd276996d6dffdd78892553f273930584c528 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Thu, 23 Sep 2021 12:42:28 -0500 Subject: [PATCH 18/48] Added graph allocator / deallocator implementation to the C-API. --- cpp/include/cugraph_c/cugraph_api.h | 24 ++++++++++++ cpp/src/c_api/cugraph_api.cpp | 59 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index c9f5ce59894..69a7eeaddab 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -31,6 +31,11 @@ typedef enum cugraph_error_ { typedef int bool_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_raft_handle_ { @@ -84,6 +89,7 @@ typedef struct cugraph_rw_ret_ { /* C algorithm specific wrapper declarations: : should go into separate corresponding headers */ +/* Random Walks */ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_array_t* ptr_d_start, @@ -93,6 +99,24 @@ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_unique_ptr_t* ptr_sampling_strategy, cugraph_rw_ret_t* ret); +/* SG graph allocator*/ +cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_handle_t* p_handle, + data_type_id_t vertex_tid, + data_type_id_t edge_tid, + data_type_id_t weight_tid, + bool_t st, + cugraph_device_array_t* p_src, + cugraph_device_array_t* p_dst, + cugraph_device_array_t* p_weights, + size_t num_vertices, + size_t num_edges, + bool_t check, + bool_t is_symmetric, + bool_t is_multigraph); + +/* graph deallocator*/ +void cugraph_free_graph(cugraph_graph_envelope_t* graph); + #ifdef __cplusplus } #endif diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index e2cb8a04f92..759a3d8a16f 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -25,6 +25,10 @@ #include +extern "C" { +int data_type_sz[] = {4, 8, 4, 8}; +} + extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_array_t* ptr_d_start, @@ -77,3 +81,58 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr return status; } + +extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_handle_t* p_handle, + data_type_id_t vertex_tid, + data_type_id_t edge_tid, + data_type_id_t weight_tid, + bool_t st, + cugraph_device_array_t* p_src, + cugraph_device_array_t* p_dst, + cugraph_device_array_t* p_weights, + size_t num_vertices, + size_t num_edges, + bool_t check, + bool_t is_symmetric, + bool_t is_multigraph) +{ + using namespace cugraph::visitors; + + try { + raft::handle_t const* p_raft_handle = reinterpret_cast(p_handle); + + bool do_check = static_cast(check); + bool is_sym = static_cast(is_symmetric); + bool is_multi = static_cast(is_multigraph); + + erased_pack_t ep_graph_cnstr{const_cast(p_raft_handle), + p_src, + p_dst, + p_weights, + &num_edges, + &num_vertices, + &check, + &is_sym, + &is_multi}; + + return_t graph_uniq_ptr = cugraph::api::graph_create(static_cast(vertex_tid), + static_cast(edge_tid), + static_cast(weight_tid), + st, + false, + ep_graph_cnstr); + + return reinterpret_cast(graph_uniq_ptr.release()); + } catch (...) { + return nullptr; + } +} + +extern "C" void cugraph_free_graph(cugraph_graph_envelope_t* graph) +{ + using namespace cugraph::visitors; + + graph_envelope_t* ptr_graph_envelope = reinterpret_cast(graph); + + delete ptr_graph_envelope; +} From 7065363a9b211d22e50cdecdf2b584dbbfe8f8e6 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Thu, 23 Sep 2021 17:14:03 -0500 Subject: [PATCH 19/48] Added (mostly placeholder) C tests for C API, updated CI scripts, updated tests/CMakeLists.txt to build C tests. --- ci/test.sh | 11 ++- cpp/tests/CMakeLists.txt | 17 ++++ cpp/tests/c_api/c_test_utils.h | 49 +++++++++++ cpp/tests/c_api/create_sg_graph_test.c | 112 +++++++++++++++++++++++++ cpp/tests/c_api/random_walks_test.c | 42 ++++++++++ 5 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 cpp/tests/c_api/c_test_utils.h create mode 100644 cpp/tests/c_api/create_sg_graph_test.c create mode 100644 cpp/tests/c_api/random_walks_test.c diff --git a/ci/test.sh b/ci/test.sh index f166e7b295d..1a760f34a1a 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -70,12 +70,21 @@ if (python ${CUGRAPH_ROOT}/ci/utils/is_pascal.py); then echo "WARNING: skipping C++ tests on Pascal GPU arch." else echo "C++ gtests for cuGraph (single-GPU only)..." - for gt in $(find ./tests -name "*_TEST" | grep -v "MG_" || true); do + for gt in $(find ./tests -name "*_TEST" | grep -v "MG_\|CAPI_" || true); do test_name=$(basename $gt) echo "Running gtest $test_name" ${gt} ${GTEST_FILTER} ${GTEST_ARGS} echo "Ran gtest $test_name : return code was: $?, test script exit code is now: $EXITCODE" done + # FIXME: the C API tests do not generate XML, so CI systems will not show + # them in the GUI. Failing C API tests will still fail CI though, and the + # output will appear in logs. + for ct in $(find ./tests -name "CAPI_*_TEST"); do + test_name=$(basename $ct) + echo "Running C API test $test_name" + ${ct} + echo "Ran C API test $test_name : return code was: $?, test script exit code is now: $EXITCODE" + done fi echo "Python pytest for pylibcugraph..." diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index ab5c8a345ea..7c00dc70fa8 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -226,6 +226,17 @@ function(ConfigureTestMG CMAKE_TEST_NAME) endfunction() +function(ConfigureCTest CMAKE_TEST_NAME) + add_executable(${CMAKE_TEST_NAME} ${ARGN}) + + target_link_libraries(${CMAKE_TEST_NAME} + PRIVATE + cugraph_c + ) + + add_test(NAME ${CMAKE_TEST_NAME} COMMAND ${CMAKE_TEST_NAME}) +endfunction() + ################################################################################################### # - set rapids dataset path ---------------------------------------------------------------------- @@ -474,6 +485,12 @@ if(BUILD_CUGRAPH_MG_TESTS) endif() endif() +################################################################################################### +# - C API tests ----------------------------------------------------------------------------------- + +ConfigureCTest(CAPI_CREATE_SG_GRAPH_TEST c_api/create_sg_graph_test.c) +ConfigureCTest(CAPI_RANDOM_WALKS_TEST c_api/random_walks_test.c) + ################################################################################################### ### enable testing ################################################################################ ################################################################################################### diff --git a/cpp/tests/c_api/c_test_utils.h b/cpp/tests/c_api/c_test_utils.h new file mode 100644 index 00000000000..b62fa01f919 --- /dev/null +++ b/cpp/tests/c_api/c_test_utils.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, 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 + + +/* + * 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 ret_val = 0; + time_t start_time, end_time; + + printf("RUNNING: %s...", test_name); + fflush(stdout); + + time(&start_time); + ret_val = test(); + 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; +} + +#define RUN_TEST(test_name) run_test(test_name, #test_name) diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c new file mode 100644 index 00000000000..9c1a28116bb --- /dev/null +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021, 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 + + +/* + * Simple check of creating a graph from a COO on device memory. + */ +int test_create_sg_graph_simple() { + int test_failed = 0; + + cugraph_graph_envelope_t* G = NULL; + cugraph_raft_handle_t handle; + cugraph_device_array_t* src_ptr = NULL; + cugraph_device_array_t* dst_ptr = NULL; + cugraph_device_array_t* weights_ptr = NULL; + size_t num_verts = 4; + size_t num_edges = 3; + bool_t do_expensive_check = 0; + bool_t store_transposed = 0; + bool_t is_symmetric = 0; + bool_t is_multigraph = 0; + + /* + * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO + */ + + G = cugraph_make_sg_graph( + &handle, + INT32, INT32, INT32, /* vert, edge, weight types */ + store_transposed, + src_ptr, dst_ptr, weights_ptr, + num_verts, num_edges, + do_expensive_check, + is_symmetric, is_multigraph); + + cugraph_free_graph(G); + + return test_failed; +} + + +/* + * Since cugraph_make_sg_graph() can return NULL, this ensures + * cugraph_free_graph() can accept NULL. + */ +int test_free_graph_NULL_ptr() { + /* Returns void, so check that the call does not crash. */ + cugraph_free_graph((cugraph_graph_envelope_t*) NULL); + return 0; +} + + +/* + * Test creating a graph with NULL device arrays and "expensive check" enabled. + */ +int test_create_sg_graph_bad_arrays() { + int test_failed = 0; + + cugraph_graph_envelope_t* G = NULL; + cugraph_raft_handle_t handle; + cugraph_device_array_t* src_ptr = NULL; + cugraph_device_array_t* dst_ptr = NULL; + cugraph_device_array_t* weights_ptr = NULL; + size_t num_verts = 4; + size_t num_edges = 3; + bool_t do_expensive_check = 1; + bool_t store_transposed = 0; + bool_t is_symmetric = 0; + bool_t is_multigraph = 0; + + G = cugraph_make_sg_graph( + &handle, + INT32, INT32, INT32, /* vert, edge, weight types */ + store_transposed, + src_ptr, dst_ptr, weights_ptr, + num_verts, num_edges, + do_expensive_check, + is_symmetric, is_multigraph); + + if(G != NULL) { + test_failed = 1; + } + + return test_failed; +} + +/******************************************************************************/ + +int main(int argc, char** argv) { + int result = 0; + result |= RUN_TEST(test_create_sg_graph_simple); + result |= RUN_TEST(test_free_graph_NULL_ptr); + result |= RUN_TEST(test_create_sg_graph_bad_arrays); + return result; +} diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c new file mode 100644 index 00000000000..819b8e6a46e --- /dev/null +++ b/cpp/tests/c_api/random_walks_test.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, 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 + + +int test_random_walks_1() { + return 0; +} + +int test_random_walks_2() { + return 0; +} + +int test_random_walks_3() { + return 0; +} + +/******************************************************************************/ + +int main(int argc, char** argv) { + int result = 0; + result |= RUN_TEST(test_random_walks_1); + result |= RUN_TEST(test_random_walks_2); + result |= RUN_TEST(test_random_walks_3); + return result; +} From 53d4e189f5638d6edf3d1441b177f06c3b95583d Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Thu, 23 Sep 2021 17:17:31 -0500 Subject: [PATCH 20/48] Added temporary passing return code until test is finished. --- cpp/tests/c_api/create_sg_graph_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index 9c1a28116bb..a252b8a41c4 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -38,8 +38,10 @@ int test_create_sg_graph_simple() { bool_t is_multigraph = 0; /* - * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO + * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO. + * FIXME: return success until this test is finished. */ + return 0; G = cugraph_make_sg_graph( &handle, From ff1637b19006fb6fb5eeba901ebe3d833bb73fde Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Thu, 23 Sep 2021 17:27:48 -0500 Subject: [PATCH 21/48] clang format fixes. --- cpp/tests/c_api/c_test_utils.h | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cpp/tests/c_api/c_test_utils.h b/cpp/tests/c_api/c_test_utils.h index b62fa01f919..c87eb0b6f08 100644 --- a/cpp/tests/c_api/c_test_utils.h +++ b/cpp/tests/c_api/c_test_utils.h @@ -17,33 +17,33 @@ #include #include - /* * 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 ret_val = 0; - time_t start_time, end_time; - - printf("RUNNING: %s...", test_name); - fflush(stdout); - - time(&start_time); - ret_val = test(); - 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; +int run_test(int (*test)(), const char* test_name) +{ + int ret_val = 0; + time_t start_time, end_time; + + printf("RUNNING: %s...", test_name); + fflush(stdout); + + time(&start_time); + ret_val = test(); + 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; } #define RUN_TEST(test_name) run_test(test_name, #test_name) From 4829f6ac80ef0a4d6ad7282928f0f9e4c07eb371 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Thu, 23 Sep 2021 17:36:06 -0500 Subject: [PATCH 22/48] Temporarily returning success until test is finished. --- cpp/tests/c_api/create_sg_graph_test.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index a252b8a41c4..bd295a18b22 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -87,6 +87,11 @@ int test_create_sg_graph_bad_arrays() { bool_t is_symmetric = 0; bool_t is_multigraph = 0; + /* + * FIXME: return success until this test is finished. + */ + return 0; + G = cugraph_make_sg_graph( &handle, INT32, INT32, INT32, /* vert, edge, weight types */ From d696a6b9a98e3b08fea0504feebdbbfe1d47cca0 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Fri, 24 Sep 2021 11:58:47 -0500 Subject: [PATCH 23/48] Adding FAISS to the list of libs to link for the C API library. Still looking if this is the correct approach, but I think this is needed so the RPATH is updated correctly. --- cpp/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index a18336adb0e..9844b447a89 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -372,6 +372,7 @@ target_include_directories(cugraph_c target_link_libraries(cugraph_c PUBLIC cugraph::cugraph + FAISS::FAISS ) ################################################################################ From 74011596e4a30a9c3e98ad6d6d221ea9bd8691f0 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Fri, 24 Sep 2021 14:59:01 -0500 Subject: [PATCH 24/48] Added other link libs as private to cover extra dependencies for completeness, moved FAISS to private as well. --- cpp/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 9844b447a89..e0397add692 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -372,7 +372,12 @@ target_include_directories(cugraph_c target_link_libraries(cugraph_c PUBLIC cugraph::cugraph + PRIVATE FAISS::FAISS + CUDA::cublas + CUDA::curand + CUDA::cusolver + CUDA::cusparse ) ################################################################################ From 80e7adca2b323bcac6cb5445dc6561d56312a1ec Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Fri, 24 Sep 2021 15:35:14 -0500 Subject: [PATCH 25/48] Moving FAISS to PUBLIC section in order to have build find library location. --- cpp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index e0397add692..45e17b7f282 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -372,8 +372,8 @@ target_include_directories(cugraph_c target_link_libraries(cugraph_c PUBLIC cugraph::cugraph - PRIVATE FAISS::FAISS + PRIVATE CUDA::cublas CUDA::curand CUDA::cusolver From 4b85ee77805c0b8bdee67228a8abb3c21a1052b2 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Fri, 24 Sep 2021 15:43:07 -0500 Subject: [PATCH 26/48] Moving all lib deps to public for now for consistency and to ensure all cases are handled until we can better determine if any can be made private. --- cpp/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 45e17b7f282..495c609c238 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -373,7 +373,6 @@ target_link_libraries(cugraph_c PUBLIC cugraph::cugraph FAISS::FAISS - PRIVATE CUDA::cublas CUDA::curand CUDA::cusolver From 450e2699ffbd4d5c1d48ff1cc30a5bcd69a1b060 Mon Sep 17 00:00:00 2001 From: Rick Ratzel Date: Fri, 24 Sep 2021 16:11:29 -0500 Subject: [PATCH 27/48] Moved libcugraph.so to private after confirming that a local build worked. Ideally all would be private but some still need testing. --- cpp/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 495c609c238..d49e899262b 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -371,12 +371,13 @@ target_include_directories(cugraph_c # - C-API link libraries ------------------------------------------------------- target_link_libraries(cugraph_c PUBLIC - cugraph::cugraph FAISS::FAISS CUDA::cublas CUDA::curand CUDA::cusolver CUDA::cusparse + PRIVATE + cugraph::cugraph ) ################################################################################ From 470835d849ea35f5f201c072dcaadc14dd47136c Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Fri, 24 Sep 2021 17:08:28 -0500 Subject: [PATCH 28/48] Added device_buffer management in the C-API. --- cpp/include/cugraph_c/cugraph_api.h | 34 ++++++++++- cpp/src/c_api/cugraph_api.cpp | 89 ++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 69a7eeaddab..f802ef9ef6e 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -18,6 +18,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -25,12 +26,15 @@ extern "C" { typedef enum cugraph_error_ { CUGRAPH_SUCCESS, - CUGRAPH_ERROR_UNKNOWN, - CUGRAPH_INVALID_HANDLE + CUGRAPH_UNKNOWN_ERROR, + CUGRAPH_INVALID_HANDLE, + CUGRAPH_ALLOC_ERROR } cugraph_error_t; typedef int 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*/ @@ -87,7 +91,8 @@ typedef struct cugraph_rw_ret_ { * vertex_t_id, cugraph_rw_ret_t* rw_result); */ -/* C algorithm specific wrapper declarations: : should go into separate corresponding headers */ +/* C algorithm specific wrapper declarations; FIXME: should go into separate corresponding headers + */ /* Random Walks */ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, @@ -117,6 +122,29 @@ cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_handle_t* p_h /* graph deallocator*/ void cugraph_free_graph(cugraph_graph_envelope_t* graph); +/* rmm::device buffer allocator: fill pointer semantics*/ +cugraph_error_t cugraph_make_device_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + size_t n_elems, + cugraph_device_buffer_t* ptr_buffer); + +/* rmm::device buffer de-allocator*/ +void cugraph_free_device_buffer(cugraph_device_buffer_t* ptr_buffer); + +/* update dst device buffer from host src*/ +cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + cugraph_device_buffer_t* ptr_dst, + const byte_t* ptr_h_src, + size_t n_elems); + +/* update src host buffer device src*/ +cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + byte_t* ptr_h_dst, + const cugraph_device_buffer_t* ptr_src, + size_t n_elems); + #ifdef __cplusplus } #endif diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 759a3d8a16f..0cd5cbabfd0 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -23,6 +23,7 @@ #include +#include #include extern "C" { @@ -50,7 +51,10 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr graph_envelope_t* p_g_env = reinterpret_cast(ptr_graph_envelope); raft::handle_t const* p_raft_handle = reinterpret_cast(ptr_handle); - void* p_d_start = reinterpret_cast(ptr_d_start); + + if (!p_raft_handle) return CUGRAPH_ALLOC_ERROR; + + void* p_d_start = reinterpret_cast(ptr_d_start); bool use_padding = static_cast(flag_use_padding); @@ -76,12 +80,14 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr ret->p_erased_ret = new return_t(std::move(ret_erased)); } catch (...) { - status = CUGRAPH_ERROR_UNKNOWN; + status = CUGRAPH_UNKNOWN_ERROR; } return status; } +// graph factory: return pointer semantics (because it returns a stub); +// extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_handle_t* p_handle, data_type_id_t vertex_tid, data_type_id_t edge_tid, @@ -101,6 +107,8 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha try { raft::handle_t const* p_raft_handle = reinterpret_cast(p_handle); + if (!p_raft_handle) return nullptr; + bool do_check = static_cast(check); bool is_sym = static_cast(is_symmetric); bool is_multi = static_cast(is_multigraph); @@ -136,3 +144,80 @@ extern "C" void cugraph_free_graph(cugraph_graph_envelope_t* graph) delete ptr_graph_envelope; } + +// device buffer factory: fill pointer semantics (because the pointer is more than a stub); +// +extern "C" cugraph_error_t cugraph_make_device_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + size_t n_elems, + cugraph_device_buffer_t* ptr_buffer) +{ + cugraph_error_t status = CUGRAPH_SUCCESS; + try { + raft::handle_t const* p_raft_handle = reinterpret_cast(raft_handle); + + if (!p_raft_handle) return CUGRAPH_ALLOC_ERROR; + + size_t byte_sz = n_elems * (::data_type_sz[dtype]); + ptr_buffer->data_ = new rmm::device_buffer(byte_sz, p_raft_handle->get_stream()); + ptr_buffer->size_ = byte_sz; + } catch (...) { + status = CUGRAPH_ALLOC_ERROR; + } + return status; +} + +extern "C" void cugraph_free_device_buffer(cugraph_device_buffer_t* ptr_buffer) +{ + rmm::device_buffer* ptr_rmm_d_buf = reinterpret_cast(ptr_buffer->data_); + + delete ptr_rmm_d_buf; +} + +extern "C" cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + cugraph_device_buffer_t* ptr_dst, + const byte_t* ptr_h_src, + size_t n_elems) +{ + cugraph_error_t status = CUGRAPH_SUCCESS; + + try { + raft::handle_t const* ptr_raft_handle = reinterpret_cast(raft_handle); + + if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; + + size_t byte_sz = n_elems * (::data_type_sz[dtype]); + + raft::update_device( + static_cast(ptr_dst->data_), ptr_h_src, byte_sz, ptr_raft_handle->get_stream()); + } catch (...) { + status = CUGRAPH_UNKNOWN_ERROR; + } + return status; +} + +extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_t* raft_handle, + data_type_id_t dtype, + byte_t* ptr_h_dst, + const cugraph_device_buffer_t* ptr_src, + size_t n_elems) +{ + cugraph_error_t status = CUGRAPH_SUCCESS; + + try { + raft::handle_t const* ptr_raft_handle = reinterpret_cast(raft_handle); + + if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; + + size_t byte_sz = n_elems * (::data_type_sz[dtype]); + + raft::update_host(ptr_h_dst, + static_cast(ptr_src->data_), + byte_sz, + ptr_raft_handle->get_stream()); + } catch (...) { + status = CUGRAPH_UNKNOWN_ERROR; + } + return status; +} From 5e95b458df9436660341f7fdf034845c2074c6de Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 09:45:56 -0500 Subject: [PATCH 29/48] Simplified device buffer usage. --- cpp/include/cugraph_c/cugraph_api.h | 12 +- cpp/src/c_api/cugraph_api.cpp | 28 ++-- cpp/tests/c_api/create_sg_graph_test.c | 171 +++++++++++++------------ 3 files changed, 114 insertions(+), 97 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index f802ef9ef6e..121afb9ea2e 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -50,10 +50,6 @@ typedef struct cugraph_graph_envelope_ { int allign_; } cugraph_graph_envelope_t; -typedef struct cugraph_erased_device_array_ { - int allign_; -} cugraph_device_array_t; - typedef struct cugraph_erased_unique_ptr_ { int allign_; } cugraph_unique_ptr_t; @@ -97,7 +93,7 @@ typedef struct cugraph_rw_ret_ { /* Random Walks */ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, - cugraph_device_array_t* ptr_d_start, + cugraph_device_buffer_t* ptr_d_start, size_t num_paths, size_t max_depth, bool_t flag_use_padding, @@ -110,9 +106,9 @@ cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_handle_t* p_h data_type_id_t edge_tid, data_type_id_t weight_tid, bool_t st, - cugraph_device_array_t* p_src, - cugraph_device_array_t* p_dst, - cugraph_device_array_t* p_weights, + cugraph_device_buffer_t* p_src, + cugraph_device_buffer_t* p_dst, + cugraph_device_buffer_t* p_weights, size_t num_vertices, size_t num_edges, bool_t check, diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 0cd5cbabfd0..0785e330cfa 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -26,13 +26,21 @@ #include #include +namespace helpers { +void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) +{ + rmm::device_buffer* ptr_d_buffer = reinterpret_cast(ptr_buf->data_); + return ptr_d_buffer->data(); +} +} // namespace helpers + extern "C" { int data_type_sz[] = {4, 8, 4, 8}; } extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, - cugraph_device_array_t* ptr_d_start, + cugraph_device_buffer_t* ptr_d_start, size_t num_paths, size_t max_depth, bool_t flag_use_padding, @@ -54,7 +62,7 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr if (!p_raft_handle) return CUGRAPH_ALLOC_ERROR; - void* p_d_start = reinterpret_cast(ptr_d_start); + void* p_d_start = helpers::raw_device_ptr(ptr_d_start); bool use_padding = static_cast(flag_use_padding); @@ -93,9 +101,9 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha data_type_id_t edge_tid, data_type_id_t weight_tid, bool_t st, - cugraph_device_array_t* p_src, - cugraph_device_array_t* p_dst, - cugraph_device_array_t* p_weights, + cugraph_device_buffer_t* p_src, + cugraph_device_buffer_t* p_dst, + cugraph_device_buffer_t* p_weights, size_t num_vertices, size_t num_edges, bool_t check, @@ -113,10 +121,14 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha bool is_sym = static_cast(is_symmetric); bool is_multi = static_cast(is_multigraph); + void* p_d_src = helpers::raw_device_ptr(p_src); + void* p_d_dst = helpers::raw_device_ptr(p_dst); + void* p_d_weights = helpers::raw_device_ptr(p_weights); + erased_pack_t ep_graph_cnstr{const_cast(p_raft_handle), - p_src, - p_dst, - p_weights, + p_d_src, + p_d_dst, + p_d_weights, &num_edges, &num_vertices, &check, diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index bd295a18b22..3db80ae7767 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -14,106 +14,115 @@ * limitations under the License. */ -#include "c_test_utils.h" /* RUN_TEST */ +#include "c_test_utils.h" /* RUN_TEST */ #include - /* * Simple check of creating a graph from a COO on device memory. */ -int test_create_sg_graph_simple() { - int test_failed = 0; - - cugraph_graph_envelope_t* G = NULL; - cugraph_raft_handle_t handle; - cugraph_device_array_t* src_ptr = NULL; - cugraph_device_array_t* dst_ptr = NULL; - cugraph_device_array_t* weights_ptr = NULL; - size_t num_verts = 4; - size_t num_edges = 3; - bool_t do_expensive_check = 0; - bool_t store_transposed = 0; - bool_t is_symmetric = 0; - bool_t is_multigraph = 0; - - /* - * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO. - * FIXME: return success until this test is finished. - */ - return 0; - - G = cugraph_make_sg_graph( - &handle, - INT32, INT32, INT32, /* vert, edge, weight types */ - store_transposed, - src_ptr, dst_ptr, weights_ptr, - num_verts, num_edges, - do_expensive_check, - is_symmetric, is_multigraph); - - cugraph_free_graph(G); - - return test_failed; +int test_create_sg_graph_simple() +{ + int test_failed = 0; + + cugraph_graph_envelope_t* G = NULL; + cugraph_raft_handle_t handle; + cugraph_device_buffer_t* src_ptr = NULL; + cugraph_device_buffer_t* dst_ptr = NULL; + cugraph_device_buffer_t* weights_ptr = NULL; + size_t num_verts = 4; + size_t num_edges = 3; + bool_t do_expensive_check = 0; + bool_t store_transposed = 0; + bool_t is_symmetric = 0; + bool_t is_multigraph = 0; + + /* + * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO. + * FIXME: return success until this test is finished. + */ + return 0; + + G = cugraph_make_sg_graph(&handle, + INT32, + INT32, + INT32, /* vert, edge, weight types */ + store_transposed, + src_ptr, + dst_ptr, + weights_ptr, + num_verts, + num_edges, + do_expensive_check, + is_symmetric, + is_multigraph); + + cugraph_free_graph(G); + + return test_failed; } - /* * Since cugraph_make_sg_graph() can return NULL, this ensures * cugraph_free_graph() can accept NULL. */ -int test_free_graph_NULL_ptr() { - /* Returns void, so check that the call does not crash. */ - cugraph_free_graph((cugraph_graph_envelope_t*) NULL); - return 0; +int test_free_graph_NULL_ptr() +{ + /* Returns void, so check that the call does not crash. */ + cugraph_free_graph((cugraph_graph_envelope_t*)NULL); + return 0; } - /* * Test creating a graph with NULL device arrays and "expensive check" enabled. */ -int test_create_sg_graph_bad_arrays() { - int test_failed = 0; - - cugraph_graph_envelope_t* G = NULL; - cugraph_raft_handle_t handle; - cugraph_device_array_t* src_ptr = NULL; - cugraph_device_array_t* dst_ptr = NULL; - cugraph_device_array_t* weights_ptr = NULL; - size_t num_verts = 4; - size_t num_edges = 3; - bool_t do_expensive_check = 1; - bool_t store_transposed = 0; - bool_t is_symmetric = 0; - bool_t is_multigraph = 0; - - /* - * FIXME: return success until this test is finished. - */ - return 0; - - G = cugraph_make_sg_graph( - &handle, - INT32, INT32, INT32, /* vert, edge, weight types */ - store_transposed, - src_ptr, dst_ptr, weights_ptr, - num_verts, num_edges, - do_expensive_check, - is_symmetric, is_multigraph); - - if(G != NULL) { - test_failed = 1; - } - - return test_failed; +int test_create_sg_graph_bad_arrays() +{ + int test_failed = 0; + + cugraph_graph_envelope_t* G = NULL; + cugraph_raft_handle_t handle; + cugraph_device_buffer_t* src_ptr = NULL; + cugraph_device_buffer_t* dst_ptr = NULL; + cugraph_device_buffer_t* weights_ptr = NULL; + size_t num_verts = 4; + size_t num_edges = 3; + bool_t do_expensive_check = 1; + bool_t store_transposed = 0; + bool_t is_symmetric = 0; + bool_t is_multigraph = 0; + + /* + * FIXME: return success until this test is finished. + */ + return 0; + + G = cugraph_make_sg_graph(&handle, + INT32, + INT32, + INT32, /* vert, edge, weight types */ + store_transposed, + src_ptr, + dst_ptr, + weights_ptr, + num_verts, + num_edges, + do_expensive_check, + is_symmetric, + is_multigraph); + + if (G != NULL) { test_failed = 1; } + + return test_failed; } /******************************************************************************/ -int main(int argc, char** argv) { - int result = 0; - result |= RUN_TEST(test_create_sg_graph_simple); - result |= RUN_TEST(test_free_graph_NULL_ptr); - result |= RUN_TEST(test_create_sg_graph_bad_arrays); - return result; +int main(int argc, char** argv) +{ + int result = 0; + result |= RUN_TEST(test_create_sg_graph_simple); + result |= RUN_TEST(test_free_graph_NULL_ptr); + result |= RUN_TEST(test_create_sg_graph_bad_arrays); + return result; } From 751435f8cc366021909c803e333811da1ab83bfe Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 10:26:35 -0500 Subject: [PATCH 30/48] C-API raft::handle_t allocator/deallocator. --- cpp/include/cugraph_c/cugraph_api.h | 6 ++++++ cpp/src/c_api/cugraph_api.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 121afb9ea2e..406872f79fb 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -141,6 +141,12 @@ cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_t* raft_han const cugraph_device_buffer_t* ptr_src, size_t n_elems); +/* raft::handle_t allocator (for now; possibly a more encompassing handle in the future)*/ +cugraph_raft_handle_t* cugraph_create_handle(void); + +/* raft::handle_t deallocator*/ +void cugraph_free_handle(cugraph_raft_handle_t* p_handle); + #ifdef __cplusplus } #endif diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 0785e330cfa..cc77a8920f5 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -233,3 +233,14 @@ extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_ } return status; } + +cugraph_raft_handle_t* cugraph_create_handle(void) +{ + return reinterpret_cast(new raft::handle_t{}); +} + +void cugraph_free_handle(cugraph_raft_handle_t* p_handle) +{ + raft::handle_t* p_raft_handle = reinterpret_cast(p_handle); + delete p_raft_handle; +} From afe39b7ec192f8e77aaff0b819acd4ad158a8510 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 10:52:41 -0500 Subject: [PATCH 31/48] C-API unique_ptr allocator/deallocator. --- cpp/include/cugraph_c/cugraph_api.h | 10 +++++++++- cpp/src/c_api/cugraph_api.cpp | 25 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 406872f79fb..510bd6e5d00 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -90,7 +90,15 @@ typedef struct cugraph_rw_ret_ { /* C algorithm specific wrapper declarations; FIXME: should go into separate corresponding headers */ -/* Random Walks */ +/* Random Walks functionality*/ + +/* Sampling data allocator*/ +cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, double p, double q); + +/* Sampling data deallocator*/ +void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling); + +/* algorithm wrapper*/ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_buffer_t* ptr_d_start, diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index cc77a8920f5..3670cc97146 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -38,6 +38,25 @@ extern "C" { int data_type_sz[] = {4, 8, 4, 8}; } +cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, double p, double q) +{ + using ptr_sampling_t = std::unique_ptr; + try { + ptr_sampling_t ptr_uniq = std::make_unique(sampling_type_id, p, q); + ptr_sampling_t* p_sampling = new ptr_sampling_t(std::move(ptr_uniq)); + return reinterpret_cast(p_sampling); + } catch (...) { + return nullptr; + } +} + +void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling) +{ + using ptr_sampling_t = std::unique_ptr; + ptr_sampling_t* p_uniq_sampling = reinterpret_cast(p_sampling); + delete p_uniq_sampling; +} + extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_buffer_t* ptr_d_start, @@ -236,7 +255,11 @@ extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_ cugraph_raft_handle_t* cugraph_create_handle(void) { - return reinterpret_cast(new raft::handle_t{}); + try { + return reinterpret_cast(new raft::handle_t{}); + } catch (...) { + return nullptr; + } } void cugraph_free_handle(cugraph_raft_handle_t* p_handle) From f5e0eace3dd8a3bcac165dd9f65d75f7d93514bd Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 11:09:37 -0500 Subject: [PATCH 32/48] C-API RW result deallocator. --- cpp/include/cugraph_c/cugraph_api.h | 3 +++ cpp/src/c_api/cugraph_api.cpp | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 510bd6e5d00..049cf21d626 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -98,6 +98,9 @@ cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, dou /* Sampling data deallocator*/ void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling); +/* deallocate result returned by RW wrapper*/ +void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret); + /* algorithm wrapper*/ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 3670cc97146..54d50609152 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -57,6 +57,13 @@ void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling) delete p_uniq_sampling; } +void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret) +{ + using namespace cugraph::visitors; + return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); + delete p_ret; +} + extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_buffer_t* ptr_d_start, @@ -101,8 +108,11 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr return_t ret_erased = cugraph::api::random_walks(*p_g_env, ep); // caller deffered type-reconstruction: caller has the knoweldge - // and means to reconstruct the result: - // (CAVEAT: must allocate, because `ret_erased` is local to this function!) + // and means to reconstruct the result; + // in this case the underlying result (behind type-erased `return_t`) + // is `std::tuple` + // + // (allocated, because `ret_erased` is local to this function!) // ret->p_erased_ret = new return_t(std::move(ret_erased)); From 6d336643fb425b9b5837a1c8c542afc1a63fada6 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 13:37:01 -0500 Subject: [PATCH 33/48] Fixed the missing exten 'C'. --- cpp/src/c_api/cugraph_api.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 54d50609152..dcc7f284657 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -38,7 +38,9 @@ extern "C" { int data_type_sz[] = {4, 8, 4, 8}; } -cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, double p, double q) +extern "C" cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, + double p, + double q) { using ptr_sampling_t = std::unique_ptr; try { @@ -50,14 +52,14 @@ cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, dou } } -void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling) +extern "C" void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling) { using ptr_sampling_t = std::unique_ptr; ptr_sampling_t* p_uniq_sampling = reinterpret_cast(p_sampling); delete p_uniq_sampling; } -void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret) +extern "C" void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret) { using namespace cugraph::visitors; return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); @@ -263,7 +265,7 @@ extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_ return status; } -cugraph_raft_handle_t* cugraph_create_handle(void) +extern "C" cugraph_raft_handle_t* cugraph_create_handle(void) { try { return reinterpret_cast(new raft::handle_t{}); @@ -272,7 +274,7 @@ cugraph_raft_handle_t* cugraph_create_handle(void) } } -void cugraph_free_handle(cugraph_raft_handle_t* p_handle) +extern "C" void cugraph_free_handle(cugraph_raft_handle_t* p_handle) { raft::handle_t* p_raft_handle = reinterpret_cast(p_handle); delete p_raft_handle; From 45ca57c99b3e0675c93402f43d9cf2fadaf73636 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 14:14:41 -0500 Subject: [PATCH 34/48] Extractors for RW results and some cleanup / simplification of the C-API. --- cpp/include/cugraph_c/cugraph_api.h | 6 +-- cpp/src/c_api/cugraph_api.cpp | 62 +++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 049cf21d626..c7e03af50fa 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -142,15 +142,13 @@ void cugraph_free_device_buffer(cugraph_device_buffer_t* ptr_buffer); cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handle_t* raft_handle, data_type_id_t dtype, cugraph_device_buffer_t* ptr_dst, - const byte_t* ptr_h_src, - size_t n_elems); + const byte_t* ptr_h_src); /* update src host buffer device src*/ cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_t* raft_handle, data_type_id_t dtype, byte_t* ptr_h_dst, - const cugraph_device_buffer_t* ptr_src, - size_t n_elems); + const cugraph_device_buffer_t* ptr_src); /* raft::handle_t allocator (for now; possibly a more encompassing handle in the future)*/ cugraph_raft_handle_t* cugraph_create_handle(void); diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index dcc7f284657..e4c701963cf 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -66,6 +66,48 @@ extern "C" void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret) delete p_ret; } +extern "C" void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_v) +{ + using namespace cugraph::visitors; + using actual_ret_t = std::tuple; + return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); + + auto const& tpl_erased = p_ret->get(); + + rmm::device_buffer const& d_vertex = std::get<0>(tpl_erased); + p_d_buf_v->data_ = const_cast(d_vertex.data()); + p_d_buf_v->size_ = d_vertex.size(); +} + +extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_w) +{ + using namespace cugraph::visitors; + using actual_ret_t = std::tuple; + return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); + + auto const& tpl_erased = p_ret->get(); + + rmm::device_buffer const& d_weights = std::get<1>(tpl_erased); + p_d_buf_w->data_ = const_cast(d_weights.data()); + p_d_buf_w->size_ = d_weights.size(); +} + +extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_sz) +{ + using namespace cugraph::visitors; + using actual_ret_t = std::tuple; + return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); + + auto const& tpl_erased = p_ret->get(); + + rmm::device_buffer const& d_sizes = std::get<2>(tpl_erased); + p_d_buf_sz->data_ = const_cast(d_sizes.data()); + p_d_buf_sz->size_ = d_sizes.size(); +} + extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, cugraph_device_buffer_t* ptr_d_start, @@ -192,7 +234,7 @@ extern "C" void cugraph_free_graph(cugraph_graph_envelope_t* graph) // extern "C" cugraph_error_t cugraph_make_device_buffer(const cugraph_raft_handle_t* raft_handle, data_type_id_t dtype, - size_t n_elems, + size_t n_elems, // ... of type `dtype` cugraph_device_buffer_t* ptr_buffer) { cugraph_error_t status = CUGRAPH_SUCCESS; @@ -220,8 +262,7 @@ extern "C" void cugraph_free_device_buffer(cugraph_device_buffer_t* ptr_buffer) extern "C" cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handle_t* raft_handle, data_type_id_t dtype, cugraph_device_buffer_t* ptr_dst, - const byte_t* ptr_h_src, - size_t n_elems) + const byte_t* ptr_h_src) { cugraph_error_t status = CUGRAPH_SUCCESS; @@ -230,10 +271,10 @@ extern "C" cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handl if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; - size_t byte_sz = n_elems * (::data_type_sz[dtype]); - - raft::update_device( - static_cast(ptr_dst->data_), ptr_h_src, byte_sz, ptr_raft_handle->get_stream()); + raft::update_device(static_cast(ptr_dst->data_), + ptr_h_src, + ptr_dst->size_, + ptr_raft_handle->get_stream()); } catch (...) { status = CUGRAPH_UNKNOWN_ERROR; } @@ -243,8 +284,7 @@ extern "C" cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handl extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_t* raft_handle, data_type_id_t dtype, byte_t* ptr_h_dst, - const cugraph_device_buffer_t* ptr_src, - size_t n_elems) + const cugraph_device_buffer_t* ptr_src) { cugraph_error_t status = CUGRAPH_SUCCESS; @@ -253,11 +293,9 @@ extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_ if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; - size_t byte_sz = n_elems * (::data_type_sz[dtype]); - raft::update_host(ptr_h_dst, static_cast(ptr_src->data_), - byte_sz, + ptr_src->size_, ptr_raft_handle->get_stream()); } catch (...) { status = CUGRAPH_UNKNOWN_ERROR; From 2626bf0abe7f183383828a2067f4ec96044d5532 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 14:21:50 -0500 Subject: [PATCH 35/48] C-API RW extractors. --- cpp/include/cugraph_c/cugraph_api.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index c7e03af50fa..704c06cfac3 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -101,6 +101,15 @@ void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling); /* deallocate result returned by RW wrapper*/ void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret); +/* RW result vertex extractor*/ +void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_v); + +/* RW result weights extractor*/ +void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_w); + +/* RW result size extractor*/ +void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_sz); + /* algorithm wrapper*/ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, cugraph_graph_envelope_t* ptr_graph_envelope, From f10ea068a6b2ce64c13f3f7a924a2e3a3725b77e Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 16:40:00 -0500 Subject: [PATCH 36/48] C-API RW test checking functionality. --- cpp/tests/c_api/random_walks_test.c | 75 +++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 819b8e6a46e..28082f08c63 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -14,29 +14,76 @@ * limitations under the License. */ -#include "c_test_utils.h" /* RUN_TEST */ +#include "c_test_utils.h" /* RUN_TEST */ #include +/* sample graph: + 0 --(.1)--> 1 --(1.1)--> 4 + /|\ /\ | | + | / | | + (5.1) (3.1)(2.1) (3.2) + | / | | + | / \|/ \|/ + 2 --(4.1)-->3 --(7.2)--> 5 +*/ -int test_random_walks_1() { - return 0; -} +/* array of compressed paths, + using 1-based indexing for vertices, + to avoid confusion between, for example, + `012` and `12`, which result in same number*/ +#define N_PATHS 30 +static int32_t c_ps_array[N_PATHS] = {1, 2, 3, 4, 5, 6, 12, 124, 125, 1246, + 1256, 24, 25, 246, 256, 31, 32, 34, 312, 3124, + 3125, 31246, 31256, 324, 325, 3246, 3256, 346, 46, 56}; + +/* linear search of `value` inside `p_cmprsd_path[max_num_paths]`*/ +bool_t is_one_of(int32_t value, int32_t* p_cmprsd_path, int max_num_paths) +{ + int i = 0; + for (; i < max_num_paths; ++i) + if (value == p_cmprsd_path[i]) return 1; -int test_random_walks_2() { - return 0; + return 0; } -int test_random_walks_3() { - return 0; +/* check on host if all obtained paths are possible paths */ +bool_t host_check_paths( + int32_t* p_path_v, int32_t* p_path_sz, int num_paths, int32_t* p_cmprsd_path, int max_num_paths) +{ + int i = 0; + int count_passed = 0; + + for (; i < num_paths; ++i) { + int32_t crt_path_sz = p_path_sz[i]; + int path_it = 0; + int32_t crt_path_accumulator = 0; + bool_t flag_passed = 0; + + for (; path_it < crt_path_sz; ++path_it) { + crt_path_accumulator = *p_path_v + 10 * crt_path_accumulator; + ++p_path_v; /* iterate p_path_v*/ + } + + flag_passed = is_one_of(crt_path_accumulator, p_cmprsd_path, max_num_paths); + if (flag_passed) ++count_passed; + } + + return (count_passed == num_paths); } +int test_random_walks_1() { return 0; } + +int test_random_walks_2() { return 0; } + +int test_random_walks_3() { return 0; } /******************************************************************************/ -int main(int argc, char** argv) { - int result = 0; - result |= RUN_TEST(test_random_walks_1); - result |= RUN_TEST(test_random_walks_2); - result |= RUN_TEST(test_random_walks_3); - return result; +int main(int argc, char** argv) +{ + int result = 0; + result |= RUN_TEST(test_random_walks_1); + result |= RUN_TEST(test_random_walks_2); + result |= RUN_TEST(test_random_walks_3); + return result; } From 1e3d4e9e002e844016493d6d97d3656ce71ae6ce Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Mon, 27 Sep 2021 16:48:38 -0500 Subject: [PATCH 37/48] C-API RW test checking functionality simplified / more readable. --- cpp/tests/c_api/random_walks_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 28082f08c63..2a3c5937676 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -48,8 +48,7 @@ bool_t is_one_of(int32_t value, int32_t* p_cmprsd_path, int max_num_paths) } /* check on host if all obtained paths are possible paths */ -bool_t host_check_paths( - int32_t* p_path_v, int32_t* p_path_sz, int num_paths, int32_t* p_cmprsd_path, int max_num_paths) +bool_t host_check_paths(int32_t* p_path_v, int32_t* p_path_sz, int num_paths) { int i = 0; int count_passed = 0; @@ -65,7 +64,7 @@ bool_t host_check_paths( ++p_path_v; /* iterate p_path_v*/ } - flag_passed = is_one_of(crt_path_accumulator, p_cmprsd_path, max_num_paths); + flag_passed = is_one_of(crt_path_accumulator, c_ps_array, N_PATHS); if (flag_passed) ++count_passed; } From ac9c70d4fa80bcda49ec2dda81fd69bd9db9c239 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 11:47:08 -0500 Subject: [PATCH 38/48] C-API RW tests. Resources management: handle and device_buffers. --- cpp/include/cugraph_c/cugraph_api.h | 5 ++- cpp/src/c_api/cugraph_api.cpp | 9 ++++++ cpp/tests/c_api/random_walks_test.c | 48 ++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 704c06cfac3..47df9effe2c 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -71,7 +71,10 @@ typedef struct cugraph_rw_ret_ { void* p_erased_ret; } cugraph_rw_ret_t; -/* TODO: +/* Runtime production (not just DEBUG) assert */ +bool_t runtime_assert(bool_t statement_truth_value, const char* error_msg); + +/* Functionality: * (1.) graph_envelope "cnstr" / "destr": * * cugraph_graph_envelope_t* make_graph_envelope(...); diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index e4c701963cf..d93ea067eda 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace helpers { void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) { @@ -38,6 +40,13 @@ extern "C" { int data_type_sz[] = {4, 8, 4, 8}; } +bool_t runtime_assert(bool_t statement_truth_value, const char* error_msg) +{ + if (!statement_truth_value) { std::cerr << "ASSERTION FAILED: " << error_msg << '\n'; } + + return statement_truth_value; +} + extern "C" cugraph_unique_ptr_t* cugraph_create_sampling_strategy(int sampling_type_id, double p, double q) diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 2a3c5937676..6fb2c4a1085 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -70,7 +70,53 @@ bool_t host_check_paths(int32_t* p_path_v, int32_t* p_path_sz, int num_paths) return (count_passed == num_paths); } -int test_random_walks_1() { return 0; } +int test_random_walks_1() +{ + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; + + cugraph_error_t ret_code = CUGRAPH_SUCCESS; + 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_raft_handle_t* p_handle = NULL; + cugraph_device_buffer_t dbuf_src; + cugraph_device_buffer_t dbuf_dst; + cugraph_device_buffer_t dbuf_wgt; + + p_handle = cugraph_create_handle(); + runtime_assert(p_handle != NULL, "raft handle creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, INT32, num_edges, &dbuf_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, INT32, num_edges, &dbuf_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, FLOAT32, num_edges, &dbuf_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, INT32, &dbuf_src, (byte_t*)h_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, INT32, &dbuf_dst, (byte_t*)h_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, FLOAT32, &dbuf_wgt, (byte_t*)h_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); + + cugraph_free_device_buffer(&dbuf_wgt); + cugraph_free_device_buffer(&dbuf_dst); + cugraph_free_device_buffer(&dbuf_src); + cugraph_free_handle(p_handle); + + return 0; +} int test_random_walks_2() { return 0; } From 1e17b335e8ad5a4ec5a76431fedfe338b8651ddb Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 13:55:39 -0500 Subject: [PATCH 39/48] Fix#1 for graph_envelope factory crash. --- .../cugraph/visitors/graph_factory.hpp | 129 +++++++++++------- 1 file changed, 79 insertions(+), 50 deletions(-) diff --git a/cpp/include/cugraph/visitors/graph_factory.hpp b/cpp/include/cugraph/visitors/graph_factory.hpp index 9c8198bf3b0..7f57333f36a 100644 --- a/cpp/include/cugraph/visitors/graph_factory.hpp +++ b/cpp/include/cugraph/visitors/graph_factory.hpp @@ -111,59 +111,71 @@ struct graph_factory_t< : graph_factory_base_t { std::unique_ptr make_graph(erased_pack_t& ep) const override { +#ifdef _DEBUG_ + std::cout << "Enter graph factory...\n"; +#endif + /// std::cout << "Multi-GPU factory.\n"; std::vector const& v_args{ep.get_args()}; - // invoke cnstr. using cython arg pack: + // branch on various constructors based on + // number of arguments in the pack: // - assert(v_args.size() == 9); - -#ifdef _DEBUG_ - std::cout << "Enter graph factory...\n"; -#endif + auto pack_arg_sz = v_args.size(); + assert(pack_arg_sz > 0); // need at least the raft handle // cnstr. args unpacking: // raft::handle_t const& handle = *static_cast(v_args[0]); - vertex_t* src_vertices = static_cast(v_args[1]); - vertex_t* dst_vertices = static_cast(v_args[2]); - weight_t* weights = static_cast(v_args[3]); - vertex_t* vertex_partition_offsets = static_cast(v_args[4]); - edge_t num_partition_edges = *static_cast(v_args[5]); - vertex_t num_global_vertices = *static_cast(v_args[6]); - edge_t num_global_edges = *static_cast(v_args[7]); - bool sorted_by_degree = *static_cast(v_args[8]); - - // TODO: un-hardcode: have it passed int `ep` - // - graph_properties_t graph_props{.is_symmetric = false, .is_multigraph = false}; - bool do_expensive_check{false}; // FIXME: check what should this default to - - auto& row_comm = handle.get_subcomm(cugraph::partition_2d::key_naming_t().row_name()); - auto const row_comm_rank = row_comm.get_rank(); - auto const row_comm_size = row_comm.get_size(); // pcols - auto& col_comm = handle.get_subcomm(cugraph::partition_2d::key_naming_t().col_name()); - auto const col_comm_rank = col_comm.get_rank(); - auto const col_comm_size = col_comm.get_size(); // prows - - std::vector> edgelist( - {{src_vertices, dst_vertices, weights, num_partition_edges}}); - - std::vector partition_offsets_vector( - vertex_partition_offsets, vertex_partition_offsets + (row_comm_size * col_comm_size) + 1); - - partition_t partition( - partition_offsets_vector, row_comm_size, col_comm_size, row_comm_rank, col_comm_rank); - - std::optional> - opt_seg_off{}; // FIXME: may needd to pass/extract segment_offsets vector - - graph_meta_t meta{ - num_global_vertices, num_global_edges, graph_props, partition, opt_seg_off}; - - return std::make_unique>( - handle, edgelist, meta, do_expensive_check); + if (pack_arg_sz == 1) { + // invoke graph_t(handle); + return std::make_unique>( + handle); + } else { + // invoke cnstr. using cython arg pack: + // + assert(pack_arg_sz == 9); + + vertex_t* src_vertices = static_cast(v_args[1]); + vertex_t* dst_vertices = static_cast(v_args[2]); + weight_t* weights = static_cast(v_args[3]); + vertex_t* vertex_partition_offsets = static_cast(v_args[4]); + edge_t num_partition_edges = *static_cast(v_args[5]); + vertex_t num_global_vertices = *static_cast(v_args[6]); + edge_t num_global_edges = *static_cast(v_args[7]); + bool sorted_by_degree = *static_cast(v_args[8]); + + // TODO: un-hardcode: have it passed int `ep` + // + graph_properties_t graph_props{.is_symmetric = false, .is_multigraph = false}; + bool do_expensive_check{false}; // FIXME: check what should this default to + + auto& row_comm = handle.get_subcomm(cugraph::partition_2d::key_naming_t().row_name()); + auto const row_comm_rank = row_comm.get_rank(); + auto const row_comm_size = row_comm.get_size(); // pcols + auto& col_comm = handle.get_subcomm(cugraph::partition_2d::key_naming_t().col_name()); + auto const col_comm_rank = col_comm.get_rank(); + auto const col_comm_size = col_comm.get_size(); // prows + + std::vector> edgelist( + {{src_vertices, dst_vertices, weights, num_partition_edges}}); + + std::vector partition_offsets_vector( + vertex_partition_offsets, vertex_partition_offsets + (row_comm_size * col_comm_size) + 1); + + partition_t partition( + partition_offsets_vector, row_comm_size, col_comm_size, row_comm_rank, col_comm_rank); + + std::optional> + opt_seg_off{}; // FIXME: may needd to pass/extract segment_offsets vector + + graph_meta_t meta{ + num_global_vertices, num_global_edges, graph_props, partition, opt_seg_off}; + + return std::make_unique>( + handle, edgelist, meta, do_expensive_check); + } } }; @@ -178,20 +190,37 @@ struct graph_factory_t< std::unique_ptr make_graph(erased_pack_t& ep) const override { /// std::cout << "Single-GPU factory.\n"; + std::vector const& v_args{ep.get_args()}; - assert(v_args.size() == 4); + // branch on various constructors based on + // number of arguments in the pack: + // + auto pack_arg_sz = v_args.size(); + assert(pack_arg_sz > 0); // need at least the raft handle + // cnstr. args unpacking: + // raft::handle_t const& handle = *static_cast(v_args[0]); - auto const& elist = *static_cast const*>(v_args[1]); + if (pack_arg_sz == 1) { + // invoke graph_t(handle); + return std::make_unique>( + handle); + } else { + assert(pack_arg_sz == 4); + + raft::handle_t const& handle = *static_cast(v_args[0]); + + auto const& elist = *static_cast const*>(v_args[1]); - auto meta = *static_cast const*>(v_args[2]); + auto meta = *static_cast const*>(v_args[2]); - bool check = *static_cast(v_args[3]); + bool check = *static_cast(v_args[3]); - return std::make_unique>( - handle, elist, meta, check); + return std::make_unique>( + handle, elist, meta, check); + } } }; From f9f10061909217cf51ae6fd62f1b890823ff3302 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 16:48:40 -0500 Subject: [PATCH 40/48] Fixed graph_envelope creation crash. --- cpp/include/cugraph/visitors/ret_terased.hpp | 8 +- cpp/include/cugraph_c/cugraph_api.h | 2 +- cpp/src/c_api/cugraph_api.cpp | 66 +++++++++--- cpp/src/visitors/graph_make_visitor.cpp | 101 +++++++++++++++---- cpp/tests/c_api/create_sg_graph_test.c | 101 ++++++++++++------- cpp/tests/c_api/random_walks_test.c | 48 +-------- 6 files changed, 208 insertions(+), 118 deletions(-) diff --git a/cpp/include/cugraph/visitors/ret_terased.hpp b/cpp/include/cugraph/visitors/ret_terased.hpp index 7f893567550..7cc8140fb18 100644 --- a/cpp/include/cugraph/visitors/ret_terased.hpp +++ b/cpp/include/cugraph/visitors/ret_terased.hpp @@ -109,7 +109,13 @@ struct return_t { throw std::runtime_error("ERROR: nullptr impl."); } - void const* get_ptr(void) const { return static_cast(p_impl_.get()); } + void const* get_ptr(void) const + { + if (p_impl_) + return static_cast(p_impl_.get()); + else + return nullptr; + } void* release(void) { return static_cast(p_impl_.release()); } diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 47df9effe2c..4fe350452b7 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -31,7 +31,7 @@ typedef enum cugraph_error_ { CUGRAPH_ALLOC_ERROR } cugraph_error_t; -typedef int bool_t; +typedef enum bool_ { FALSE = 0, TRUE = 1 } bool_t; typedef int8_t byte_t; diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index d93ea067eda..5ac98fed4e7 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -28,6 +28,8 @@ #include +#define _DEBUG_ + namespace helpers { void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) { @@ -85,8 +87,9 @@ extern "C" void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_vertex = std::get<0>(tpl_erased); - p_d_buf_v->data_ = const_cast(d_vertex.data()); - p_d_buf_v->size_ = d_vertex.size(); + p_d_buf_v->data_ = + const_cast(d_vertex.data()); // FIXME: inconsistency; should be &d_vertex + p_d_buf_v->size_ = d_vertex.size(); } extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, @@ -99,8 +102,9 @@ extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_weights = std::get<1>(tpl_erased); - p_d_buf_w->data_ = const_cast(d_weights.data()); - p_d_buf_w->size_ = d_weights.size(); + p_d_buf_w->data_ = + const_cast(d_weights.data()); // FIXME: inconsistency; should be &d_weights + p_d_buf_w->size_ = d_weights.size(); } extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, @@ -113,8 +117,9 @@ extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_sizes = std::get<2>(tpl_erased); - p_d_buf_sz->data_ = const_cast(d_sizes.data()); - p_d_buf_sz->size_ = d_sizes.size(); + p_d_buf_sz->data_ = + const_cast(d_sizes.data()); // FIXME: inconsistency; should be &d_sizes + p_d_buf_sz->size_ = d_sizes.size(); } extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, @@ -194,11 +199,19 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha { using namespace cugraph::visitors; +#ifdef _DEBUG_ + std::cout << "C-api++: 1. Graph envelope maker entry.\n"; +#endif + try { raft::handle_t const* p_raft_handle = reinterpret_cast(p_handle); if (!p_raft_handle) return nullptr; +#ifdef _DEBUG_ + std::cout << "C-api++: 2. Unpack args.\n"; +#endif + bool do_check = static_cast(check); bool is_sym = static_cast(is_symmetric); bool is_multi = static_cast(is_multigraph); @@ -207,6 +220,10 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha void* p_d_dst = helpers::raw_device_ptr(p_dst); void* p_d_weights = helpers::raw_device_ptr(p_weights); +#ifdef _DEBUG_ + std::cout << "C-api++: 3. Re-pack args.\n"; +#endif + erased_pack_t ep_graph_cnstr{const_cast(p_raft_handle), p_d_src, p_d_dst, @@ -217,6 +234,10 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha &is_sym, &is_multi}; +#ifdef _DEBUG_ + std::cout << "C-api++: 4. Call graph create.\n"; +#endif + return_t graph_uniq_ptr = cugraph::api::graph_create(static_cast(vertex_tid), static_cast(edge_tid), static_cast(weight_tid), @@ -224,19 +245,34 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha false, ep_graph_cnstr); - return reinterpret_cast(graph_uniq_ptr.release()); +#ifdef _DEBUG_ + std::cout << "C-api++: 5. Return from graph create.\n"; +#endif + + if (graph_uniq_ptr.get_ptr() == nullptr) { + std::cerr << "cugraph++: Graph envelope creation failed."; + return nullptr; + } else { + graph_envelope_t const& graph_envelope = graph_uniq_ptr.get(); +#ifdef _DEBUG_ + std::cout << "C-api++: 5.1. Return graph_envelope.\n"; +#endif + + return reinterpret_cast(graph_uniq_ptr.release()); + } } catch (...) { + std::cerr << "cugraph++: Graph envelope creation failed."; return nullptr; } } -extern "C" void cugraph_free_graph(cugraph_graph_envelope_t* graph) +extern "C" void cugraph_free_graph(cugraph_graph_envelope_t* ptr_graph) { using namespace cugraph::visitors; - graph_envelope_t* ptr_graph_envelope = reinterpret_cast(graph); + return_t::base_return_t* p_released_ptr = reinterpret_cast(ptr_graph); - delete ptr_graph_envelope; + delete p_released_ptr; } // device buffer factory: fill pointer semantics (because the pointer is more than a stub); @@ -280,10 +316,9 @@ extern "C" cugraph_error_t cugraph_update_device_buffer(const cugraph_raft_handl if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; - raft::update_device(static_cast(ptr_dst->data_), - ptr_h_src, - ptr_dst->size_, - ptr_raft_handle->get_stream()); + void* ptr_d_dst = helpers::raw_device_ptr(ptr_dst); + raft::update_device( + static_cast(ptr_d_dst), ptr_h_src, ptr_dst->size_, ptr_raft_handle->get_stream()); } catch (...) { status = CUGRAPH_UNKNOWN_ERROR; } @@ -302,8 +337,9 @@ extern "C" cugraph_error_t cugraph_update_host_buffer(const cugraph_raft_handle_ if (!ptr_raft_handle) return CUGRAPH_ALLOC_ERROR; + void* ptr_d_src = helpers::raw_device_ptr(const_cast(ptr_src)); raft::update_host(ptr_h_dst, - static_cast(ptr_src->data_), + static_cast(ptr_d_src), ptr_src->size_, ptr_raft_handle->get_stream()); } catch (...) { diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp index 7b768c100a1..821452d9357 100644 --- a/cpp/src/visitors/graph_make_visitor.cpp +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -17,6 +17,12 @@ #include #include +#define _DEBUG_ + +#ifdef _DEBUG_ +#include +#endif + namespace cugraph { namespace visitors { // @@ -31,7 +37,14 @@ void graph_maker_visitor::value>>:: visit_graph(graph_envelope_t::base_graph_t const& graph) { +#ifdef _DEBUG_ + std::cout << "1. Graph maker visitor entry.\n"; +#endif if constexpr (mg == false) { +#ifdef _DEBUG_ + std::cout << "2. mg == false.\n"; +#endif + auto const& v_args = ep_.get_args(); auto num_args = v_args.size(); @@ -55,10 +68,14 @@ void graph_maker_visitor 8) is_multigraph = *static_cast(v_args[8]); } +#ifdef _DEBUG_ + std::cout << "3. Visitor argument unpacking done...\n"; +#endif + cugraph::graph_properties_t graph_props{is_sym, is_multigraph}; - std::optional opt_ptr_w; - if (p_weights) { opt_ptr_w = p_weights; } + std::optional opt_ptr_w = + p_weights != nullptr ? std::optional{p_weights} : std::nullopt; cugraph::edgelist_t edgelist{p_src, p_dst, opt_ptr_w, num_edges}; @@ -75,7 +92,16 @@ void graph_maker_visitor 0); // raft::handle_t, ... - // unpack args: - // - assert(v_args.size() > 0); // raft::handle_t, ... +#ifdef _DEBUG_ + std::cout << "5.2. Unpack args.\n"; +#endif + // cnstr. args unpacking: + // + raft::handle_t const& handle = *static_cast(v_args[0]); - // cnstr. args unpacking: - // - raft::handle_t const& handle = *static_cast(v_args[0]); +#ifdef _DEBUG_ + std::cout << "5.3. Re-pack args.\n"; +#endif - erased_pack_t ep_graph{const_cast(&handle)}; - GTypes graph_tid = GTypes::GRAPH_T; + erased_pack_t ep_graph{const_cast(&handle)}; + GTypes graph_tid = GTypes::GRAPH_T; - // first construct empty graph, - // to be able to resolve types at runtime (CDD): - // - graph_envelope_t g{vertex_tid, edge_tid, weight_tid, st, mg, graph_tid, ep_graph}; +#ifdef _DEBUG_ + std::cout << "5.4. Straw graph create...\n"; +#endif + + // first construct empty graph, + // to be able to resolve types at runtime (CDD): + // + graph_envelope_t g{vertex_tid, edge_tid, weight_tid, false, false, graph_tid, ep_graph}; - auto p_visitor = g.factory()->make_graph_maker_visitor(ep_cnstr); +#ifdef _DEBUG_ + std::cout << "6. graph envelope factory straw graph...done.\n"; +#endif - g.apply(*p_visitor); + auto p_visitor = g.factory()->make_graph_maker_visitor(ep_cnstr); - return p_visitor->get_result(); // envelopes: graph_envelope_t - // conversion to raw pointer: - // reinterpret_cast(p_visitor->get_result().release()); +#ifdef _DEBUG_ + std::cout << "7. graph envelope factory visitor creation...done.\n"; +#endif + + g.apply(*p_visitor); + +#ifdef _DEBUG_ + std::cout << "8. graph envelope factory visitor application...done.\n"; +#endif + + return p_visitor->get_result(); // envelopes: graph_envelope_t + // conversion to raw pointer: + // reinterpret_cast(p_visitor->get_result().release()); + } catch (std::exception const& ex) { + std::cerr << "cugraph++: " << ex.what() << "in graph_envelope factory.\n"; + return return_t{}; + } catch (...) { + std::cerr << "cugraph++: Unknown exception occurred in graph_envelope factory.\n"; + return return_t{}; + } } } // namespace api diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index 3db80ae7767..497b9e8074b 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -17,49 +17,82 @@ #include "c_test_utils.h" /* RUN_TEST */ #include +#include /* * Simple check of creating a graph from a COO on device memory. */ int test_create_sg_graph_simple() { - int test_failed = 0; + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; - cugraph_graph_envelope_t* G = NULL; - cugraph_raft_handle_t handle; - cugraph_device_buffer_t* src_ptr = NULL; - cugraph_device_buffer_t* dst_ptr = NULL; - cugraph_device_buffer_t* weights_ptr = NULL; - size_t num_verts = 4; - size_t num_edges = 3; - bool_t do_expensive_check = 0; - bool_t store_transposed = 0; - bool_t is_symmetric = 0; - bool_t is_multigraph = 0; + cugraph_error_t ret_code = CUGRAPH_SUCCESS; + size_t num_edges = 8; + size_t num_vertices = 6; - /* - * FIXME: populate GPU memory with a small (4 verts, 3 edges) graph COO. - * FIXME: return success until this test is finished. - */ - return 0; + 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}; - G = cugraph_make_sg_graph(&handle, - INT32, - INT32, - INT32, /* vert, edge, weight types */ - store_transposed, - src_ptr, - dst_ptr, - weights_ptr, - num_verts, - num_edges, - do_expensive_check, - is_symmetric, - is_multigraph); + cugraph_raft_handle_t* p_handle = NULL; + cugraph_device_buffer_t dbuf_src; + cugraph_device_buffer_t dbuf_dst; + cugraph_device_buffer_t dbuf_wgt; + cugraph_graph_envelope_t* p_graph_envelope = NULL; - cugraph_free_graph(G); + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; - return test_failed; + p_handle = cugraph_create_handle(); + runtime_assert(p_handle != NULL, "raft handle creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, weight_tid, num_edges, &dbuf_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_src, (byte_t*)h_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_dst, (byte_t*)h_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, weight_tid, &dbuf_wgt, (byte_t*)h_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); + + p_graph_envelope = cugraph_make_sg_graph(p_handle, + vertex_tid, + edge_tid, + weight_tid, + FALSE, + &dbuf_src, + &dbuf_dst, + &dbuf_wgt, + num_vertices, + num_edges, + FALSE, + FALSE, + FALSE); + runtime_assert(p_graph_envelope != NULL, "graph envelope creation failed."); + + cugraph_free_graph(p_graph_envelope); + + cugraph_free_device_buffer(&dbuf_wgt); + + cugraph_free_device_buffer(&dbuf_dst); + + cugraph_free_device_buffer(&dbuf_src); + + cugraph_free_handle(p_handle); + + return 0; } /* @@ -122,7 +155,7 @@ int main(int argc, char** argv) { int result = 0; result |= RUN_TEST(test_create_sg_graph_simple); - result |= RUN_TEST(test_free_graph_NULL_ptr); - result |= RUN_TEST(test_create_sg_graph_bad_arrays); + /*result |= RUN_TEST(test_free_graph_NULL_ptr); + result |= RUN_TEST(test_create_sg_graph_bad_arrays);*/ return result; } diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 6fb2c4a1085..2a3c5937676 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -70,53 +70,7 @@ bool_t host_check_paths(int32_t* p_path_v, int32_t* p_path_sz, int num_paths) return (count_passed == num_paths); } -int test_random_walks_1() -{ - typedef int32_t vertex_t; - typedef int32_t edge_t; - typedef float weight_t; - - cugraph_error_t ret_code = CUGRAPH_SUCCESS; - 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_raft_handle_t* p_handle = NULL; - cugraph_device_buffer_t dbuf_src; - cugraph_device_buffer_t dbuf_dst; - cugraph_device_buffer_t dbuf_wgt; - - p_handle = cugraph_create_handle(); - runtime_assert(p_handle != NULL, "raft handle creation failed."); - - ret_code = cugraph_make_device_buffer(p_handle, INT32, num_edges, &dbuf_src); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); - - ret_code = cugraph_make_device_buffer(p_handle, INT32, num_edges, &dbuf_dst); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); - - ret_code = cugraph_make_device_buffer(p_handle, FLOAT32, num_edges, &dbuf_wgt); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); - - ret_code = cugraph_update_device_buffer(p_handle, INT32, &dbuf_src, (byte_t*)h_src); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); - - ret_code = cugraph_update_device_buffer(p_handle, INT32, &dbuf_dst, (byte_t*)h_dst); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); - - ret_code = cugraph_update_device_buffer(p_handle, FLOAT32, &dbuf_wgt, (byte_t*)h_wgt); - runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); - - cugraph_free_device_buffer(&dbuf_wgt); - cugraph_free_device_buffer(&dbuf_dst); - cugraph_free_device_buffer(&dbuf_src); - cugraph_free_handle(p_handle); - - return 0; -} +int test_random_walks_1() { return 0; } int test_random_walks_2() { return 0; } From b8dd3109214ccd7812f5d4a181b188e41ac1b5c5 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 17:00:21 -0500 Subject: [PATCH 41/48] Clean-up. --- cpp/src/c_api/cugraph_api.cpp | 29 ++---------- cpp/src/visitors/graph_make_visitor.cpp | 62 +++---------------------- 2 files changed, 10 insertions(+), 81 deletions(-) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 5ac98fed4e7..aad29475cfa 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -28,8 +28,6 @@ #include -#define _DEBUG_ - namespace helpers { void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) { @@ -199,19 +197,11 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha { using namespace cugraph::visitors; -#ifdef _DEBUG_ - std::cout << "C-api++: 1. Graph envelope maker entry.\n"; -#endif - try { raft::handle_t const* p_raft_handle = reinterpret_cast(p_handle); if (!p_raft_handle) return nullptr; -#ifdef _DEBUG_ - std::cout << "C-api++: 2. Unpack args.\n"; -#endif - bool do_check = static_cast(check); bool is_sym = static_cast(is_symmetric); bool is_multi = static_cast(is_multigraph); @@ -220,10 +210,6 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha void* p_d_dst = helpers::raw_device_ptr(p_dst); void* p_d_weights = helpers::raw_device_ptr(p_weights); -#ifdef _DEBUG_ - std::cout << "C-api++: 3. Re-pack args.\n"; -#endif - erased_pack_t ep_graph_cnstr{const_cast(p_raft_handle), p_d_src, p_d_dst, @@ -234,10 +220,6 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha &is_sym, &is_multi}; -#ifdef _DEBUG_ - std::cout << "C-api++: 4. Call graph create.\n"; -#endif - return_t graph_uniq_ptr = cugraph::api::graph_create(static_cast(vertex_tid), static_cast(edge_tid), static_cast(weight_tid), @@ -245,18 +227,13 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha false, ep_graph_cnstr); -#ifdef _DEBUG_ - std::cout << "C-api++: 5. Return from graph create.\n"; -#endif - if (graph_uniq_ptr.get_ptr() == nullptr) { std::cerr << "cugraph++: Graph envelope creation failed."; return nullptr; } else { - graph_envelope_t const& graph_envelope = graph_uniq_ptr.get(); -#ifdef _DEBUG_ - std::cout << "C-api++: 5.1. Return graph_envelope.\n"; -#endif + // useful debug check, not dead code: + // + // graph_envelope_t const& graph_envelope = graph_uniq_ptr.get(); return reinterpret_cast(graph_uniq_ptr.release()); } diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp index 821452d9357..3a4a865678f 100644 --- a/cpp/src/visitors/graph_make_visitor.cpp +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -17,12 +17,6 @@ #include #include -#define _DEBUG_ - -#ifdef _DEBUG_ -#include -#endif - namespace cugraph { namespace visitors { // @@ -37,14 +31,7 @@ void graph_maker_visitor::value>>:: visit_graph(graph_envelope_t::base_graph_t const& graph) { -#ifdef _DEBUG_ - std::cout << "1. Graph maker visitor entry.\n"; -#endif if constexpr (mg == false) { -#ifdef _DEBUG_ - std::cout << "2. mg == false.\n"; -#endif - auto const& v_args = ep_.get_args(); auto num_args = v_args.size(); @@ -68,10 +55,6 @@ void graph_maker_visitor 8) is_multigraph = *static_cast(v_args[8]); } -#ifdef _DEBUG_ - std::cout << "3. Visitor argument unpacking done...\n"; -#endif - cugraph::graph_properties_t graph_props{is_sym, is_multigraph}; std::optional opt_ptr_w = @@ -92,16 +75,8 @@ void graph_maker_visitor 0); // raft::handle_t, ... + assert(v_args.size() > 0); // raft::handle_t, ... -#ifdef _DEBUG_ - std::cout << "5.2. Unpack args.\n"; -#endif // cnstr. args unpacking: // raft::handle_t const& handle = *static_cast(v_args[0]); -#ifdef _DEBUG_ - std::cout << "5.3. Re-pack args.\n"; -#endif - erased_pack_t ep_graph{const_cast(&handle)}; GTypes graph_tid = GTypes::GRAPH_T; -#ifdef _DEBUG_ - std::cout << "5.4. Straw graph create...\n"; -#endif - // first construct empty graph, // to be able to resolve types at runtime (CDD): // graph_envelope_t g{vertex_tid, edge_tid, weight_tid, false, false, graph_tid, ep_graph}; -#ifdef _DEBUG_ - std::cout << "6. graph envelope factory straw graph...done.\n"; -#endif - auto p_visitor = g.factory()->make_graph_maker_visitor(ep_cnstr); -#ifdef _DEBUG_ - std::cout << "7. graph envelope factory visitor creation...done.\n"; -#endif - g.apply(*p_visitor); -#ifdef _DEBUG_ - std::cout << "8. graph envelope factory visitor application...done.\n"; -#endif - return p_visitor->get_result(); // envelopes: graph_envelope_t - // conversion to raw pointer: - // reinterpret_cast(p_visitor->get_result().release()); + // FIXME: provide extraction mechanism: + // return_t::base_return_t* p_base_ret = p_visitor->get_result().release(); + // return_t::generic_return_t* p_typed_ret = + // dynamic_cast*>(p_base_ret); graph_envelope_t + // const& graph_envelope_t graph_envelope = p_typed_ret->get(); + } catch (std::exception const& ex) { std::cerr << "cugraph++: " << ex.what() << "in graph_envelope factory.\n"; return return_t{}; From bb5be4d6f8b30f529f0cda2aa06f2158327a9c2e Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 17:11:31 -0500 Subject: [PATCH 42/48] Fixed some C-API inconsistencies. --- cpp/include/cugraph_c/cugraph_api.h | 4 ++-- cpp/src/c_api/cugraph_api.cpp | 15 ++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 4fe350452b7..4b7e9692ca9 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -55,8 +55,8 @@ typedef struct cugraph_erased_unique_ptr_ { } cugraph_unique_ptr_t; typedef struct cugraph_device_buffer_ { - void* data_; - size_t size_; /* in bytes */ + void* data_; /* (rmm::device_buffer*) */ + size_t size_; /* rmm::device_buffer::size() */ } cugraph_device_buffer_t; /* C algorithm specific stubs: should go into separate corresponding headers */ diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index aad29475cfa..adf4a15e615 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -85,9 +85,8 @@ extern "C" void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_vertex = std::get<0>(tpl_erased); - p_d_buf_v->data_ = - const_cast(d_vertex.data()); // FIXME: inconsistency; should be &d_vertex - p_d_buf_v->size_ = d_vertex.size(); + p_d_buf_v->data_ = const_cast(static_cast(&d_vertex)); + p_d_buf_v->size_ = d_vertex.size(); } extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, @@ -100,9 +99,8 @@ extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_weights = std::get<1>(tpl_erased); - p_d_buf_w->data_ = - const_cast(d_weights.data()); // FIXME: inconsistency; should be &d_weights - p_d_buf_w->size_ = d_weights.size(); + p_d_buf_w->data_ = const_cast(static_cast(&d_weights)); + p_d_buf_w->size_ = d_weights.size(); } extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, @@ -115,9 +113,8 @@ extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, auto const& tpl_erased = p_ret->get(); rmm::device_buffer const& d_sizes = std::get<2>(tpl_erased); - p_d_buf_sz->data_ = - const_cast(d_sizes.data()); // FIXME: inconsistency; should be &d_sizes - p_d_buf_sz->size_ = d_sizes.size(); + p_d_buf_sz->data_ = const_cast(static_cast(&d_sizes)); + p_d_buf_sz->size_ = d_sizes.size(); } extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, From 2f5b4ee251ea280e3d123320e902228ebfbc543e Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Tue, 28 Sep 2021 17:25:45 -0500 Subject: [PATCH 43/48] Added a graph_envelope_t unwrapper to be called from within C++ delegates of the C-API. --- cpp/src/c_api/cugraph_api.cpp | 14 ++++++++++++++ cpp/src/visitors/graph_make_visitor.cpp | 10 ++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index adf4a15e615..e9fe7058bc0 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -34,6 +34,20 @@ void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) rmm::device_buffer* ptr_d_buffer = reinterpret_cast(ptr_buf->data_); return ptr_d_buffer->data(); } + +cugraph::visitors::graph_envelope_t const& extract_graph_envelope( + cugraph_graph_envelope_t* ptr_graph) +{ + using namespace cugraph::visitors; + + return_t::base_return_t* p_base_ret = reinterpret_cast(ptr_graph); + return_t::generic_return_t* p_typed_ret = + dynamic_cast*>(p_base_ret); + + graph_envelope_t const& graph_envelope = p_typed_ret->get(); + + return graph_envelope; +} } // namespace helpers extern "C" { diff --git a/cpp/src/visitors/graph_make_visitor.cpp b/cpp/src/visitors/graph_make_visitor.cpp index 3a4a865678f..6e20843994c 100644 --- a/cpp/src/visitors/graph_make_visitor.cpp +++ b/cpp/src/visitors/graph_make_visitor.cpp @@ -156,12 +156,14 @@ return_t graph_create( g.apply(*p_visitor); - return p_visitor->get_result(); // envelopes: graph_envelope_t - // FIXME: provide extraction mechanism: + // graph_envelope_t can be extracted through the following mechanism: + // // return_t::base_return_t* p_base_ret = p_visitor->get_result().release(); // return_t::generic_return_t* p_typed_ret = - // dynamic_cast*>(p_base_ret); graph_envelope_t - // const& graph_envelope_t graph_envelope = p_typed_ret->get(); + // dynamic_cast*>(p_base_ret); + // graph_envelope_t const& graph_envelope = p_typed_ret->get(); + // + return p_visitor->get_result(); } catch (std::exception const& ex) { std::cerr << "cugraph++: " << ex.what() << "in graph_envelope factory.\n"; From a59402b7eb21c290563d588bdbfd03c9d5cbbd9d Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 29 Sep 2021 10:22:06 -0500 Subject: [PATCH 44/48] Enabled negative tests on C-API graph creation. --- cpp/tests/c_api/create_sg_graph_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index 497b9e8074b..e34c314b230 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -155,7 +155,7 @@ int main(int argc, char** argv) { int result = 0; result |= RUN_TEST(test_create_sg_graph_simple); - /*result |= RUN_TEST(test_free_graph_NULL_ptr); - result |= RUN_TEST(test_create_sg_graph_bad_arrays);*/ + result |= RUN_TEST(test_free_graph_NULL_ptr); + result |= RUN_TEST(test_create_sg_graph_bad_arrays); return result; } From b82e00663d8de33b154b55c344e13d751c244314 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 29 Sep 2021 10:33:15 -0500 Subject: [PATCH 45/48] Fixed graph_envelope unpacking in C-API RW wrapper. --- cpp/src/c_api/cugraph_api.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index e9fe7058bc0..37a5b9f2e9b 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -149,7 +149,8 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr try { // unpack C stub arguments: // - graph_envelope_t* p_g_env = reinterpret_cast(ptr_graph_envelope); + graph_envelope_t& graph_envelope = + const_cast(helpers::extract_graph_envelope(ptr_graph_envelope)); raft::handle_t const* p_raft_handle = reinterpret_cast(ptr_handle); @@ -172,7 +173,7 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr // call algorithm: // - return_t ret_erased = cugraph::api::random_walks(*p_g_env, ep); + return_t ret_erased = cugraph::api::random_walks(graph_envelope, ep); // caller deffered type-reconstruction: caller has the knoweldge // and means to reconstruct the result; From a78f678a99050d1e29df644613b9723fe6156b66 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 29 Sep 2021 12:47:08 -0500 Subject: [PATCH 46/48] RW back to back tests. --- cpp/include/cugraph_c/cugraph_api.h | 11 +- cpp/src/c_api/cugraph_api.cpp | 77 +++--- cpp/tests/c_api/random_walks_test.c | 366 +++++++++++++++++++++++++++- 3 files changed, 405 insertions(+), 49 deletions(-) diff --git a/cpp/include/cugraph_c/cugraph_api.h b/cpp/include/cugraph_c/cugraph_api.h index 4b7e9692ca9..33ed1464c76 100644 --- a/cpp/include/cugraph_c/cugraph_api.h +++ b/cpp/include/cugraph_c/cugraph_api.h @@ -25,7 +25,7 @@ extern "C" { #endif typedef enum cugraph_error_ { - CUGRAPH_SUCCESS, + CUGRAPH_SUCCESS = 0, CUGRAPH_UNKNOWN_ERROR, CUGRAPH_INVALID_HANDLE, CUGRAPH_ALLOC_ERROR @@ -105,13 +105,16 @@ void cugraph_free_sampling_strategy(cugraph_unique_ptr_t* p_sampling); void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret); /* RW result vertex extractor*/ -void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_v); +cugraph_error_t extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_v); /* RW result weights extractor*/ -void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_w); +cugraph_error_t extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_w); /* RW result size extractor*/ -void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf_sz); +cugraph_error_t extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_sz); /* algorithm wrapper*/ cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 37a5b9f2e9b..39f45b29771 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -31,8 +31,12 @@ namespace helpers { void* raw_device_ptr(cugraph_device_buffer_t* ptr_buf) { - rmm::device_buffer* ptr_d_buffer = reinterpret_cast(ptr_buf->data_); - return ptr_d_buffer->data(); + if (!ptr_buf || !ptr_buf->data_) + return nullptr; + else { + rmm::device_buffer* ptr_d_buffer = reinterpret_cast(ptr_buf->data_); + return ptr_d_buffer->data(); + } } cugraph::visitors::graph_envelope_t const& extract_graph_envelope( @@ -48,6 +52,29 @@ cugraph::visitors::graph_envelope_t const& extract_graph_envelope( return graph_envelope; } + +template +cugraph_error_t extract_rw_result(cugraph_rw_ret_t* p_rw_ret, cugraph_device_buffer_t* p_d_buf) +{ + if (!p_rw_ret) + return CUGRAPH_ALLOC_ERROR; + else + try { + using namespace cugraph::visitors; + using actual_ret_t = std::tuple; + return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); + + auto const& tpl_erased = p_ret->get(); + + rmm::device_buffer const& d_vertex = std::get(tpl_erased); + p_d_buf->data_ = const_cast(static_cast(&d_vertex)); + p_d_buf->size_ = d_vertex.size(); + + return CUGRAPH_SUCCESS; + } catch (...) { + return CUGRAPH_UNKNOWN_ERROR; + } +} } // namespace helpers extern "C" { @@ -89,46 +116,22 @@ extern "C" void cugraph_free_rw_result(cugraph_rw_ret_t* p_rw_ret) delete p_ret; } -extern "C" void extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, - cugraph_device_buffer_t* p_d_buf_v) +extern "C" cugraph_error_t extract_vertex_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_v) { - using namespace cugraph::visitors; - using actual_ret_t = std::tuple; - return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); - - auto const& tpl_erased = p_ret->get(); - - rmm::device_buffer const& d_vertex = std::get<0>(tpl_erased); - p_d_buf_v->data_ = const_cast(static_cast(&d_vertex)); - p_d_buf_v->size_ = d_vertex.size(); + return helpers::extract_rw_result<0>(p_rw_ret, p_d_buf_v); } -extern "C" void extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, - cugraph_device_buffer_t* p_d_buf_w) +extern "C" cugraph_error_t extract_weight_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_w) { - using namespace cugraph::visitors; - using actual_ret_t = std::tuple; - return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); - - auto const& tpl_erased = p_ret->get(); - - rmm::device_buffer const& d_weights = std::get<1>(tpl_erased); - p_d_buf_w->data_ = const_cast(static_cast(&d_weights)); - p_d_buf_w->size_ = d_weights.size(); + return helpers::extract_rw_result<1>(p_rw_ret, p_d_buf_w); } -extern "C" void extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, - cugraph_device_buffer_t* p_d_buf_sz) +extern "C" cugraph_error_t extract_size_rw_result(cugraph_rw_ret_t* p_rw_ret, + cugraph_device_buffer_t* p_d_buf_sz) { - using namespace cugraph::visitors; - using actual_ret_t = std::tuple; - return_t* p_ret = reinterpret_cast(p_rw_ret->p_erased_ret); - - auto const& tpl_erased = p_ret->get(); - - rmm::device_buffer const& d_sizes = std::get<2>(tpl_erased); - p_d_buf_sz->data_ = const_cast(static_cast(&d_sizes)); - p_d_buf_sz->size_ = d_sizes.size(); + return helpers::extract_rw_result<2>(p_rw_ret, p_d_buf_sz); } extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr_handle, @@ -158,10 +161,14 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr void* p_d_start = helpers::raw_device_ptr(ptr_d_start); + if (!p_d_start) return CUGRAPH_ALLOC_ERROR; + bool use_padding = static_cast(flag_use_padding); ptr_sampling_t* p_uniq_sampling = reinterpret_cast(ptr_sampling_strategy); + if (!p_uniq_sampling) return CUGRAPH_ALLOC_ERROR; + // pack type-erased algorithm arguments: // erased_pack_t ep{const_cast(p_raft_handle), diff --git a/cpp/tests/c_api/random_walks_test.c b/cpp/tests/c_api/random_walks_test.c index 2a3c5937676..caf22bdf1ec 100644 --- a/cpp/tests/c_api/random_walks_test.c +++ b/cpp/tests/c_api/random_walks_test.c @@ -18,6 +18,9 @@ #include +#define NUM_PATHS 2 +#define MAX_DEPTH 4 + /* sample graph: 0 --(.1)--> 1 --(1.1)--> 4 /|\ /\ | | @@ -28,14 +31,122 @@ 2 --(4.1)-->3 --(7.2)--> 5 */ +/* positive test RW call flow*/ +int test_random_walks_1() +{ + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; + + cugraph_error_t ret_code = CUGRAPH_SUCCESS; + 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_raft_handle_t* p_handle = NULL; + cugraph_device_buffer_t dbuf_src; + cugraph_device_buffer_t dbuf_dst; + cugraph_device_buffer_t dbuf_wgt; + cugraph_graph_envelope_t* p_graph_envelope = NULL; + + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; + + /* RW args:*/ + cugraph_rw_ret_t rw_ret; + cugraph_device_buffer_t dbuf_start; + size_t num_paths = 2; + size_t max_depth = 4; + bool_t flag_use_padding = FALSE; + cugraph_unique_ptr_t* p_sampling_strategy = NULL; + vertex_t h_start[] = {0, 2}; + + p_handle = cugraph_create_handle(); + runtime_assert(p_handle != NULL, "raft handle creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, weight_tid, num_edges, &dbuf_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_src, (byte_t*)h_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_dst, (byte_t*)h_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, weight_tid, &dbuf_wgt, (byte_t*)h_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_paths, &dbuf_start); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "start device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_start, (byte_t*)h_start); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "start device_buffer update failed."); + + p_sampling_strategy = cugraph_create_sampling_strategy(0, 0.0, 0.0); + runtime_assert(p_sampling_strategy != NULL, "start device_buffer update failed."); + + p_graph_envelope = cugraph_make_sg_graph(p_handle, + vertex_tid, + edge_tid, + weight_tid, + FALSE, + &dbuf_src, + &dbuf_dst, + &dbuf_wgt, + num_vertices, + num_edges, + FALSE, + FALSE, + FALSE); + runtime_assert(p_graph_envelope != NULL, "graph envelope creation failed."); + + ret_code = cugraph_random_walks(p_handle, + p_graph_envelope, + &dbuf_start, + num_paths, + max_depth, + flag_use_padding, + p_sampling_strategy, + &rw_ret); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "cugraph_random_walks() failed."); + + cugraph_free_rw_result(&rw_ret); + + cugraph_free_graph(p_graph_envelope); + + cugraph_free_sampling_strategy(p_sampling_strategy); + + cugraph_free_device_buffer(&dbuf_start); + + cugraph_free_device_buffer(&dbuf_wgt); + + cugraph_free_device_buffer(&dbuf_dst); + + cugraph_free_device_buffer(&dbuf_src); + + cugraph_free_handle(p_handle); + + return 0; +} + /* array of compressed paths, using 1-based indexing for vertices, to avoid confusion between, for example, `012` and `12`, which result in same number*/ -#define N_PATHS 30 -static int32_t c_ps_array[N_PATHS] = {1, 2, 3, 4, 5, 6, 12, 124, 125, 1246, - 1256, 24, 25, 246, 256, 31, 32, 34, 312, 3124, - 3125, 31246, 31256, 324, 325, 3246, 3256, 346, 46, 56}; +#define NUM_MAX_PATHS 30 +static int32_t c_ps_array[NUM_MAX_PATHS] = { + 1, 2, 3, 4, 5, 6, 12, 124, 125, 1246, 1256, 24, 25, 246, 256, + 31, 32, 34, 312, 3124, 3125, 31246, 31256, 324, 325, 3246, 3256, 346, 46, 56}; /* linear search of `value` inside `p_cmprsd_path[max_num_paths]`*/ bool_t is_one_of(int32_t value, int32_t* p_cmprsd_path, int max_num_paths) @@ -60,21 +171,256 @@ bool_t host_check_paths(int32_t* p_path_v, int32_t* p_path_sz, int num_paths) bool_t flag_passed = 0; for (; path_it < crt_path_sz; ++path_it) { - crt_path_accumulator = *p_path_v + 10 * crt_path_accumulator; - ++p_path_v; /* iterate p_path_v*/ + crt_path_accumulator = + (*p_path_v + 1) + 10 * crt_path_accumulator; /* 1-based indexing for vertices is necessary + to avoid ambiguity, hence the `+1`*/ + ++p_path_v; /* iterate p_path_v*/ } - flag_passed = is_one_of(crt_path_accumulator, c_ps_array, N_PATHS); + flag_passed = is_one_of(crt_path_accumulator, c_ps_array, NUM_MAX_PATHS); if (flag_passed) ++count_passed; } return (count_passed == num_paths); } -int test_random_walks_1() { return 0; } -int test_random_walks_2() { return 0; } +/* check RW call results*/ +int test_random_walks_2() +{ + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; + + cugraph_error_t ret_code = CUGRAPH_SUCCESS; + 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_raft_handle_t* p_handle = NULL; + cugraph_device_buffer_t dbuf_src; + cugraph_device_buffer_t dbuf_dst; + cugraph_device_buffer_t dbuf_wgt; + cugraph_graph_envelope_t* p_graph_envelope = NULL; + + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; + + /* RW args:*/ + cugraph_rw_ret_t rw_ret; + cugraph_device_buffer_t dbuf_start; + cugraph_device_buffer_t dbuf_rw_ret_v; + cugraph_device_buffer_t dbuf_rw_ret_sz; + + size_t num_paths = NUM_PATHS; + size_t max_depth = MAX_DEPTH; + bool_t flag_use_padding = FALSE; + cugraph_unique_ptr_t* p_sampling_strategy = NULL; + bool_t flag_passed = FALSE; + vertex_t h_start[] = {0, 2}; + edge_t h_sizes[NUM_PATHS]; + vertex_t h_paths[NUM_PATHS * MAX_DEPTH]; + + p_handle = cugraph_create_handle(); + runtime_assert(p_handle != NULL, "raft handle creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, weight_tid, num_edges, &dbuf_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_src, (byte_t*)h_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_dst, (byte_t*)h_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, weight_tid, &dbuf_wgt, (byte_t*)h_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_paths, &dbuf_start); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "start device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_start, (byte_t*)h_start); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "start device_buffer update failed."); -int test_random_walks_3() { return 0; } + p_sampling_strategy = cugraph_create_sampling_strategy(0, 0.0, 0.0); + runtime_assert(p_sampling_strategy != NULL, "sampling strategy creation failed."); + + p_graph_envelope = cugraph_make_sg_graph(p_handle, + vertex_tid, + edge_tid, + weight_tid, + FALSE, + &dbuf_src, + &dbuf_dst, + &dbuf_wgt, + num_vertices, + num_edges, + FALSE, + FALSE, + FALSE); + runtime_assert(p_graph_envelope != NULL, "graph envelope creation failed."); + + ret_code = cugraph_random_walks(p_handle, + p_graph_envelope, + &dbuf_start, + num_paths, + max_depth, + flag_use_padding, + p_sampling_strategy, + &rw_ret); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "cugraph_random_walks() failed."); + + extract_size_rw_result(&rw_ret, &dbuf_rw_ret_sz); + + ret_code = cugraph_update_host_buffer(p_handle, edge_tid, (byte_t*)h_sizes, &dbuf_rw_ret_sz); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "size host buffer update failed."); + + extract_vertex_rw_result(&rw_ret, &dbuf_rw_ret_v); + + ret_code = cugraph_update_host_buffer(p_handle, vertex_tid, (byte_t*)h_paths, &dbuf_rw_ret_v); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "paths host buffer update failed."); + + flag_passed = host_check_paths(h_paths, h_sizes, num_paths); + runtime_assert(flag_passed == TRUE, "paths check failed."); + + cugraph_free_rw_result(&rw_ret); + + cugraph_free_graph(p_graph_envelope); + + cugraph_free_sampling_strategy(p_sampling_strategy); + + cugraph_free_device_buffer(&dbuf_start); + + cugraph_free_device_buffer(&dbuf_wgt); + + cugraph_free_device_buffer(&dbuf_dst); + + cugraph_free_device_buffer(&dbuf_src); + + cugraph_free_handle(p_handle); + + return 0; +} + +/* negative test RW call flow*/ +int test_random_walks_3() +{ + typedef int32_t vertex_t; + typedef int32_t edge_t; + typedef float weight_t; + + cugraph_error_t ret_code = CUGRAPH_SUCCESS; + 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_raft_handle_t* p_handle = NULL; + cugraph_device_buffer_t dbuf_src; + cugraph_device_buffer_t dbuf_dst; + cugraph_device_buffer_t dbuf_wgt; + cugraph_graph_envelope_t* p_graph_envelope = NULL; + + data_type_id_t vertex_tid = INT32; + data_type_id_t edge_tid = INT32; + data_type_id_t weight_tid = FLOAT32; + + /* RW args:*/ + cugraph_rw_ret_t rw_ret; + cugraph_device_buffer_t dbuf_start; + size_t num_paths = 2; + size_t max_depth = 4; + bool_t flag_use_padding = FALSE; + cugraph_unique_ptr_t* p_sampling_strategy = NULL; + bool_t flag_failed = FALSE; + + /* purposely erroneous start buffer*/ + dbuf_start.data_ = NULL; + dbuf_start.size_ = 0; + + p_handle = cugraph_create_handle(); + runtime_assert(p_handle != NULL, "raft handle creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, vertex_tid, num_edges, &dbuf_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer creation failed."); + + ret_code = cugraph_make_device_buffer(p_handle, weight_tid, num_edges, &dbuf_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer creation failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_src, (byte_t*)h_src); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "src device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, vertex_tid, &dbuf_dst, (byte_t*)h_dst); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "dst device_buffer update failed."); + + ret_code = cugraph_update_device_buffer(p_handle, weight_tid, &dbuf_wgt, (byte_t*)h_wgt); + runtime_assert(ret_code == CUGRAPH_SUCCESS, "weight device_buffer update failed."); + + p_sampling_strategy = cugraph_create_sampling_strategy(0, 0.0, 0.0); + runtime_assert(p_sampling_strategy != NULL, "sampling strategy creation failed."); + + p_graph_envelope = cugraph_make_sg_graph(p_handle, + vertex_tid, + edge_tid, + weight_tid, + FALSE, + &dbuf_src, + &dbuf_dst, + &dbuf_wgt, + num_vertices, + num_edges, + FALSE, + FALSE, + FALSE); + runtime_assert(p_graph_envelope != NULL, "graph envelope creation failed."); + + ret_code = cugraph_random_walks(p_handle, + p_graph_envelope, + &dbuf_start, + num_paths, + max_depth, + flag_use_padding, + p_sampling_strategy, + &rw_ret); + flag_failed = (ret_code != CUGRAPH_SUCCESS); + runtime_assert(flag_failed == TRUE, "cugraph_random_walks() should have failed."); + + cugraph_free_rw_result(&rw_ret); + + cugraph_free_graph(p_graph_envelope); + + cugraph_free_sampling_strategy(p_sampling_strategy); + + cugraph_free_device_buffer(&dbuf_start); + + cugraph_free_device_buffer(&dbuf_wgt); + + cugraph_free_device_buffer(&dbuf_dst); + + cugraph_free_device_buffer(&dbuf_src); + + cugraph_free_handle(p_handle); + + /* because bools and err return codes from programs have opposite meaning...*/ + if (flag_failed) + return 0; + else + return 1; +} /******************************************************************************/ From c64e235dc5ce4833f34673d7380b502ba4e4dd60 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 29 Sep 2021 15:32:22 -0500 Subject: [PATCH 47/48] Fixed one no-op test to actually test. --- cpp/src/c_api/cugraph_api.cpp | 2 +- cpp/tests/c_api/create_sg_graph_test.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 39f45b29771..28e49566ed7 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -219,7 +219,7 @@ extern "C" cugraph_graph_envelope_t* cugraph_make_sg_graph(const cugraph_raft_ha try { raft::handle_t const* p_raft_handle = reinterpret_cast(p_handle); - if (!p_raft_handle) return nullptr; + if (!p_raft_handle || !p_src || !p_dst || !p_weights) return nullptr; bool do_check = static_cast(check); bool is_sym = static_cast(is_symmetric); diff --git a/cpp/tests/c_api/create_sg_graph_test.c b/cpp/tests/c_api/create_sg_graph_test.c index e34c314b230..2154f68cd07 100644 --- a/cpp/tests/c_api/create_sg_graph_test.c +++ b/cpp/tests/c_api/create_sg_graph_test.c @@ -125,11 +125,6 @@ int test_create_sg_graph_bad_arrays() bool_t is_symmetric = 0; bool_t is_multigraph = 0; - /* - * FIXME: return success until this test is finished. - */ - return 0; - G = cugraph_make_sg_graph(&handle, INT32, INT32, From 84c23778e9f8e27fe040ac7f79237fc5085584a3 Mon Sep 17 00:00:00 2001 From: Andrei Schaffer Date: Wed, 29 Sep 2021 16:00:23 -0500 Subject: [PATCH 48/48] Fixed failure handling in RW wrapper. --- cpp/src/c_api/cugraph_api.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/src/c_api/cugraph_api.cpp b/cpp/src/c_api/cugraph_api.cpp index 28e49566ed7..01c3882d0d5 100644 --- a/cpp/src/c_api/cugraph_api.cpp +++ b/cpp/src/c_api/cugraph_api.cpp @@ -149,6 +149,10 @@ extern "C" cugraph_error_t cugraph_random_walks(const cugraph_raft_handle_t* ptr cugraph_error_t status = CUGRAPH_SUCCESS; + if (!ret) return CUGRAPH_ALLOC_ERROR; + + ret->p_erased_ret = nullptr; // initialize to `nullptr` in case of failure + try { // unpack C stub arguments: //