Skip to content

Commit cd329c1

Browse files
committed
Flows: fix bottleneck from construction of identical net detection
1 parent 4186ef3 commit cd329c1

7 files changed

Lines changed: 61 additions & 31 deletions

File tree

mt-kahypar/partition/refinement/flows/flow_refinement_scheduler.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ HyperedgeWeight FlowRefinementScheduler<GraphAndGainTypes>::runFlowSearch(Partit
219219
auto start = std::chrono::high_resolution_clock::now();
220220
if ( sub_hg.numNodes() > 0 ) {
221221
auto partitioned_hg = utils::partitioned_hg_const_cast(phg);
222+
223+
if (_refiner[refiner_idx] == nullptr) {
224+
_refiner[refiner_idx] = constructFlowRefiner();
225+
}
222226
_refiner[refiner_idx]->initialize(partitioned_hg);
223227
_refiner[refiner_idx]->updateTimeLimit(time_limit);
224228
MoveSequence sequence = _refiner[refiner_idx]->refine(partitioned_hg, sub_hg, start);
@@ -370,13 +374,6 @@ void FlowRefinementScheduler<GraphAndGainTypes>::initializeImpl(mt_kahypar_parti
370374
phg.partWeight(i), _context.partition.max_part_weights[i]);
371375
}
372376

373-
// Initialize Refiners
374-
for (auto& refiner: _refiner) {
375-
if ( refiner == nullptr ) {
376-
refiner = constructFlowRefiner();
377-
}
378-
}
379-
380377
// Initialize Quotient Graph and Scheduler
381378
_stats.reset();
382379
utils::Timer& timer = utils::Utilities::instance().getTimer(_context.utility_id);

mt-kahypar/partition/refinement/flows/flow_refiner.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,18 @@ FlowProblem FlowRefiner<GraphAndGainTypes>::constructFlowHypergraph(const Partit
157157

158158
const bool sequential = _context.shared_memory.num_threads == _context.refinement.flows.num_parallel_searches;
159159
if ( sequential ) {
160-
flow_problem = _sequential_construction.constructFlowHypergraph(
160+
if ( _sequential_construction == nullptr ) {
161+
_sequential_construction = std::make_unique<SequentialConstruction<GraphAndGainTypes>>(
162+
_num_hyperedges, _flow_hg, _sequential_hfc, _context);
163+
}
164+
flow_problem = _sequential_construction->constructFlowHypergraph(
161165
phg, sub_hg, _block_0, _block_1, _whfc_to_node);
162166
} else {
163-
flow_problem = _parallel_construction.constructFlowHypergraph(
167+
if ( _parallel_construction == nullptr ) {
168+
_parallel_construction = std::make_unique<ParallelConstruction<GraphAndGainTypes>>(
169+
_num_hyperedges, _flow_hg, _parallel_hfc, _context);
170+
}
171+
flow_problem = _parallel_construction->constructFlowHypergraph(
164172
phg, sub_hg, _block_0, _block_1, _whfc_to_node);
165173
}
166174

mt-kahypar/partition/refinement/flows/flow_refiner.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
#pragma once
2929

30+
#include <memory>
31+
3032
#include <tbb/concurrent_vector.h>
3133

3234
#include "WHFC/algorithm/hyperflowcutter.h"
@@ -57,14 +59,15 @@ class FlowRefiner final : public IFlowRefiner {
5759
const Context& context) :
5860
_phg(nullptr),
5961
_context(context),
62+
_num_hyperedges(num_hyperedges),
6063
_block_0(kInvalidPartition),
6164
_block_1(kInvalidPartition),
6265
_flow_hg(),
6366
_sequential_hfc(_flow_hg, context.partition.seed),
6467
_parallel_hfc(_flow_hg, context.partition.seed),
6568
_whfc_to_node(),
66-
_sequential_construction(num_hyperedges, _flow_hg, _sequential_hfc, context),
67-
_parallel_construction(num_hyperedges, _flow_hg, _parallel_hfc, context) {
69+
_sequential_construction(nullptr),
70+
_parallel_construction(nullptr) {
6871
_sequential_hfc.find_most_balanced = _context.refinement.flows.find_most_balanced_cut;
6972
_sequential_hfc.timer.active = false;
7073
_sequential_hfc.forceSequential(true);
@@ -111,14 +114,15 @@ class FlowRefiner final : public IFlowRefiner {
111114
const Context& _context;
112115
using IFlowRefiner::_time_limit;
113116

117+
HyperedgeID _num_hyperedges;
114118
PartitionID _block_0;
115119
PartitionID _block_1;
116120
FlowHypergraphBuilder _flow_hg;
117121
whfc::HyperFlowCutter<whfc::SequentialPushRelabel> _sequential_hfc;
118122
whfc::HyperFlowCutter<whfc::ParallelPushRelabel> _parallel_hfc;
119123

120124
vec<HypernodeID> _whfc_to_node;
121-
SequentialConstruction<GraphAndGainTypes> _sequential_construction;
122-
ParallelConstruction<GraphAndGainTypes> _parallel_construction;
125+
std::unique_ptr<SequentialConstruction<GraphAndGainTypes>> _sequential_construction;
126+
std::unique_ptr<ParallelConstruction<GraphAndGainTypes>> _parallel_construction;
123127
};
124128
} // namespace mt_kahypar

mt-kahypar/partition/refinement/flows/parallel_construction.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,15 @@ template<typename GraphAndGainTypes>
4040
typename ParallelConstruction<GraphAndGainTypes>::TmpHyperedge
4141
ParallelConstruction<GraphAndGainTypes>::DynamicIdenticalNetDetection::get(const size_t he_hash,
4242
const vec<whfc::Node>& pins) {
43+
if constexpr (PartitionedHypergraph::is_graph) {
44+
// there can't be identical nets for graphs
45+
return TmpHyperedge { 0, std::numeric_limits<size_t>::max(), whfc::invalidHyperedge };
46+
}
47+
4348
const size_t bucket_idx = he_hash % _hash_buckets.size();
4449
if ( __atomic_load_n(&_hash_buckets[bucket_idx].threshold, __ATOMIC_RELAXED) == _threshold ) {
4550
// There exists already some hyperedges with the same hash
51+
_hash_buckets[bucket_idx].lock.lock();
4652
for ( const ThresholdHyperedge& tmp : _hash_buckets[bucket_idx].identical_nets ) {
4753
// Check if there is some hyperedge equal to he
4854
const TmpHyperedge& tmp_e = tmp.e;
@@ -57,28 +63,33 @@ ParallelConstruction<GraphAndGainTypes>::DynamicIdenticalNetDetection::get(const
5763
}
5864
}
5965
if ( is_identical ) {
66+
_hash_buckets[bucket_idx].lock.unlock();
6067
return tmp_e;
6168
}
6269
}
6370
}
71+
_hash_buckets[bucket_idx].lock.unlock();
6472
}
6573
return TmpHyperedge { 0, std::numeric_limits<size_t>::max(), whfc::invalidHyperedge };
6674
}
6775

6876
template<typename GraphAndGainTypes>
6977
void ParallelConstruction<GraphAndGainTypes>::DynamicIdenticalNetDetection::add(const TmpHyperedge& tmp_he) {
78+
if constexpr (PartitionedHypergraph::is_graph) {
79+
// there can't be identical nets for graphs
80+
return;
81+
}
82+
7083
const size_t bucket_idx = tmp_he.hash % _hash_buckets.size();
71-
uint32_t expected = __atomic_load_n(&_hash_buckets[bucket_idx].threshold, __ATOMIC_RELAXED);
72-
uint32_t desired = _threshold - 1;
73-
while ( __atomic_load_n(&_hash_buckets[bucket_idx].threshold, __ATOMIC_RELAXED) < _threshold ) {
74-
if ( expected < desired &&
75-
__atomic_compare_exchange(&_hash_buckets[bucket_idx].threshold,
76-
&expected, &desired, false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED) ) {
77-
_hash_buckets[bucket_idx].identical_nets.clear();
78-
__atomic_store_n(&_hash_buckets[bucket_idx].threshold, _threshold, __ATOMIC_RELAXED);
79-
}
84+
HashBucket& bucket = _hash_buckets[bucket_idx];
85+
bucket.lock.lock();
86+
const uint32_t current = __atomic_load_n(&bucket.threshold, __ATOMIC_RELAXED);
87+
if (current < _threshold) {
88+
bucket.identical_nets.clear();
89+
__atomic_store_n(&bucket.threshold, _threshold, __ATOMIC_RELAXED);
8090
}
81-
_hash_buckets[bucket_idx].identical_nets.push_back(ThresholdHyperedge { tmp_he, _threshold });
91+
bucket.identical_nets.push_back(ThresholdHyperedge { tmp_he, _threshold });
92+
bucket.lock.unlock();
8293
}
8394

8495
template<typename GraphAndGainTypes>

mt-kahypar/partition/refinement/flows/parallel_construction.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "WHFC/algorithm/hyperflowcutter.h"
3333
#include "WHFC/algorithm/parallel_push_relabel.h"
3434

35+
#include "mt-kahypar/parallel/atomic_wrapper.h"
3536
#include "mt-kahypar/partition/context.h"
3637
#include "mt-kahypar/datastructures/sparse_map.h"
3738
#include "mt-kahypar/datastructures/concurrent_flat_map.h"
@@ -74,8 +75,7 @@ class ParallelConstruction {
7475
const uint32_t threshold;
7576
};
7677

77-
using IdenticalNetVector = tbb::concurrent_vector<
78-
ThresholdHyperedge, parallel::zero_allocator<ThresholdHyperedge>>;
78+
using IdenticalNetVector = vec<ThresholdHyperedge>;
7979

8080
struct HashBucket {
8181
HashBucket() :
@@ -84,6 +84,7 @@ class ParallelConstruction {
8484

8585
IdenticalNetVector identical_nets;
8686
uint32_t threshold;
87+
SpinLock lock;
8788
};
8889

8990
public:
@@ -92,9 +93,11 @@ class ParallelConstruction {
9293
const Context& context) :
9394
_flow_hg(flow_hg),
9495
_hash_buckets(),
95-
_threshold(2) {
96-
_hash_buckets.resize(std::max(UL(1024), num_hyperedges /
97-
context.refinement.flows.num_parallel_searches));
96+
_threshold(1) {
97+
if constexpr (!PartitionedHypergraph::is_graph) {
98+
_hash_buckets.resize(std::max(UL(1024), num_hyperedges /
99+
std::max(UL(8), 2 * context.refinement.flows.num_parallel_searches)));
100+
}
98101
}
99102

100103
TmpHyperedge get(const size_t he_hash,
@@ -103,7 +106,7 @@ class ParallelConstruction {
103106
void add(const TmpHyperedge& tmp_he);
104107

105108
void reset() {
106-
_threshold += 2;
109+
_threshold++;
107110
}
108111

109112
private:

mt-kahypar/partition/refinement/flows/sequential_construction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ namespace mt_kahypar {
3737
template<typename GraphAndGainTypes>
3838
whfc::Hyperedge SequentialConstruction<GraphAndGainTypes>::DynamicIdenticalNetDetection::add_if_not_contained(
3939
const whfc::Hyperedge he, const size_t he_hash, const vec<whfc::Node>& pins) {
40+
if constexpr (PartitionedHypergraph::is_graph) {
41+
// there can't be identical nets for graphs
42+
return whfc::invalidHyperedge;
43+
}
44+
4045
const size_t bucket_idx = he_hash % _hash_buckets.size();
4146
if ( _hash_buckets[bucket_idx].threshold == _threshold ) {
4247
// There exists already some hyperedges with the same hash

mt-kahypar/partition/refinement/flows/sequential_construction.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ class SequentialConstruction {
8080
_flow_hg(flow_hg),
8181
_hash_buckets(),
8282
_threshold(1) {
83-
_hash_buckets.resize(std::max(UL(1024), num_hyperedges /
84-
context.refinement.flows.num_parallel_searches));
83+
if constexpr (!PartitionedHypergraph::is_graph) {
84+
_hash_buckets.resize(std::max(UL(1024), num_hyperedges /
85+
std::max(UL(8), 2 * context.refinement.flows.num_parallel_searches)));
86+
}
8587
}
8688

8789
/**

0 commit comments

Comments
 (0)