Skip to content

Commit 9724271

Browse files
committed
Fix bug found in how we handle empty frontiers in sampling
1 parent 5be6b95 commit 9724271

5 files changed

Lines changed: 78 additions & 18 deletions

File tree

cpp/include/cugraph/prims/detail/per_v_select_transform_e.cuh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,19 @@ per_v_select_transform_e(
585585
std::inclusive_scan(
586586
local_key_list_sizes.begin(), local_key_list_sizes.end(), local_key_list_offsets.begin() + 1);
587587

588+
// Empty frontier (after minor-comm size exchange): return immediately.
589+
if (local_key_list_offsets.back() == 0) {
590+
auto empty_results = allocate_dataframe_buffer<T>(0, handle.get_stream());
591+
if (invalid_value) {
592+
return std::make_tuple(std::nullopt, std::move(empty_results));
593+
} else {
594+
rmm::device_uvector<size_t> sample_offsets(size_t{1}, handle.get_stream());
595+
sample_offsets.set_element_to_zero_async(size_t{0}, handle.get_stream());
596+
return std::make_tuple(std::make_optional(std::move(sample_offsets)),
597+
std::move(empty_results));
598+
}
599+
}
600+
588601
// 1. aggregate key_list
589602

590603
std::optional<key_buffer_t> aggregate_local_key_list{std::nullopt};

cpp/include/cugraph/prims/detail/sample_and_compute_local_nbr_indices.cuh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5067,6 +5067,12 @@ homogeneous_uniform_sample_and_compute_local_nbr_indices(
50675067
}
50685068
assert(minor_comm_size == graph_view.number_of_local_edge_partitions());
50695069

5070+
if (local_frontier_offsets.back() == 0) {
5071+
return std::make_tuple(rmm::device_uvector<edge_t>(0, handle.get_stream()),
5072+
std::optional<rmm::device_uvector<size_t>>{std::nullopt},
5073+
std::vector<size_t>(local_frontier_offsets.size(), size_t{0}));
5074+
}
5075+
50705076
auto aggregate_local_frontier_major_first =
50715077
thrust_tuple_get_or_identity<KeyIterator, 0>(aggregate_local_frontier_key_first);
50725078

@@ -5191,6 +5197,12 @@ heterogeneous_uniform_sample_and_compute_local_nbr_indices(
51915197
}
51925198
assert(minor_comm_size == graph_view.number_of_local_edge_partitions());
51935199

5200+
if (local_frontier_offsets.back() == 0) {
5201+
return std::make_tuple(rmm::device_uvector<edge_t>(0, handle.get_stream()),
5202+
std::optional<rmm::device_uvector<size_t>>{std::nullopt},
5203+
std::vector<size_t>(local_frontier_offsets.size(), size_t{0}));
5204+
}
5205+
51945206
auto num_edge_types = static_cast<edge_type_t>(Ks.size());
51955207

51965208
auto edge_mask_view = graph_view.edge_mask_view();
@@ -5528,6 +5540,12 @@ homogeneous_biased_sample_and_compute_local_nbr_indices(
55285540
}
55295541
assert(minor_comm_size == graph_view.number_of_local_edge_partitions());
55305542

5543+
if (local_frontier_offsets.back() == 0) {
5544+
return std::make_tuple(rmm::device_uvector<edge_t>(0, handle.get_stream()),
5545+
std::optional<rmm::device_uvector<size_t>>{std::nullopt},
5546+
std::vector<size_t>(local_frontier_offsets.size(), size_t{0}));
5547+
}
5548+
55315549
auto edge_mask_view = graph_view.edge_mask_view();
55325550

55335551
// 1. compute biases for unique keys (to reduce memory footprint)
@@ -5684,6 +5702,12 @@ heterogeneous_biased_sample_and_compute_local_nbr_indices(
56845702
}
56855703
assert(minor_comm_size == graph_view.number_of_local_edge_partitions());
56865704

5705+
if (local_frontier_offsets.back() == 0) {
5706+
return std::make_tuple(rmm::device_uvector<edge_t>(0, handle.get_stream()),
5707+
std::optional<rmm::device_uvector<size_t>>{std::nullopt},
5708+
std::vector<size_t>(local_frontier_offsets.size(), size_t{0}));
5709+
}
5710+
56875711
auto num_edge_types = static_cast<edge_type_t>(Ks.size());
56885712

56895713
auto edge_mask_view = graph_view.edge_mask_view();

cpp/include/cugraph/prims/detail/transform_v_frontier_e.cuh

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
#pragma once
@@ -614,24 +614,26 @@ auto transform_v_frontier_e(raft::handle_t const& handle,
614614
get_dataframe_buffer_begin(aggregate_value_buffer));
615615
}
616616
} else {
617-
raft::grid_1d_thread_t update_grid(
618-
(local_frontier_offsets[i + 1] - local_frontier_offsets[i]),
619-
detail::transform_v_frontier_e_kernel_block_size,
620-
handle.get_device_properties().maxGridSize[0]);
617+
auto frontier_size = local_frontier_offsets[i + 1] - local_frontier_offsets[i];
618+
if (frontier_size > 0) {
619+
raft::grid_1d_thread_t update_grid(frontier_size,
620+
detail::transform_v_frontier_e_kernel_block_size,
621+
handle.get_device_properties().maxGridSize[0]);
621622

622-
detail::transform_v_frontier_e_hypersparse_or_low_degree<false, GraphViewType>
623-
<<<update_grid.num_blocks, update_grid.block_size, 0, handle.get_stream()>>>(
624-
edge_partition,
625-
edge_partition_frontier_key_first,
626-
thrust::make_counting_iterator(size_t{0}),
627-
thrust::make_counting_iterator(local_frontier_offsets[i + 1] - local_frontier_offsets[i]),
628-
edge_partition_src_value_input,
629-
edge_partition_dst_value_input,
630-
edge_partition_e_value_input,
631-
edge_partition_e_mask,
632-
edge_partition_frontier_local_degree_offsets,
633-
e_op,
634-
get_dataframe_buffer_begin(aggregate_value_buffer));
623+
detail::transform_v_frontier_e_hypersparse_or_low_degree<false, GraphViewType>
624+
<<<update_grid.num_blocks, update_grid.block_size, 0, handle.get_stream()>>>(
625+
edge_partition,
626+
edge_partition_frontier_key_first,
627+
thrust::make_counting_iterator(size_t{0}),
628+
thrust::make_counting_iterator(frontier_size),
629+
edge_partition_src_value_input,
630+
edge_partition_dst_value_input,
631+
edge_partition_e_value_input,
632+
edge_partition_e_mask,
633+
edge_partition_frontier_local_degree_offsets,
634+
e_op,
635+
get_dataframe_buffer_begin(aggregate_value_buffer));
636+
}
635637
}
636638
}
637639

