Skip to content

Commit

Permalink
refactor: remove template arguments from the DeltaPartitionedGraph to…
Browse files Browse the repository at this point in the history
… simplify FM setup
  • Loading branch information
DanielSeemaier committed Jul 30, 2024
1 parent e942b97 commit 8a5688e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 123 deletions.
97 changes: 12 additions & 85 deletions kaminpar-shm/datastructures/delta_partitioned_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,17 @@
#include "kaminpar-common/ranges.h"

namespace kaminpar::shm {
template <
// If false, block(NodeID) may only be called on nodes that were not moved.
bool allow_read_after_move = true,
// If false, store the block weight changes in a vector of size k, otherwise
// use a hash map.
bool compact_block_weight_delta = false>
class GenericDeltaPartitionedGraph : public GraphDelegate<Graph> {
class DeltaPartitionedGraph : public GraphDelegate<Graph> {
struct DeltaEntry {
NodeID node;
BlockID block;
};

public:
constexpr static bool kAllowsReadAfterMove = allow_read_after_move;

GenericDeltaPartitionedGraph(const PartitionedGraph *p_graph)
DeltaPartitionedGraph(const PartitionedGraph *p_graph)
: GraphDelegate<Graph>(&p_graph->graph()),
_p_graph(p_graph) {
if constexpr (!compact_block_weight_delta) {
_block_weights_delta.resize(_p_graph->k());
}
_block_weights_delta.resize(_p_graph->k());
}

[[nodiscard]] const PartitionedGraph &p_graph() const {
Expand All @@ -56,22 +46,8 @@ class GenericDeltaPartitionedGraph : public GraphDelegate<Graph> {
}

[[nodiscard]] inline BlockID block(const NodeID node) const {
if constexpr (allow_read_after_move) {
const auto *it = _partition_delta.get_if_contained(node);
return (it != _partition_delta.end()) ? *it : _p_graph->block(node);
} else {
KASSERT(
std::find_if(
_partition_delta.begin(),
_partition_delta.end(),
[&](const DeltaEntry &entry) { return entry.node == node; }
) == _partition_delta.end(),
"node " << node << " was moved, access illegal",
assert::heavy
);

return _p_graph->block(node);
}
const auto *it = _partition_delta.get_if_contained(node);
return (it != _partition_delta.end()) ? *it : _p_graph->block(node);
}

template <bool update_block_weight = true>
Expand All @@ -88,79 +64,30 @@ class GenericDeltaPartitionedGraph : public GraphDelegate<Graph> {
_block_weights_delta[new_block] += node_weight(node);
}

if constexpr (allow_read_after_move) {
_partition_delta[node] = new_block;
} else {
KASSERT(
std::find_if(
_partition_delta.begin(),
_partition_delta.end(),
[&](const DeltaEntry &entry) { return entry.node == node; }
) == _partition_delta.end(),
"node " << node << " already in delta",
assert::heavy
);

_partition_delta.push_back({node, new_block});
}
_partition_delta[node] = new_block;
}

[[nodiscard]] inline BlockWeight block_weight(const BlockID block) const {
BlockWeight delta = 0;

if constexpr (compact_block_weight_delta) {
const auto *it = _block_weights_delta.get_if_contained(block);
if (it != _block_weights_delta.end()) {
delta = *it;
}
} else {
delta = _block_weights_delta[block];
}

return _p_graph->block_weight(block) + delta;
return _p_graph->block_weight(block) + _block_weights_delta[block];
}

template <typename Lambda> void for_each(Lambda &&lambda) {
if constexpr (allow_read_after_move) {
_partition_delta.for_each(std::forward<Lambda>(lambda));
} else {
for (const auto &[moved_node, moved_to] : _partition_delta) {
lambda(moved_node, moved_to);
}
}
_partition_delta.for_each(std::forward<Lambda>(lambda));
}

std::size_t size() const {
[[nodiscard]] std::size_t size() const {
return _partition_delta.size();
}

void clear() {
if constexpr (compact_block_weight_delta) {
_block_weights_delta.clear();
} else {
std::fill(_block_weights_delta.begin(), _block_weights_delta.end(), 0);
}

std::fill(_block_weights_delta.begin(), _block_weights_delta.end(), 0);
_partition_delta.clear();
}

private:
const PartitionedGraph *_p_graph;

// Depending on the configuration, use a hash map to be memory efficient,
// otherwise store the block weight deltas in vector (i.e., O(P * k) memory).
std::conditional_t<
compact_block_weight_delta,
DynamicFlatMap<BlockID, BlockWeight>,
ScalableVector<BlockWeight>>
_block_weights_delta;

// If we need random access to the partition delta, use a hash map. Otherwise,
// we can just store the moves in a vector.
std::conditional_t<
allow_read_after_move,
DynamicFlatMap<NodeID, BlockID>,
ScalableVector<DeltaEntry>>
_partition_delta;
ScalableVector<BlockWeight> _block_weights_delta;
DynamicFlatMap<NodeID, BlockID> _partition_delta;
};
} // namespace kaminpar::shm
57 changes: 23 additions & 34 deletions kaminpar-shm/refinement/fm/fm_refiner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,24 @@ void GlobalStats::print() {
}
} // namespace fm

template <typename GainCache, typename DeltaPartitionedGraph>
FMRefiner<GainCache, DeltaPartitionedGraph>::FMRefiner(const Context &input_ctx)
template <typename GainCache>
FMRefiner<GainCache>::FMRefiner(const Context &input_ctx)
: _ctx(input_ctx),
_fm_ctx(input_ctx.refinement.kway_fm),
_uninitialized(true) {}

template <typename GainCache, typename DeltaPartitionedGraph>
FMRefiner<GainCache, DeltaPartitionedGraph>::~FMRefiner() = default;
template <typename GainCache> FMRefiner<GainCache>::~FMRefiner() = default;

template <typename GainCache, typename DeltaPartitionedGraph>
void FMRefiner<GainCache, DeltaPartitionedGraph>::initialize(const PartitionedGraph &) {
template <typename GainCache> void FMRefiner<GainCache>::initialize(const PartitionedGraph &) {
if (_uninitialized) {
SCOPED_HEAP_PROFILER("FM Allocation");
_shared = std::make_unique<fm::SharedData<GainCache>>(_ctx, _ctx.partition.n, _ctx.partition.k);
_uninitialized = false;
}
}

template <typename GainCache, typename DeltaPartitionedGraph>
bool FMRefiner<GainCache, DeltaPartitionedGraph>::refine(
PartitionedGraph &p_graph, const PartitionContext &p_ctx
) {
template <typename GainCache>
bool FMRefiner<GainCache>::refine(PartitionedGraph &p_graph, const PartitionContext &p_ctx) {
SCOPED_HEAP_PROFILER("FM");
SCOPED_TIMER("FM");

Expand All @@ -151,7 +147,7 @@ bool FMRefiner<GainCache, DeltaPartitionedGraph>::refine(
EdgeWeight total_expected_gain = 0;

// Create thread-local workers numbered 1..P
using Worker = LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>;
using Worker = LocalizedFMRefiner<GainCache>;
std::atomic<int> next_id = 0;
tbb::enumerable_thread_specific<std::unique_ptr<Worker>> localized_fm_refiner_ets([&] {
// It is important that worker IDs start at 1, otherwise the node
Expand Down Expand Up @@ -198,8 +194,7 @@ bool FMRefiner<GainCache, DeltaPartitionedGraph>::refine(
}
tbb::parallel_for<int>(0, _ctx.parallel.num_threads, [&](int) {
EdgeWeight &expected_gain = expected_gain_ets.local();
LocalizedFMRefiner<GainCache, DeltaPartitionedGraph> &localized_refiner =
*localized_fm_refiner_ets.local();
LocalizedFMRefiner<GainCache> &localized_refiner = *localized_fm_refiner_ets.local();

// The workers attempt to extract seed nodes from the border nodes
// that are still available, continuing this process until there are
Expand Down Expand Up @@ -251,8 +246,8 @@ bool FMRefiner<GainCache, DeltaPartitionedGraph>::refine(
return false;
}

template <typename GainCache, typename DeltaPartitionedGraph>
LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::LocalizedFMRefiner(
template <typename GainCache>
LocalizedFMRefiner<GainCache>::LocalizedFMRefiner(
const int id,
const PartitionContext &p_ctx,
const KwayFMRefinementContext &fm_ctx,
Expand All @@ -274,25 +269,21 @@ LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::LocalizedFMRefiner(
}
}

template <typename GainCache, typename DeltaPartitionedGraph>
void LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::enable_move_recording() {
template <typename GainCache> void LocalizedFMRefiner<GainCache>::enable_move_recording() {
_record_applied_moves = true;
}

template <typename GainCache, typename DeltaPartitionedGraph>
const std::vector<fm::AppliedMove> &
LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::last_batch_moves() {
template <typename GainCache>
const std::vector<fm::AppliedMove> &LocalizedFMRefiner<GainCache>::last_batch_moves() {
return _applied_moves;
}

template <typename GainCache, typename DeltaPartitionedGraph>
const std::vector<NodeID> &
LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::last_batch_seed_nodes() {
template <typename GainCache>
const std::vector<NodeID> &LocalizedFMRefiner<GainCache>::last_batch_seed_nodes() {
return _seed_nodes;
}

template <typename GainCache, typename DeltaPartitionedGraph>
EdgeWeight LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::run_batch() {
template <typename GainCache> EdgeWeight LocalizedFMRefiner<GainCache>::run_batch() {
using fm::NodeTracker;

_seed_nodes.clear();
Expand Down Expand Up @@ -462,8 +453,8 @@ EdgeWeight LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::run_batch() {
return best_total_gain;
}

template <typename GainCache, typename DeltaPartitionedGraph>
inline void LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::update_after_move(
template <typename GainCache>
inline void LocalizedFMRefiner<GainCache>::update_after_move(
const NodeID node, const NodeID moved_node, const BlockID moved_from, const BlockID moved_to
) {
const BlockID old_block = _p_graph.block(node);
Expand Down Expand Up @@ -510,8 +501,7 @@ inline void LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::update_after_m
}
}

template <typename GainCache, typename DeltaPartitionedGraph>
inline bool LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::update_block_pq() {
template <typename GainCache> inline bool LocalizedFMRefiner<GainCache>::update_block_pq() {
bool have_more_nodes = false;
for (const BlockID block : _p_graph.blocks()) {
if (!_node_pqs[block].empty()) {
Expand All @@ -525,9 +515,9 @@ inline bool LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::update_block_p
return have_more_nodes;
}

template <typename GainCache, typename DeltaPartitionedGraph>
template <typename GainCache>
template <typename GainCacheType, typename PartitionedGraphType>
inline void LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::insert_into_node_pq(
inline void LocalizedFMRefiner<GainCache>::insert_into_node_pq(
const PartitionedGraphType &p_graph, const GainCacheType &gain_cache, const NodeID u
) {
const BlockID block_u = p_graph.block(u);
Expand All @@ -538,10 +528,9 @@ inline void LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::insert_into_no
_node_pqs[block_u].push(u, gain);
}

template <typename GainCache, typename DeltaPartitionedGraph>
template <typename GainCache>
template <typename GainCacheType, typename PartitionedGraphType>
inline std::pair<BlockID, EdgeWeight>
LocalizedFMRefiner<GainCache, DeltaPartitionedGraph>::best_gain(
inline std::pair<BlockID, EdgeWeight> LocalizedFMRefiner<GainCache>::best_gain(
const PartitionedGraphType &p_graph, const GainCacheType &gain_cache, const NodeID u
) {
const BlockID from = p_graph.block(u);
Expand Down
6 changes: 2 additions & 4 deletions kaminpar-shm/refinement/fm/fm_refiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@ template <typename GainCache> struct SharedData {
};
} // namespace fm

template <typename GainCache, typename DeltaPartitionedGraph = GenericDeltaPartitionedGraph<>>
class FMRefiner : public Refiner {
template <typename GainCache> class FMRefiner : public Refiner {
public:
FMRefiner(const Context &ctx);
~FMRefiner() override; // Required for the std::unique_ptr<> member.
Expand All @@ -211,8 +210,7 @@ class FMRefiner : public Refiner {
std::unique_ptr<fm::SharedData<GainCache>> _shared;
};

template <typename GainCache, typename DeltaPartitionedGraph = GenericDeltaPartitionedGraph<>>
class LocalizedFMRefiner {
template <typename GainCache> class LocalizedFMRefiner {
public:
LocalizedFMRefiner(
int id,
Expand Down

0 comments on commit 8a5688e

Please sign in to comment.