Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move edge triangle count to the stable API #4382

Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
be543b1
enable k-1 core
jnke2016 Apr 25, 2024
327a07e
perform edge triangle count in chunk
jnke2016 Apr 26, 2024
c623465
perform edge triangle count in chunks
jnke2016 Apr 30, 2024
7cbb61f
enable k-1 core optimization and unroll intersection edges in chunks
jnke2016 Apr 30, 2024
6dbe157
fix style
jnke2016 Apr 30, 2024
3e12f02
fix style
jnke2016 Apr 30, 2024
1f00dd6
add edge triangle count tests
jnke2016 May 4, 2024
da330b3
move edge triangle count to the stable API
jnke2016 May 4, 2024
913283d
fix style
jnke2016 May 4, 2024
d758071
update branch
jnke2016 May 4, 2024
ce3ff47
fix style
jnke2016 May 4, 2024
0ebb7f5
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 4, 2024
9d2d4f7
update function definition
jnke2016 May 5, 2024
2019d99
fix style
jnke2016 May 5, 2024
701e33d
update test
jnke2016 May 5, 2024
9a12994
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 5, 2024
0d74246
return edge_property_t
jnke2016 May 7, 2024
c103e52
fix style
jnke2016 May 7, 2024
686a214
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 7, 2024
50798d5
add edge mask tests
jnke2016 May 8, 2024
86fd201
fix style
jnke2016 May 8, 2024
9ca7f5e
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 8, 2024
aad7590
add mg implementation of edge triangle count
jnke2016 May 11, 2024
28149f7
add reference for mg edge triangle count
jnke2016 May 11, 2024
0e69382
add mg edge triangle count tests
jnke2016 May 12, 2024
f893d24
remove debug print and unused import
jnke2016 May 12, 2024
30f891a
add edge mask test
jnke2016 May 12, 2024
be7ed1a
update 'mg_graph_to_sg_graph' to support 'edge_ids'
jnke2016 May 12, 2024
e705eca
add fixme
jnke2016 May 12, 2024
2453a6f
add doxygen documentation
jnke2016 May 12, 2024
e69f862
explicitly provide template parameter types
jnke2016 May 12, 2024
2bb9cba
rename variable
jnke2016 May 12, 2024
6a02f03
remove unnecessary sort
jnke2016 May 12, 2024
17017ec
round with the raft util function
jnke2016 May 12, 2024
13501fe
update fixme
jnke2016 May 12, 2024
e5a0f2d
rename variable
jnke2016 May 12, 2024
ca30c84
fix style
jnke2016 May 12, 2024
ba48f90
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 12, 2024
50231b6
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 12, 2024
b5d069a
fix typo
jnke2016 May 12, 2024
5a03431
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 12, 2024
8ca19cd
fix improper cast
jnke2016 May 14, 2024
0ca2953
remove temporary variable
jnke2016 May 14, 2024
56118f3
remove weights test
jnke2016 May 14, 2024
3463723
add edge mask test for rmat benchmark
jnke2016 May 14, 2024
f047a41
update mg tests
jnke2016 May 14, 2024
52bc273
fix style
jnke2016 May 14, 2024
02e15e4
update branch
jnke2016 May 14, 2024
2030ed8
fix style
jnke2016 May 14, 2024
3385690
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 14, 2024
1c4ee11
update tests
jnke2016 May 14, 2024
5b1c248
fix style
jnke2016 May 14, 2024
b8e21c3
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 14, 2024
fefddc5
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 14, 2024
9e9a198
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 14, 2024
0ab7906
update fixme
jnke2016 May 16, 2024
6439274
Merge remote-tracking branch 'upstream/branch-24.06_optimize-k-truss'…
jnke2016 May 16, 2024
a3e041e
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 16, 2024
d4217b2
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 21, 2024
1c175dc
fix typo and function call
jnke2016 May 22, 2024
095d561
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
rlratzel May 24, 2024
2408a95
Fixes style.
rlratzel May 24, 2024
03a2790
fix style
jnke2016 May 24, 2024
cf39539
Merge remote-tracking branch 'upstream/branch-24.06' into branch-24.0…
jnke2016 May 24, 2024
a62ad7a
Merge remote-tracking branch 'upstream/branch-24.06_stable-edge_trian…
jnke2016 May 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpp/include/cugraph/algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,10 @@ void triangle_count(raft::handle_t const& handle,
raft::device_span<edge_t> counts,
bool do_expensive_check = false);

