Skip to content

Commit 6693bca

Browse files
committed
Refactor router heap to use heap approximation.
The heap approximation doesn't precisely follow the heap property, but offers an approximation that is sufficent for the router's purpose. This new data structure is faster to clear, faster during route time, and results in better router behavior because it provides some randomness on elements with costs within ~1%. Signed-off-by: Keith Rothman <[email protected]>
1 parent 771be2c commit 6693bca

File tree

4 files changed

+489
-337
lines changed

4 files changed

+489
-337
lines changed

vpr/src/route/bucket.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include "bucket.h"
2+
3+
std::vector<t_heap*> BucketItems::heap_items_;
4+
size_t BucketItems::alloced_items_ = 0;
5+
int BucketItems::num_heap_allocated_ = 0;
6+
t_heap* BucketItems::heap_free_head_ = nullptr;
7+
vtr::t_chunk BucketItems::heap_ch_;
8+
9+
void Bucket::init(const DeviceGrid& grid) {
10+
vtr::free(heap_);
11+
heap_ = nullptr;
12+
13+
heap_size_ = (grid.width() - 1) * (grid.height() - 1);
14+
heap_ = (t_heap**)vtr::malloc(heap_size_ * sizeof(t_heap*));
15+
memset(heap_, 0, heap_size_ * sizeof(t_heap*));
16+
17+
heap_head_ = std::numeric_limits<size_t>::max();
18+
heap_tail_ = 0;
19+
}
20+
21+
void Bucket::free() {
22+
vtr::free(heap_);
23+
heap_ = nullptr;
24+
}
25+
26+
void Bucket::expand(size_t required_number_of_buckets) {
27+
auto old_size = heap_size_;
28+
heap_size_ = required_number_of_buckets * 2;
29+
30+
heap_ = (t_heap**)vtr::realloc((void*)(heap_),
31+
heap_size_ * sizeof(t_heap*));
32+
std::fill(heap_ + old_size, heap_ + heap_size_, nullptr);
33+
}
34+
35+
void Bucket::verify() {
36+
for (size_t bucket = heap_head_; bucket <= heap_tail_; ++bucket) {
37+
for (t_heap* data = heap_[bucket]; data != nullptr;
38+
data = data->next_bucket) {
39+
VTR_ASSERT(data->cost > 0 && ((size_t)cost_to_int(data->cost)) == bucket);
40+
}
41+
}
42+
}
43+
44+
size_t Bucket::seed_ = 1231;
45+
t_heap** Bucket::heap_ = nullptr;
46+
size_t Bucket::heap_size_ = 0;
47+
size_t Bucket::heap_head_ = std::numeric_limits<size_t>::max();
48+
size_t Bucket::heap_tail_ = 0;
49+
50+
void Bucket::clear() {
51+
if (heap_head_ != std::numeric_limits<size_t>::max()) {
52+
std::fill(heap_ + heap_head_, heap_ + heap_tail_ + 1, nullptr);
53+
}
54+
heap_head_ = std::numeric_limits<size_t>::max();
55+
heap_tail_ = 0;
56+
}
57+
58+
void Bucket::push(t_heap* hptr) {
59+
float cost = hptr->cost;
60+
if (!std::isfinite(cost)) {
61+
return;
62+
}
63+
64+
//heap_::verify_extract_top();
65+
66+
// Which bucket should this go into?
67+
auto int_cost = cost_to_int(cost);
68+
69+
if (int_cost < 0) {
70+
VTR_LOG_WARN("Cost is negative? cost = %g\n", cost);
71+
int_cost = 0;
72+
}
73+
74+
size_t uint_cost = int_cost;
75+
76+
// Is that bucket allocated?
77+
if (uint_cost >= heap_size_) {
78+
// Not enough buckets!
79+
expand(uint_cost);
80+
}
81+
82+
// Insert into bucket
83+
auto* prev = heap_[uint_cost];
84+
hptr->next_bucket = prev;
85+
heap_[uint_cost] = hptr;
86+
87+
if (uint_cost < heap_head_) {
88+
heap_head_ = uint_cost;
89+
}
90+
if (uint_cost > heap_tail_) {
91+
heap_tail_ = uint_cost;
92+
}
93+
94+
//heap_::verify_extract_top();
95+
}
96+
97+
t_heap* Bucket::pop() {
98+
auto heap_head = heap_head_;
99+
auto heap_tail = heap_tail_;
100+
t_heap** heap = heap_;
101+
102+
// Check empty
103+
if (heap_head == std::numeric_limits<size_t>::max()) {
104+
return nullptr;
105+
}
106+
107+
// Find first non-empty bucket
108+
109+
// Randomly remove element
110+
size_t count = fast_rand() % 4;
111+
112+
t_heap* prev = nullptr;
113+
t_heap* next = heap[heap_head];
114+
for (size_t i = 0; i < count && next->next_bucket != nullptr; ++i) {
115+
prev = next;
116+
next = prev->next_bucket;
117+
}
118+
119+
if (prev == nullptr) {
120+
heap[heap_head] = next->next_bucket;
121+
} else {
122+
prev->next_bucket = next->next_bucket;
123+
}
124+
125+
// Update first non-empty bucket if bucket is now empty
126+
if (heap[heap_head] == nullptr) {
127+
heap_head += 1;
128+
while (heap_head <= heap_tail && heap[heap_head] == nullptr) {
129+
heap_head += 1;
130+
}
131+
132+
if (heap_head > heap_tail) {
133+
heap_head = std::numeric_limits<size_t>::max();
134+
}
135+
136+
heap_head_ = heap_head;
137+
}
138+
139+
return next;
140+
}
141+
142+
void Bucket::print() {
143+
for (size_t i = heap_head_; i < heap_tail_; ++i) {
144+
if (heap_[heap_head_] != nullptr) {
145+
VTR_LOG("B:%d ", i);
146+
for (auto* item = heap_[i]; item != nullptr; item = item->next_bucket) {
147+
VTR_LOG(" %e", item->cost);
148+
}
149+
}
150+
}
151+
VTR_LOG("\n");
152+
}

0 commit comments

Comments
 (0)