cpp/src/sampling/neighbor_sampling_impl.cuh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <cugraph/graph.hpp>
1616
#include <cugraph/graph_functions.hpp>
1717
#include <cugraph/sampling_functions.hpp>
18+
#include <cugraph/utilities/host_scalar_comm.hpp>
1819
#include <cugraph/utilities/thrust_wrappers/fill.hpp>
1920
#include <cugraph/vertex_partition_view.hpp>
2021

@@ -189,6 +190,16 @@ neighbor_sample_impl(raft::handle_t const& handle,
189190
}
190191

191192
for (size_t hop = 0; hop < num_hops; ++hop) {
193+
{
194+
size_t local_frontier_size = (hop == 0) ? starting_vertices.size() : frontier_vertices.size();
195+
size_t frontier_size = local_frontier_size;
196+
if constexpr (multi_gpu) {
197+
frontier_size = host_scalar_allreduce(
198+
handle.get_comms(), local_frontier_size, raft::comms::op_t::SUM, handle.get_stream());
199+
}
200+
if (frontier_size == 0) { break; }
201+
}
202+
192203
std::optional<std::vector<size_t>> level_Ks{std::nullopt};
193204
std::unique_ptr<bool[]> gather_flags{};
194205
std::vector<raft::device_span<vertex_t const>> next_frontier_vertex_spans{};

cpp/src/sampling/temporal_sampling_impl.cuh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <cugraph/sampling_functions.hpp>
2020
#include <cugraph/utilities/device_functors.cuh>
2121
#include <cugraph/utilities/error.hpp>
22+
#include <cugraph/utilities/host_scalar_comm.hpp>
2223
#include <cugraph/utilities/thrust_wrappers/fill.hpp>
2324
#include <cugraph/utilities/thrust_wrappers/sort.hpp>
2425
#include <cugraph/vertex_partition_view.hpp>
@@ -615,6 +616,15 @@ temporal_neighbor_sample_impl(
615616
produced_edge_lists.reserve(num_hops * 2); // at most a biased/uniform + a gather list per hop
616617

617618
for (size_t hop = 0; hop < num_hops; ++hop) {
619+
{
620+
size_t frontier_size = frontier_vertices.size();
621+
if constexpr (multi_gpu) {
622+
frontier_size = host_scalar_allreduce(
623+
handle.get_comms(), frontier_size, raft::comms::op_t::SUM, handle.get_stream());
624+
}
625+
if (frontier_size == 0) { break; }
626+
}
627+
618628
std::optional<std::vector<size_t>> level_Ks{std::nullopt};
619629
std::unique_ptr<bool[]> gather_flags{};
620630
std::vector<raft::device_span<vertex_t const>> next_frontier_vertex_spans{};

0 commit comments

Comments
 (0)