template <typename vertex_t, typename edge_t, bool multi_gpu>
jnke2016 marked this conversation as resolved.
Show resolved Hide resolved
rmm::device_uvector<edge_t> edge_triangle_count(
jnke2016 marked this conversation as resolved.
Show resolved Hide resolved
raft::handle_t const& handle, graph_view_t<vertex_t, edge_t, false, multi_gpu> const& graph_view);

/*
* @brief Compute K-Truss.
*
Expand Down
154 changes: 89 additions & 65 deletions cpp/src/community/edge_triangle_count_impl.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ namespace detail {

template <typename vertex_t, typename edge_t, typename EdgeIterator>
struct update_edges_p_r_q_r_num_triangles {
size_t num_edges{}; // rename to num_edges
size_t num_edges{};
const edge_t edge_first_or_second{};
size_t chunk_start{};
raft::device_span<size_t const> intersection_offsets{};
raft::device_span<vertex_t const> intersection_indices{};
raft::device_span<edge_t> num_triangles{};
Expand All @@ -48,28 +49,22 @@ struct update_edges_p_r_q_r_num_triangles {
thrust::seq, intersection_offsets.begin() + 1, intersection_offsets.end(), i);
auto idx = thrust::distance(intersection_offsets.begin() + 1, itr);
if (edge_first_or_second == 0) {
auto p_r_pair =
thrust::make_tuple(thrust::get<0>(*(edge_first + idx)), intersection_indices[i]);
auto p_r_pair = thrust::make_tuple(thrust::get<0>(*(edge_first + chunk_start + idx)),
intersection_indices[i]);

// Find its position in 'edges'
auto itr_p_r_p_q =
thrust::lower_bound(thrust::seq,
edge_first,
edge_first + num_edges, // pass the number of vertex pairs
p_r_pair);
thrust::lower_bound(thrust::seq, edge_first, edge_first + num_edges, p_r_pair);

assert(*itr_p_r_p_q == p_r_pair);
idx = thrust::distance(edge_first, itr_p_r_p_q);
} else {
auto p_r_pair =
thrust::make_tuple(thrust::get<1>(*(edge_first + idx)), intersection_indices[i]);
auto p_r_pair = thrust::make_tuple(thrust::get<1>(*(edge_first + chunk_start + idx)),
intersection_indices[i]);

// Find its position in 'edges'
auto itr_p_r_p_q =
thrust::lower_bound(thrust::seq,
edge_first,
edge_first + num_edges, // pass the number of vertex pairs
p_r_pair);
thrust::lower_bound(thrust::seq, edge_first, edge_first + num_edges, p_r_pair);
assert(*itr_p_r_p_q == p_r_pair);
idx = thrust::distance(edge_first, itr_p_r_p_q);
}
Expand All @@ -81,74 +76,103 @@ struct update_edges_p_r_q_r_num_triangles {
template <typename vertex_t, typename edge_t, bool store_transposed, bool multi_gpu>
std::enable_if_t<!multi_gpu, rmm::device_uvector<edge_t>> edge_triangle_count_impl(
raft::handle_t const& handle,
graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu> const& graph_view,
raft::device_span<vertex_t> edgelist_srcs,
raft::device_span<vertex_t> edgelist_dsts)
graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu> const& graph_view)
{
using weight_t = float;
rmm::device_uvector<vertex_t> edgelist_srcs(0, handle.get_stream());
rmm::device_uvector<vertex_t> edgelist_dsts(0, handle.get_stream());
std::tie(edgelist_srcs, edgelist_dsts, std::ignore, std::ignore) = decompress_to_edgelist(
handle,
graph_view,
std::optional<edge_property_view_t<edge_t, weight_t const*>>{std::nullopt},
std::optional<edge_property_view_t<edge_t, edge_t const*>>{std::nullopt},
std::optional<raft::device_span<vertex_t const>>(std::nullopt));
jnke2016 marked this conversation as resolved.
Show resolved Hide resolved

auto edge_first = thrust::make_zip_iterator(edgelist_srcs.begin(), edgelist_dsts.begin());

thrust::sort(handle.get_thrust_policy(), edge_first, edge_first + edgelist_srcs.size());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of sort here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. We no longer need this as we do not pass an edgelist to edge_triangle_count. In fact when we decompress the edges from the graph, they are already sorted.


// FIXME: Perform 'nbr_intersection' in chunks to reduce peak memory.
auto [intersection_offsets, intersection_indices] =
detail::nbr_intersection(handle,
graph_view,
cugraph::edge_dummy_property_t{}.view(),
edge_first,
edge_first + edgelist_srcs.size(),
std::array<bool, 2>{true, true},
false /*FIXME: pass 'do_expensive_check' as argument*/);
size_t approx_edges_to_intersect_per_iteration =
static_cast<size_t>(handle.get_device_properties().multiProcessorCount) * (1 << 17);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't approximate, right? (I mean except for the last chunk). This approx_ naming convention is used when we are dealing with the CSR data structure and # edges should need to be aligned with the CSR offset array boundaries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean except for the last chunk

