-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Naim
committed
Feb 2, 2024
1 parent
4895f74
commit 85d9ebc
Showing
7 changed files
with
302 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
3 4 34 | ||
3 5 35 | ||
4 3 43 | ||
4 5 45 | ||
5 3 53 | ||
5 4 54 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
266 changes: 266 additions & 0 deletions
266
cpp/examples/graph_partitioning/graph_partition_examples.cu
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
/* | ||
* Copyright (c) 2024, 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 <../tests/utilities/base_fixture.hpp> | ||
#include <../tests/utilities/test_utilities.hpp> | ||
|
||
// #include <prims/update_edge_src_dst_property.cuh> | ||
// #include <cugraph/edge_property.hpp> | ||
// #include <cugraph/edge_src_dst_property.hpp> | ||
|
||
#include <cugraph/algorithms.hpp> | ||
|
||
#include <raft/comms/mpi_comms.hpp> | ||
#include <raft/core/comms.hpp> | ||
#include <raft/core/handle.hpp> | ||
#include <raft/random/rng_state.hpp> | ||
|
||
#include <thrust/for_each.h> | ||
|
||
#include <iostream> | ||
#include <string> | ||
#include <system_error> | ||
using namespace std; | ||
|
||
void initialize_mpi_and_set_device(int argc, char** argv) | ||
{ | ||
RAFT_MPI_TRY(MPI_Init(&argc, &argv)); | ||
|
||
int comm_rank{}; | ||
RAFT_MPI_TRY(MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank)); | ||
|
||
int comm_size{}; | ||
RAFT_MPI_TRY(MPI_Comm_size(MPI_COMM_WORLD, &comm_size)); | ||
|
||
int num_gpus_per_node{}; | ||
RAFT_CUDA_TRY(cudaGetDeviceCount(&num_gpus_per_node)); | ||
RAFT_CUDA_TRY(cudaSetDevice(comm_rank % num_gpus_per_node)); | ||
} | ||
|
||
std::unique_ptr<raft::handle_t> initialize_mg_handle(std::string const& allocation_mode = "cuda") | ||
{ | ||
int comm_rank{}; | ||
RAFT_MPI_TRY(MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank)); | ||
|
||
std::set<std::string> possible_allocation_modes = {"cuda", "pool", "binning", "managed"}; | ||
|
||
if (possible_allocation_modes.find(allocation_mode) == possible_allocation_modes.end()) { | ||
if (!comm_rank) { | ||
std::cout << "'" << allocation_mode | ||
<< "' is not a valid allocation mode. It must be one of the followings -" | ||
<< std::endl; | ||
std::for_each(possible_allocation_modes.cbegin(), | ||
possible_allocation_modes.cend(), | ||
[](std::string mode) { std::cout << mode << std::endl; }); | ||
} | ||
RAFT_MPI_TRY(MPI_Finalize()); | ||
|
||
exit(0); | ||
} | ||
|
||
if (!comm_rank) { | ||
std::cout << "Using '" << allocation_mode | ||
<< "' allocation mode to create device memory resources." << std::endl; | ||
} | ||
std::shared_ptr<rmm::mr::device_memory_resource> resource = | ||
cugraph::test::create_memory_resource(allocation_mode); | ||
rmm::mr::set_current_device_resource(resource.get()); | ||
|
||
std::unique_ptr<raft::handle_t> handle = | ||
std::make_unique<raft::handle_t>(rmm::cuda_stream_per_thread, resource); | ||
|
||
raft::comms::initialize_mpi_comms(handle.get(), MPI_COMM_WORLD); | ||
auto& comm = handle->get_comms(); | ||
auto const comm_size = comm.get_size(); | ||
|
||
auto gpu_row_comm_size = static_cast<int>(sqrt(static_cast<double>(comm_size))); | ||
while (comm_size % gpu_row_comm_size != 0) { | ||
--gpu_row_comm_size; | ||
} | ||
|
||
cugraph::partition_manager::init_subcomm(*handle, gpu_row_comm_size); | ||
|
||
return std::move(handle); | ||
} | ||
|
||
/** | ||
* @brief This function reads graph from an input csv file and | ||
* display vertex and edge partitions. | ||
*/ | ||
|
||
template <typename vertex_t, typename edge_t, typename weight_t, bool multi_gpu> | ||
void look_into_vertex_and_edge_partitions(raft::handle_t const& handle, | ||
std::string const& csv_graph_file_path) | ||
{ | ||
auto const comm_rank = handle.get_comms().get_rank(); | ||
auto const comm_size = handle.get_comms().get_size(); | ||
|
||
std::cout << "Rank_" << comm_rank << ", reading graph from " << csv_graph_file_path << std::endl; | ||
|
||
bool renumber = true; // must be true for distributed graph. | ||
|
||
// Read a graph (along with edge properties e.g. edge weights, if provided) from | ||
// the input csv file | ||
|
||
auto [graph, edge_weights, renumber_map] = | ||
cugraph::test::read_graph_from_csv_file<vertex_t, edge_t, weight_t, false, multi_gpu>( | ||
handle, csv_graph_file_path, true, renumber); | ||
|
||
// Meta of the non-owning view of the graph object store vertex/edge partitioning map | ||
auto graph_view = graph.view(); | ||
|
||
// Non-owning of the edge edge_weights object | ||
auto edge_weight_view = edge_weights ? std::make_optional((*edge_weights).view()) : std::nullopt; | ||
|
||
// Total number of vertices | ||
vertex_t global_number_of_vertices = graph_view.number_of_vertices(); | ||
|
||
// | ||
// Look into vertex partitions | ||
// | ||
|
||
// Number of vertices mapped to this process, ie the size of | ||
// the vertex partition assigned to this process | ||
|
||
vertex_t size_of_the_vertex_partition_assigned_to_this_process = | ||
graph_view.local_vertex_partition_range_size(); | ||
|
||
// NOTE: The `renumber_map` contains the vertices assigned to this process. | ||
|
||
// Print verties mapped to this process | ||
RAFT_CUDA_TRY(cudaDeviceSynchronize()); | ||
if (renumber_map) { | ||
auto vertex_partition_title = std::string("vertices@rank_").append(std::to_string(comm_rank)); | ||
raft::print_device_vector( | ||
vertex_partition_title.c_str(), (*renumber_map).data(), (*renumber_map).size(), std::cout); | ||
} | ||
|
||
std::vector<vertex_t> h_vertices_in_this_proces((*renumber_map).size()); | ||
|
||
raft::update_host(h_vertices_in_this_proces.data(), | ||
(*renumber_map).data(), | ||
(*renumber_map).size(), | ||
handle.get_stream()); | ||
handle.sync_stream(); | ||
|
||
assert(size_of_the_vertex_partition_assigned_to_this_process == (*renumber_map).size()); | ||
|
||
// The position of a vertex in the `renumber_map` is indicative of its new (aka renumberd) | ||
// vertex id. The new (aka renumbered) id of the first vertex, ie the vertex at position 0 | ||
// of `renumber_map`, assigned to this process | ||
|
||
vertex_t renumber_vertex_id_of_local_first = graph_view.local_vertex_partition_range_first(); | ||
|
||
// The new (aka renumbered) id of the last vertex, ie the vertex at position | ||
// `size_of_the_vertex_partition_assigned_to_this_process` - 1 of `renumber_map`, | ||
// assigned to this process | ||
|
||
vertex_t renumber_vertex_id_of_local_last = graph_view.local_vertex_partition_range_last(); | ||
|
||
// Print original vertex ids, new (aka renumbered) vertex ids and the ranks of the owner processes | ||
|
||
if (renumber_map) { | ||
thrust::for_each( | ||
thrust::host, | ||
thrust::make_zip_iterator( | ||
thrust::make_tuple(h_vertices_in_this_proces.begin(), | ||
thrust::make_counting_iterator(renumber_vertex_id_of_local_first))), | ||
thrust::make_zip_iterator( | ||
thrust::make_tuple(h_vertices_in_this_proces.end(), | ||
thrust::make_counting_iterator(renumber_vertex_id_of_local_last))), | ||
[comm_rank](auto old_and_new_id_pair) { | ||
auto old_id = thrust::get<0>(old_and_new_id_pair); | ||
auto new_id = thrust::get<1>(old_and_new_id_pair); | ||
printf("owner rank = %d, original vertex id %d -----> new (renumbered) vertex id %d\n", | ||
comm_rank, | ||
static_cast<int>(old_id), | ||
static_cast<int>(new_id)); | ||
}); | ||
} | ||
|
||
// | ||
// Look into edge partitions and their associated edge properties (if any) | ||
// | ||
|
||
for (size_t ep_idx = 0; ep_idx < graph_view.number_of_local_edge_partitions(); ++ep_idx) { | ||
// Toplogy | ||
auto edge_partition = graph_view.local_edge_partition_view(ep_idx); | ||
|
||
auto number_of_edges = edge_partition.number_of_edges(); | ||
auto offsets = edge_partition.offsets(); | ||
auto indices = edge_partition.indices(); | ||
|
||
auto offsets_title = std::string("offsets_") | ||
.append(std::to_string(comm_rank)) | ||
.append("_") | ||
.append(std::to_string(ep_idx)); | ||
RAFT_CUDA_TRY(cudaDeviceSynchronize()); | ||
raft::print_device_vector(offsets_title.c_str(), offsets.begin(), offsets.size(), std::cout); | ||
|
||
auto indices_title = std::string("indices_") | ||
.append(std::to_string(comm_rank)) | ||
.append("_") | ||
.append(std::to_string(ep_idx)); | ||
RAFT_CUDA_TRY(cudaDeviceSynchronize()); | ||
raft::print_device_vector(indices_title.c_str(), indices.begin(), indices.size(), std::cout); | ||
|
||
// Edge property values | ||
if (edge_weight_view) { | ||
auto value_firsts = edge_weight_view->value_firsts(); | ||
auto edge_counts = edge_weight_view->edge_counts(); | ||
|
||
assert(number_of_edges == edge_counts[ep_idx]); | ||
|
||
RAFT_CUDA_TRY(cudaDeviceSynchronize()); | ||
auto weights_title = std::string("weights_") | ||
.append(std::to_string(comm_rank)) | ||
.append("_") | ||
.append(std::to_string(ep_idx)); | ||
raft::print_device_vector( | ||
weights_title.c_str(), value_firsts[ep_idx], edge_counts[ep_idx], std::cout); | ||
} | ||
} | ||
|
||
// using graph_view_t = cugraph::graph_view_t<vertex_t, edge_t, false, multi_gpu>; | ||
|
||
// cugraph::edge_src_property_t<graph_view_t, weight_t> src_vertex_props(handle, graph_view); | ||
} | ||
|
||
int main(int argc, char** argv) | ||
{ | ||
if (argc < 2) { | ||
std::cout << "Usage: ./sg_examples path_to_your_csv_graph_file [memory allocation mode]" | ||
<< std::endl; | ||
exit(0); | ||
} | ||
|
||
std::string const& csv_graph_file_path = argv[1]; | ||
std::string const& allocation_mode = argc < 3 ? "cuda" : argv[2]; | ||
|
||
initialize_mpi_and_set_device(argc, argv); | ||
std::unique_ptr<raft::handle_t> handle = initialize_mg_handle(allocation_mode); | ||
|
||
auto const comm_rank = handle->get_comms().get_rank(); | ||
auto const comm_size = handle->get_comms().get_size(); | ||
|
||
using vertex_t = int32_t; | ||
using edge_t = int32_t; | ||
using weight_t = float; | ||
constexpr bool multi_gpu = true; | ||
|
||
look_into_vertex_and_edge_partitions<vertex_t, edge_t, weight_t, multi_gpu>(*handle, | ||
csv_graph_file_path); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
Using 'cuda' allocation mode to create device memory resources. | ||
Rank_1, reading graph from graph2.csv | ||
Rank_0, reading graph from graph2.csv | ||
vertices@rank_0=[5]; | ||
owned by rank 0, original vertex id 5 --- becomes --> 0 | ||
offsets_0_0=[0,0]; | ||
indices_0_0=[]; | ||
weights_0_0=[]; | ||
offsets_0_1=[0,1,2]; | ||
indices_0_1=[0,0]; | ||
weights_0_1=[35,45]; | ||
vertices@rank_1=[3,4]; | ||
owned by rank 1, original vertex id 3 --- becomes --> 1 | ||
owned by rank 1, original vertex id 4 --- becomes --> 2 | ||
offsets_1_0=[0,2]; | ||
indices_1_0=[1,2]; | ||
weights_1_0=[53,54]; | ||
offsets_1_1=[0,1,2]; | ||
indices_1_1=[2,1]; | ||
weights_1_1=[34,43]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters