Skip to content

Commit

Permalink
feat(contraction): reuse the memory space of a clustering for the map…
Browse files Browse the repository at this point in the history
…ping
  • Loading branch information
dsalwasser committed Apr 26, 2024
1 parent 55495f9 commit 97ab058
Show file tree
Hide file tree
Showing 14 changed files with 86 additions and 102 deletions.
14 changes: 7 additions & 7 deletions kaminpar-shm/coarsening/cluster_coarsener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,9 @@ bool ClusteringCoarsener::coarsen() {
SCOPED_HEAP_PROFILER("Level", std::to_string(_hierarchy.size()));
SCOPED_TIMER("Level", std::to_string(_hierarchy.size()));

if (_clustering.size() < current().n()) {
SCOPED_HEAP_PROFILER("Allocation");
SCOPED_TIMER("Allocation");
_clustering.resize(current().n());
}
START_HEAP_PROFILER("Allocation");
RECORD("clustering") StaticArray<NodeID> clustering(current().n(), static_array::noinit);
STOP_HEAP_PROFILER();

const bool free_allocated_memory = !keep_allocated_memory();
const NodeWeight total_node_weight = current().total_node_weight();
Expand All @@ -47,13 +45,15 @@ bool ClusteringCoarsener::coarsen() {
compute_max_cluster_weight<NodeWeight>(_c_ctx, _p_ctx, prev_n, total_node_weight)
);
_clustering_algorithm->set_desired_cluster_count(0);
_clustering_algorithm->compute_clustering(_clustering, current(), free_allocated_memory);
_clustering_algorithm->compute_clustering(clustering, current(), free_allocated_memory);
STOP_TIMER();
STOP_HEAP_PROFILER();

START_HEAP_PROFILER("Contract graph");
auto coarsened = TIMED_SCOPE("Contract graph") {
return contract_clustering(current(), _clustering, _c_ctx.contraction, _contraction_m_ctx);
return contract_clustering(
current(), std::move(clustering), _c_ctx.contraction, _contraction_m_ctx
);
};
_hierarchy.push_back(std::move(coarsened));
STOP_HEAP_PROFILER();
Expand Down
1 change: 0 additions & 1 deletion kaminpar-shm/coarsening/cluster_coarsener.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ class ClusteringCoarsener : public Coarsener {
const Graph *_input_graph;
std::vector<std::unique_ptr<CoarseGraph>> _hierarchy;

StaticArray<NodeID> _clustering{};
std::unique_ptr<Clusterer> _clustering_algorithm;

contraction::MemoryContext _contraction_m_ctx{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,18 +277,18 @@ std::unique_ptr<CoarseGraph> contract_clustering_buffered(

std::unique_ptr<CoarseGraph> contract_clustering_buffered(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
) {
if (con_ctx.use_compact_mapping) {
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_buffered(graph, c_n, std::move(mapping), con_ctx, m_ctx);
});
} else {
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_buffered(graph, c_n, std::move(mapping), con_ctx, m_ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
namespace kaminpar::shm::contraction {
std::unique_ptr<CoarseGraph> contract_clustering_buffered(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
);
Expand Down
14 changes: 7 additions & 7 deletions kaminpar-shm/coarsening/contraction/cluster_contraction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ namespace kaminpar::shm {
using namespace contraction;

std::unique_ptr<CoarseGraph> contract_clustering(
const Graph &graph, StaticArray<NodeID> &clustering, const ContractionCoarseningContext &con_ctx
const Graph &graph, StaticArray<NodeID> clustering, const ContractionCoarseningContext &con_ctx
) {
MemoryContext m_ctx;
return contract_clustering(graph, clustering, con_ctx, m_ctx);
return contract_clustering(graph, std::move(clustering), con_ctx, m_ctx);
}

std::unique_ptr<CoarseGraph> contract_clustering(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
) {
switch (con_ctx.mode) {
case ContractionMode::BUFFERED:
return contract_clustering_buffered(graph, clustering, con_ctx, m_ctx);
return contract_clustering_buffered(graph, std::move(clustering), con_ctx, m_ctx);
case ContractionMode::BUFFERED_LEGACY:
return contract_clustering_buffered_legacy(graph, clustering, con_ctx, m_ctx);
return contract_clustering_buffered_legacy(graph, std::move(clustering), con_ctx, m_ctx);
case ContractionMode::UNBUFFERED:
return contract_clustering_unbuffered(graph, clustering, con_ctx, m_ctx);
return contract_clustering_unbuffered(graph, std::move(clustering), con_ctx, m_ctx);
case ContractionMode::UNBUFFERED_NAIVE:
return contract_clustering_unbuffered_naive(graph, clustering, con_ctx, m_ctx);
return contract_clustering_unbuffered_naive(graph, std::move(clustering), con_ctx, m_ctx);
}

__builtin_unreachable();
Expand Down
4 changes: 2 additions & 2 deletions kaminpar-shm/coarsening/contraction/cluster_contraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ struct MemoryContext {
} // namespace contraction

std::unique_ptr<CoarseGraph> contract_clustering(
const Graph &graph, StaticArray<NodeID> &clustering, const ContractionCoarseningContext &con_ctx
const Graph &graph, StaticArray<NodeID> clustering, const ContractionCoarseningContext &con_ctx
);

std::unique_ptr<CoarseGraph> contract_clustering(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
contraction::MemoryContext &m_ctx
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,40 @@ namespace kaminpar::shm::contraction {
void fill_leader_mapping(
const Graph &graph, const StaticArray<NodeID> &clustering, StaticArray<NodeID> &leader_mapping
) {
START_TIMER("Allocation");
if (leader_mapping.size() < graph.n()) {
leader_mapping.resize(graph.n());
}
STOP_TIMER();

RECORD("leader_mapping");
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", leader_mapping.size() * sizeof(NodeID));
TIMED_SCOPE("Allocation") {
if (leader_mapping.size() < graph.n()) {
RECORD("leader_mapping") leader_mapping.resize(graph.n(), static_array::noinit);
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", leader_mapping.size() * sizeof(NodeID));
}
};

START_TIMER("Preprocessing");
graph.pfor_nodes([&](const NodeID u) { leader_mapping[u] = 0; });
graph.pfor_nodes([&](const NodeID u) {
__atomic_store_n(&leader_mapping[clustering[u]], 1, __ATOMIC_RELAXED);
});
parallel::prefix_sum(
leader_mapping.begin(), leader_mapping.begin() + graph.n(), leader_mapping.begin()
);
STOP_TIMER();
TIMED_SCOPE("Preprocessing") {
graph.pfor_nodes([&](const NodeID u) { leader_mapping[u] = 0; });
graph.pfor_nodes([&](const NodeID u) {
__atomic_store_n(&leader_mapping[clustering[u]], 1, __ATOMIC_RELAXED);
});
parallel::prefix_sum(
leader_mapping.begin(), leader_mapping.begin() + graph.n(), leader_mapping.begin()
);
};
}

template <>
StaticArray<NodeID> compute_mapping(
const Graph &graph,
const StaticArray<NodeID> &clustering,
const StaticArray<NodeID> &leader_mapping
const Graph &graph, StaticArray<NodeID> clustering, const StaticArray<NodeID> &leader_mapping
) {
START_TIMER("Allocation");
RECORD("mapping") StaticArray<NodeID> mapping(graph.n());
STOP_TIMER();

START_TIMER("Preprocessing");
graph.pfor_nodes([&](const NodeID u) {
mapping[u] = __atomic_load_n(&leader_mapping[clustering[u]], __ATOMIC_RELAXED) - 1;
clustering[u] = __atomic_load_n(&leader_mapping[clustering[u]], __ATOMIC_RELAXED) - 1;
});
STOP_TIMER();

return mapping;
return std::move(clustering);
}

template <>
CompactStaticArray<NodeID> compute_mapping(
const Graph &graph,
const StaticArray<NodeID> &clustering,
const StaticArray<NodeID> &leader_mapping
const Graph &graph, StaticArray<NodeID> clustering, const StaticArray<NodeID> &leader_mapping
) {
const NodeID c_n = leader_mapping[graph.n() - 1];

Expand All @@ -83,25 +73,27 @@ CompactStaticArray<NodeID> compute_mapping(

template <template <typename> typename Mapping>
std::pair<NodeID, Mapping<NodeID>>
compute_mapping(const Graph &graph, StaticArray<NodeID> &clustering, MemoryContext &m_ctx) {
compute_mapping(const Graph &graph, StaticArray<NodeID> clustering, MemoryContext &m_ctx) {
SCOPED_HEAP_PROFILER("Compute mapping");

fill_leader_mapping(graph, clustering, m_ctx.leader_mapping);
Mapping<NodeID> mapping = compute_mapping<Mapping>(graph, clustering, m_ctx.leader_mapping);
Mapping<NodeID> mapping =
compute_mapping<Mapping>(graph, std::move(clustering), m_ctx.leader_mapping);
const NodeID c_n = m_ctx.leader_mapping[graph.n() - 1];

TIMED_SCOPE("Allocation") {
TIMED_SCOPE("Deallocation") {
m_ctx.leader_mapping.free();
clustering.free();
};

return {c_n, std::move(mapping)};
}

template std::pair<NodeID, StaticArray<NodeID>> compute_mapping<StaticArray>(
const Graph &graph, StaticArray<NodeID> &clustering, MemoryContext &m_ctx
const Graph &graph, StaticArray<NodeID> clustering, MemoryContext &m_ctx
);

template std::pair<NodeID, CompactStaticArray<NodeID>> compute_mapping<CompactStaticArray>(
const Graph &graph, StaticArray<NodeID> &clustering, MemoryContext &m_ctx
const Graph &graph, StaticArray<NodeID> clustering, MemoryContext &m_ctx
);

template <typename Mapping>
Expand All @@ -112,33 +104,32 @@ void fill_cluster_buckets(
StaticArray<NodeID> &buckets_index,
StaticArray<NodeID> &buckets
) {
START_TIMER("Allocation");
if (buckets.size() < graph.n()) {
buckets.resize(graph.n());
}
if (buckets_index.size() < c_n + 1) {
buckets_index.resize(c_n + 1);
}
STOP_TIMER();

RECORD("buckets");
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", buckets.size() * sizeof(NodeID));
SCOPED_HEAP_PROFILER("Fill cluster buckets");

RECORD("buckets_index");
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", buckets_index.size() * sizeof(NodeID));
TIMED_SCOPE("Allocation") {
if (buckets.size() < graph.n()) {
RECORD("buckets") buckets.resize(graph.n(), static_array::noinit);
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", buckets.size() * sizeof(NodeID));
}

if (buckets_index.size() < c_n + 1) {
RECORD("buckets_index") buckets_index.resize(c_n + 1, static_array::noinit);
RECORD_LOCAL_DATA_STRUCT("StaticArray<NodeID>", buckets_index.size() * sizeof(NodeID));
}
};

START_TIMER("Preprocessing");
tbb::parallel_for<NodeID>(0, c_n + 1, [&](const NodeID i) { buckets_index[i] = 0; });
graph.pfor_nodes([&](const NodeID u) {
__atomic_fetch_add(&buckets_index[mapping[u]], 1, __ATOMIC_RELAXED);
});
parallel::prefix_sum(
buckets_index.begin(), buckets_index.begin() + c_n + 1, buckets_index.begin()
);
graph.pfor_nodes([&](const NodeID u) {
buckets[__atomic_sub_fetch(&buckets_index[mapping[u]], 1, __ATOMIC_RELAXED)] = u;
});
STOP_TIMER();
TIMED_SCOPE("Preprocessing") {
tbb::parallel_for<NodeID>(0, c_n + 1, [&](const NodeID i) { buckets_index[i] = 0; });
graph.pfor_nodes([&](const NodeID u) {
__atomic_fetch_add(&buckets_index[mapping[u]], 1, __ATOMIC_RELAXED);
});
parallel::prefix_sum(
buckets_index.begin(), buckets_index.begin() + c_n + 1, buckets_index.begin()
);
graph.pfor_nodes([&](const NodeID u) {
buckets[__atomic_sub_fetch(&buckets_index[mapping[u]], 1, __ATOMIC_RELAXED)] = u;
});
};
}

template void fill_cluster_buckets(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,12 @@ void fill_leader_mapping(

template <template <typename> typename Mapping>
Mapping<NodeID> compute_mapping(
const Graph &graph,
const StaticArray<NodeID> &clustering,
const StaticArray<NodeID> &leader_mapping
const Graph &graph, StaticArray<NodeID> clustering, const StaticArray<NodeID> &leader_mapping
);

template <template <typename> typename Mapping>
std::pair<NodeID, Mapping<NodeID>>
compute_mapping(const Graph &graph, StaticArray<NodeID> &clustering, MemoryContext &m_ctx);
compute_mapping(const Graph &graph, StaticArray<NodeID> clustering, MemoryContext &m_ctx);

template <typename Mapping>
void fill_cluster_buckets(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,23 +168,22 @@ std::unique_ptr<CoarseGraph> contract_clustering_buffered_legacy(

std::unique_ptr<CoarseGraph> contract_clustering_buffered_legacy(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
) {
if (con_ctx.use_compact_mapping) {
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_buffered_legacy(graph, c_n, std::move(mapping), con_ctx, m_ctx);
});
} else {
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_buffered_legacy(graph, c_n, std::move(mapping), con_ctx, m_ctx);
});
}
}
} // namespace kaminpar::shm::contraction

Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
namespace kaminpar::shm::contraction {
std::unique_ptr<CoarseGraph> contract_clustering_buffered_legacy(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
);
}

Original file line number Diff line number Diff line change
Expand Up @@ -180,18 +180,18 @@ std::unique_ptr<CoarseGraph> contract_clustering_unbuffered_naive(

std::unique_ptr<CoarseGraph> contract_clustering_unbuffered_naive(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
) {
if (con_ctx.use_compact_mapping) {
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<CompactStaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_unbuffered_naive(graph, c_n, std::move(mapping), con_ctx, m_ctx);
});
} else {
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, clustering, m_ctx);
auto [c_n, mapping] = compute_mapping<StaticArray>(graph, std::move(clustering), m_ctx);
fill_cluster_buckets(c_n, graph, mapping, m_ctx.buckets_index, m_ctx.buckets);
return graph.reified([&](auto &graph) {
return contract_clustering_unbuffered_naive(graph, c_n, std::move(mapping), con_ctx, m_ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace kaminpar::shm::contraction {
std::unique_ptr<CoarseGraph> contract_clustering_unbuffered_naive(
const Graph &graph,
StaticArray<NodeID> &clustering,
StaticArray<NodeID> clustering,
const ContractionCoarseningContext &con_ctx,
MemoryContext &m_ctx
);
Expand Down
Loading

0 comments on commit 97ab058

Please sign in to comment.