Ya or if it is bigger than the number of edges. But I agree it doesn't align with the intended context (CSR data structure). I renamed it to edges_to_intersect_per_iteration


auto num_chunks = ((edgelist_srcs.size() % approx_edges_to_intersect_per_iteration) == 0)
? (edgelist_srcs.size() / approx_edges_to_intersect_per_iteration)
: (edgelist_srcs.size() / approx_edges_to_intersect_per_iteration) + 1;
jnke2016 marked this conversation as resolved.
Show resolved Hide resolved
size_t prev_chunk_size = 0;
auto num_edges = edgelist_srcs.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

num_remaining_edges to be clearer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And prev_chunk_size = edgelist_srcs.size() - num_remaining_edges, so redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

num_remaining_edges to be clearer?

Done

And prev_chunk_size = edgelist_srcs.size() - num_remaining_edges, so redundant

Can you be more clear here?

rmm::device_uvector<edge_t> num_triangles(edgelist_srcs.size(), handle.get_stream());

// Update the number of triangles of each (p, q) edges by looking at their intersection
// size
thrust::adjacent_difference(handle.get_thrust_policy(),
intersection_offsets.begin() + 1,
intersection_offsets.end(),
num_triangles.begin());

// Given intersection offsets and indices that are used to update the number of
// triangles of (p, q) edges where `r`s are the intersection indices, update
// the number of triangles of the pairs (p, r) and (q, r).

thrust::for_each(
handle.get_thrust_policy(),
thrust::make_counting_iterator<edge_t>(0),
thrust::make_counting_iterator<edge_t>(intersection_indices.size()),
update_edges_p_r_q_r_num_triangles<vertex_t, edge_t, decltype(edge_first)>{
edgelist_srcs.size(),
0,
raft::device_span<size_t const>(intersection_offsets.data(), intersection_offsets.size()),
raft::device_span<vertex_t const>(intersection_indices.data(), intersection_indices.size()),
raft::device_span<edge_t>(num_triangles.data(), num_triangles.size()),
edge_first});

thrust::for_each(
handle.get_thrust_policy(),
thrust::make_counting_iterator<edge_t>(0),
thrust::make_counting_iterator<edge_t>(intersection_indices.size()),
update_edges_p_r_q_r_num_triangles<vertex_t, edge_t, decltype(edge_first)>{
edgelist_srcs.size(),
1,
raft::device_span<size_t const>(intersection_offsets.data(), intersection_offsets.size()),
raft::device_span<vertex_t const>(intersection_indices.data(), intersection_indices.size()),
raft::device_span<edge_t>(num_triangles.data(), num_triangles.size()),
edge_first});
// Need to ensure that the vector has its values initialized to 0 before incrementing
thrust::fill(handle.get_thrust_policy(), num_triangles.begin(), num_triangles.end(), 0);

