Skip to content

Commit 25bf00b

Browse files
litghostvaughnbetz
authored andcommitted
Add prune checking to both heap types.
Signed-off-by: Keith Rothman <[email protected]>
1 parent 22e69b1 commit 25bf00b

File tree

6 files changed

+232
-22
lines changed

6 files changed

+232
-22
lines changed

vpr/src/route/binary_heap.cpp

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ static size_t right(size_t i) { return (i << 1) + 1; }
99
BinaryHeap::BinaryHeap()
1010
: heap_(nullptr)
1111
, heap_size_(0)
12-
, heap_tail_(0) {}
12+
, heap_tail_(0)
13+
, max_index_(std::numeric_limits<size_t>::max())
14+
, prune_limit_(std::numeric_limits<size_t>::max()) {}
1315

1416
BinaryHeap::~BinaryHeap() {
1517
free_all_memory();
@@ -26,7 +28,7 @@ void BinaryHeap::free(t_heap* hptr) {
2628
// or realloc() must be eliminated from add_to_heap()
2729
// because there is no C++ equivalent.
2830
void BinaryHeap::init_heap(const DeviceGrid& grid) {
29-
ssize_t target_heap_size = (grid.width() - 1) * (grid.height() - 1);
31+
size_t target_heap_size = (grid.width() - 1) * (grid.height() - 1);
3032
if (heap_ == nullptr || heap_size_ < target_heap_size) {
3133
if (heap_ != nullptr) {
3234
// coverity[offset_free : Intentional]
@@ -45,6 +47,11 @@ void BinaryHeap::add_to_heap(t_heap* hptr) {
4547
// start with undefined hole
4648
++heap_tail_;
4749
sift_up(heap_tail_ - 1, hptr);
50+
51+
// If we have pruned, rebuild the heap now.
52+
if (check_prune_limit()) {
53+
build_heap();
54+
}
4855
}
4956

5057
bool BinaryHeap::is_empty_heap() const {
@@ -70,7 +77,7 @@ t_heap* BinaryHeap::get_heap_head() {
7077
hole = 1;
7178
child = 2;
7279
--heap_tail_;
73-
while ((int)child < heap_tail_) {
80+
while (child < heap_tail_) {
7481
if (heap_[child + 1]->cost < heap_[child]->cost)
7582
++child; // become right child
7683
heap_[hole] = heap_[child];
@@ -85,20 +92,20 @@ t_heap* BinaryHeap::get_heap_head() {
8592
}
8693

8794
void BinaryHeap::empty_heap() {
88-
for (int i = 1; i < heap_tail_; i++)
95+
for (size_t i = 1; i < heap_tail_; i++)
8996
free(heap_[i]);
9097

9198
heap_tail_ = 1;
9299
}
93100

94-
size_t BinaryHeap::size() const { return static_cast<size_t>(heap_tail_ - 1); } // heap[0] is not valid element
101+
size_t BinaryHeap::size() const { return heap_tail_ - 1; } // heap[0] is not valid element
95102

96103
// make a heap rooted at index hole by **sifting down** in O(lgn) time
97104
void BinaryHeap::sift_down(size_t hole) {
98105
t_heap* head{heap_[hole]};
99106
size_t child{left(hole)};
100-
while ((int)child < heap_tail_) {
101-
if ((int)child + 1 < heap_tail_ && heap_[child + 1]->cost < heap_[child]->cost)
107+
while (child < heap_tail_) {
108+
if (child + 1 < heap_tail_ && heap_[child + 1]->cost < heap_[child]->cost)
102109
++child;
103110
if (heap_[child]->cost < head->cost) {
104111
heap_[hole] = heap_[child];
@@ -118,6 +125,14 @@ void BinaryHeap::build_heap() {
118125
sift_down(i);
119126
}
120127

128+
void BinaryHeap::set_prune_limit(size_t max_index, size_t prune_limit) {
129+
if (prune_limit != std::numeric_limits<size_t>::max()) {
130+
VTR_ASSERT(max_index < prune_limit);
131+
}
132+
max_index_ = max_index;
133+
prune_limit_ = prune_limit;
134+
}
135+
121136
// O(lgn) sifting up to maintain heap property after insertion (should sift down when building heap)
122137
void BinaryHeap::sift_up(size_t leaf, t_heap* const node) {
123138
while ((leaf > 1) && (node->cost < heap_[parent(leaf)]->cost)) {
@@ -142,16 +157,18 @@ void BinaryHeap::push_back(t_heap* const hptr) {
142157
expand_heap_if_full();
143158
heap_[heap_tail_] = hptr;
144159
++heap_tail_;
160+
161+
check_prune_limit();
145162
}
146163

147164
bool BinaryHeap::is_valid() const {
148165
if (heap_ == nullptr) {
149166
return false;
150167
}
151168

152-
for (size_t i = 1; (int)i <= heap_tail_ >> 1; ++i) {
153-
if ((int)left(i) < heap_tail_ && heap_[left(i)]->cost < heap_[i]->cost) return false;
154-
if ((int)right(i) < heap_tail_ && heap_[right(i)]->cost < heap_[i]->cost) return false;
169+
for (size_t i = 1; i <= heap_tail_ >> 1; ++i) {
170+
if (left(i) < heap_tail_ && heap_[left(i)]->cost < heap_[i]->cost) return false;
171+
if (right(i) < heap_tail_ && heap_[right(i)]->cost < heap_[i]->cost) return false;
155172
}
156173
return true;
157174
}
@@ -166,7 +183,7 @@ void BinaryHeap::invalidate_heap_entries(int sink_node, int ipin_node) {
166183
* architectures.
167184
* */
168185

169-
for (int i = 1; i < heap_tail_; i++) {
186+
for (size_t i = 1; i < heap_tail_; i++) {
170187
if (heap_[i]->index == sink_node) {
171188
if (heap_[i]->prev_node() == ipin_node) {
172189
heap_[i]->index = OPEN; /* Invalid. */
@@ -188,3 +205,57 @@ void BinaryHeap::free_all_memory() {
188205

189206
storage_.free_all_memory();
190207
}
208+
209+
bool BinaryHeap::check_prune_limit() {
210+
if (heap_tail_ > prune_limit_) {
211+
prune_heap();
212+
return true;
213+
}
214+
215+
return false;
216+
}
217+
218+
void BinaryHeap::prune_heap() {
219+
VTR_ASSERT(max_index_ < prune_limit_);
220+
221+
std::vector<t_heap*> best_heap_item(max_index_, nullptr);
222+
223+
// Find the cheapest instance of each index and store it.
224+
for (size_t i = 1; i < heap_tail_; i++) {
225+
if (heap_[i] == nullptr) {
226+
continue;
227+
}
228+
229+
if (heap_[i]->index == OPEN) {
230+
free(heap_[i]);
231+
heap_[i] = nullptr;
232+
continue;
233+
}
234+
235+
VTR_ASSERT(static_cast<size_t>(heap_[i]->index) < max_index_);
236+
237+
if (best_heap_item[heap_[i]->index] == nullptr || best_heap_item[heap_[i]->index]->cost > heap_[i]->cost) {
238+
best_heap_item[heap_[i]->index] = heap_[i];
239+
}
240+
}
241+
242+
// Free unused nodes.
243+
for (size_t i = 1; i < heap_tail_; i++) {
244+
if (heap_[i] == nullptr) {
245+
continue;
246+
}
247+
248+
if (best_heap_item[heap_[i]->index] != heap_[i]) {
249+
free(heap_[i]);
250+
heap_[i] = nullptr;
251+
}
252+
}
253+
254+
heap_tail_ = 1;
255+
256+
for (size_t i = 0; i < max_index_; ++i) {
257+
if (best_heap_item[i] != nullptr) {
258+
heap_[heap_tail_++] = best_heap_item[i];
259+
}
260+
}
261+
}

vpr/src/route/binary_heap.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class BinaryHeap : public HeapInterface {
1919
void empty_heap() final;
2020
t_heap* get_heap_head() final;
2121
void build_heap() final;
22+
void set_prune_limit(size_t max_index, size_t prune_limit) final;
2223

2324
void invalidate_heap_entries(int sink_node, int ipin_node) final;
2425

@@ -29,11 +30,16 @@ class BinaryHeap : public HeapInterface {
2930
void sift_up(size_t leaf, t_heap* const node);
3031
void sift_down(size_t hole);
3132
void expand_heap_if_full();
33+
bool check_prune_limit();
34+
void prune_heap();
3235

3336
HeapStorage storage_;
34-
t_heap** heap_; /* Indexed from [1..heap_size] */
35-
int heap_size_; /* Number of slots in the heap array */
36-
int heap_tail_; /* Index of first unused slot in the heap array */
37+
t_heap** heap_; /* Indexed from [1..heap_size] */
38+
size_t heap_size_; /* Number of slots in the heap array */
39+
size_t heap_tail_; /* Index of first unused slot in the heap array */
40+
41+
size_t max_index_;
42+
size_t prune_limit_;
3743
};
3844

3945
#endif /* _BINARY_HEAP_H */

vpr/src/route/bucket.cpp

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <cmath>
44
#include "vtr_log.h"
5+
#include "vpr_error.h"
56

67
BucketItems::BucketItems() noexcept
78
: alloced_items_(0)
@@ -17,7 +18,10 @@ Bucket::Bucket() noexcept
1718
, heap_tail_(0)
1819
, conv_factor_(0.f)
1920
, min_cost_(0.f)
20-
, max_cost_(0.f) {}
21+
, max_cost_(0.f)
22+
, num_items_(0)
23+
, max_index_(std::numeric_limits<size_t>::max())
24+
, prune_limit_(std::numeric_limits<size_t>::max()) {}
2125

2226
Bucket::~Bucket() {
2327
free_all_memory();
@@ -33,6 +37,7 @@ void Bucket::init_heap(const DeviceGrid& grid) {
3337

3438
heap_head_ = std::numeric_limits<size_t>::max();
3539
heap_tail_ = 0;
40+
num_items_ = 0;
3641

3742
conv_factor_ = kDefaultConvFactor;
3843

@@ -60,7 +65,13 @@ void Bucket::verify() {
6065
for (size_t bucket = heap_head_; bucket <= heap_tail_; ++bucket) {
6166
for (BucketItem* data = heap_[bucket]; data != nullptr;
6267
data = data->next_bucket) {
63-
VTR_ASSERT(data->item.cost > 0 && ((size_t)cost_to_int(data->item.cost)) == bucket);
68+
VTR_ASSERT(data->item.cost >= 0);
69+
int bucket_idx = cost_to_int(data->item.cost);
70+
if (bucket_idx != static_cast<ssize_t>(bucket)) {
71+
VPR_FATAL_ERROR(VPR_ERROR_ROUTE,
72+
"Wrong bucket for cost %g bucket_idx %d bucket %zu conv_factor %g",
73+
data->item.cost, bucket_idx, bucket, conv_factor_);
74+
}
6475
}
6576
}
6677
}
@@ -73,11 +84,22 @@ void Bucket::empty_heap() {
7384
}
7485
heap_head_ = std::numeric_limits<size_t>::max();
7586
heap_tail_ = 0;
87+
num_items_ = 0;
7688

7789
// Quickly reset all items to being free'd
7890
items_.clear();
7991
}
8092

93+
float Bucket::rescale_func() const {
94+
return 50000.f / max_cost_ / std::max(1.f, 1000.f / (max_cost_ / min_cost_));
95+
}
96+
97+
void Bucket::check_conv_factor() const {
98+
VTR_ASSERT(cost_to_int(min_cost_) >= 0);
99+
VTR_ASSERT(cost_to_int(max_cost_) >= 0);
100+
VTR_ASSERT(cost_to_int(max_cost_) < 1000000);
101+
}
102+
81103
// Checks if the scaling factor for cost results in a reasonable
82104
// number of buckets based on the maximum cost value seen.
83105
//
@@ -113,11 +135,8 @@ void Bucket::check_scaling() {
113135
// maximum cost increases. The underlying assumption of this scaling
114136
// algorithm is that the maximum cost will not result in a poor
115137
// scaling factor such that all precision is lost.
116-
conv_factor_ = 50000.f / max_cost_ / std::max(1.f, 1000.f / (max_cost_ / min_cost_));
117-
118-
VTR_ASSERT(cost_to_int(min_cost_) >= 0);
119-
VTR_ASSERT(cost_to_int(max_cost_) >= 0);
120-
VTR_ASSERT(cost_to_int(max_cost_) < 1000000);
138+
conv_factor_ = rescale_func();
139+
check_conv_factor();
121140

122141
// Reheap after adjusting scaling.
123142
if (heap_head_ != std::numeric_limits<size_t>::max()) {
@@ -200,6 +219,11 @@ void Bucket::push_back(t_heap* hptr) {
200219
if (uint_cost > heap_tail_) {
201220
heap_tail_ = uint_cost;
202221
}
222+
223+
num_items_ += 1;
224+
if (num_items_ > prune_limit_) {
225+
prune_heap();
226+
}
203227
}
204228

205229
t_heap* Bucket::get_heap_head() {
@@ -245,6 +269,7 @@ t_heap* Bucket::get_heap_head() {
245269
}
246270

247271
outstanding_items_ += 1;
272+
num_items_ -= 1;
248273
return &next->item;
249274
}
250275

@@ -263,3 +288,69 @@ void Bucket::print() {
263288
}
264289
VTR_LOG("\n");
265290
}
291+
292+
void Bucket::set_prune_limit(size_t max_index, size_t prune_limit) {
293+
if (prune_limit != std::numeric_limits<size_t>::max()) {
294+
VTR_ASSERT(max_index < prune_limit);
295+
}
296+
max_index_ = max_index;
297+
prune_limit_ = prune_limit;
298+
}
299+
300+
void Bucket::prune_heap() {
301+
std::vector<BucketItem*> best_heap_item(max_index_, nullptr);
302+
303+
for (size_t bucket = heap_head_; bucket <= heap_tail_; ++bucket) {
304+
for (BucketItem* item = heap_[bucket]; item != nullptr; item = item->next_bucket) {
305+
VTR_ASSERT(static_cast<size_t>(item->item.index) < max_index_);
306+
if (best_heap_item[item->item.index] == nullptr || best_heap_item[item->item.index]->item.cost > item->item.cost) {
307+
best_heap_item[item->item.index] = item;
308+
}
309+
}
310+
}
311+
312+
min_cost_ = std::numeric_limits<float>::max();
313+
max_cost_ = std::numeric_limits<float>::min();
314+
for (size_t bucket = heap_head_; bucket <= heap_tail_; ++bucket) {
315+
BucketItem* item = heap_[bucket];
316+
while (item != nullptr) {
317+
BucketItem* next_item = item->next_bucket;
318+
319+
if (best_heap_item[item->item.index] != item) {
320+
// This item isn't the cheapest, return it to the free list.
321+
items_.free_item(item);
322+
} else {
323+
// Update min_cost_ and max_cost_
324+
if (min_cost_ > item->item.cost) {
325+
min_cost_ = item->item.cost;
326+
}
327+
if (max_cost_ < item->item.cost) {
328+
max_cost_ = item->item.cost;
329+
}
330+
}
331+
332+
item = next_item;
333+
}
334+
}
335+
336+
// Rescale heap after pruning.
337+
conv_factor_ = rescale_func();
338+
check_conv_factor();
339+
340+
std::fill(heap_, heap_ + heap_size_, nullptr);
341+
heap_head_ = std::numeric_limits<size_t>::max();
342+
heap_tail_ = 0;
343+
num_items_ = 0;
344+
345+
// Re-heap the pruned elements.
346+
for (BucketItem* item : best_heap_item) {
347+
if (item == nullptr) {
348+
continue;
349+
}
350+
351+
outstanding_items_ += 1;
352+
push_back(&item->item);
353+
}
354+
355+
verify();
356+
}

0 commit comments

Comments
 (0)