for (size_t i = 0; i < num_chunks; ++i) {
auto chunk_size = std::min(approx_edges_to_intersect_per_iteration, num_edges);
num_edges -= chunk_size;
// Perform 'nbr_intersection' in chunks to reduce peak memory.
auto [intersection_offsets, intersection_indices] =
detail::nbr_intersection(handle,
graph_view,
cugraph::edge_dummy_property_t{}.view(),
edge_first + prev_chunk_size,
edge_first + prev_chunk_size + chunk_size,
std::array<bool, 2>{true, true},
false /*FIXME: pass 'do_expensive_check' as argument*/);

// Update the number of triangles of each (p, q) edges by looking at their intersection
// size
thrust::for_each(
handle.get_thrust_policy(),
thrust::make_counting_iterator<edge_t>(0),
thrust::make_counting_iterator<edge_t>(chunk_size),
[chunk_start = prev_chunk_size,
num_triangles = raft::device_span<edge_t>(num_triangles.data(), num_triangles.size()),
intersection_offsets = raft::device_span<size_t const>(
intersection_offsets.data(), intersection_offsets.size())] __device__(auto i) {
num_triangles[chunk_start + i] += (intersection_offsets[i + 1] - intersection_offsets[i]);
});

// Given intersection offsets and indices that are used to update the number of
// triangles of (p, q) edges where `r`s are the intersection indices, update
// the number of triangles of the pairs (p, r) and (q, r).
thrust::for_each(
handle.get_thrust_policy(),
thrust::make_counting_iterator<edge_t>(0),
thrust::make_counting_iterator<edge_t>(intersection_indices.size()),
update_edges_p_r_q_r_num_triangles<vertex_t, edge_t, decltype(edge_first)>{
edgelist_srcs.size(),
0,
prev_chunk_size,
raft::device_span<size_t const>(intersection_offsets.data(), intersection_offsets.size()),
raft::device_span<vertex_t const>(intersection_indices.data(), intersection_indices.size()),
raft::device_span<edge_t>(num_triangles.data(), num_triangles.size()),
edge_first});

thrust::for_each(
handle.get_thrust_policy(),
thrust::make_counting_iterator<edge_t>(0),
thrust::make_counting_iterator<edge_t>(intersection_indices.size()),
update_edges_p_r_q_r_num_triangles<vertex_t, edge_t, decltype(edge_first)>{
edgelist_srcs.size(),
1,
prev_chunk_size,
raft::device_span<size_t const>(intersection_offsets.data(), intersection_offsets.size()),
raft::device_span<vertex_t const>(intersection_indices.data(), intersection_indices.size()),
raft::device_span<edge_t>(num_triangles.data(), num_triangles.size()),
edge_first});

prev_chunk_size += chunk_size;
}

return num_triangles;
}

} // namespace detail

template <typename vertex_t, typename edge_t, bool store_transposed, bool multi_gpu>
template <typename vertex_t, typename edge_t, bool multi_gpu>
rmm::device_uvector<edge_t> edge_triangle_count(
raft::handle_t const& handle,
graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu> const& graph_view,
raft::device_span<vertex_t> edgelist_srcs,
raft::device_span<vertex_t> edgelist_dsts)
raft::handle_t const& handle, graph_view_t<vertex_t, edge_t, false, multi_gpu> const& graph_view)
{
return detail::edge_triangle_count_impl(handle, graph_view, edgelist_srcs, edgelist_dsts);
return detail::edge_triangle_count_impl(handle, graph_view);
}

} // namespace cugraph
12 changes: 3 additions & 9 deletions cpp/src/community/edge_triangle_count_sg.cu
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,14 @@ namespace cugraph {
// SG instantiation
template rmm::device_uvector<int32_t> edge_triangle_count(
raft::handle_t const& handle,
cugraph::graph_view_t<int32_t, int32_t, false, false> const& graph_view,
raft::device_span<int32_t> edgelist_srcs,
raft::device_span<int32_t> edgelist_dsts);
cugraph::graph_view_t<int32_t, int32_t, false, false> const& graph_view);

template rmm::device_uvector<int64_t> edge_triangle_count(
raft::handle_t const& handle,
cugraph::graph_view_t<int32_t, int64_t, false, false> const& graph_view,
raft::device_span<int32_t> edgelist_srcs,
raft::device_span<int32_t> edgelist_dsts);
cugraph::graph_view_t<int32_t, int64_t, false, false> const& graph_view);

template rmm::device_uvector<int64_t> edge_triangle_count(
raft::handle_t const& handle,
cugraph::graph_view_t<int64_t, int64_t, false, false> const& graph_view,
raft::device_span<int64_t> edgelist_srcs,
raft::device_span<int64_t> edgelist_dsts);
cugraph::graph_view_t<int64_t, int64_t, false, false> const& graph_view);

} // namespace cugraph
Loading
Loading