Skip to content

Update BinaryHeap to FourAryHeap #2627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cfd9afa
Added option to select D-arity, turn on/off use of a new heap_elem wh…
May 23, 2024
0db85d9
Merge branch 'verilog-to-routing:master' into improve_binary_heap
nedsels May 24, 2024
6038ff6
Wrote scripts to help running tests and profile results
May 28, 2024
3fde949
Wrote scripts to help running tests and profile results
May 28, 2024
51f78a8
Merge branch 'improve_binary_heap' of github.com:nedsels/vtr-verilog-…
May 28, 2024
817c833
Updated black version to 21.4b0 from 20.8b1 so that make env works
May 8, 2024
a21d763
Created final FourAryHeap implementation, but kept BinaryHeap as a in…
Jun 20, 2024
ebd8148
Created final FourAryHeap implementation, but kept BinaryHeap as a in…
Jun 20, 2024
a7f33f6
Merge branch 'improve_binary_heap' of github.com:nedsels/vtr-verilog-…
Jun 20, 2024
b68ce5f
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
Jun 21, 2024
89a5c88
Merge branch 'master' into improve_binary_heap
Jun 21, 2024
5176261
Removed .gitignore changes
Jun 21, 2024
da0018a
Removed .gitignore changes
Jun 21, 2024
7d869d2
Merge branch 'improve_binary_heap' of github.com:nedsels/vtr-verilog-…
Jun 21, 2024
9a5d3b1
Fixed bug in FourAryHeap::get_heap_head and make FourAryHeap default …
Jun 21, 2024
c58ca70
parent() is now static function
Jun 21, 2024
339fe8d
Revert "parent() is now static function"
Jun 21, 2024
bde3cae
Eliminated duplicate code in ShowRouterOpts()
Jun 24, 2024
679618a
Added Doxygen comments to HeapImplementation and its children (exclud…
Jun 24, 2024
d580ab1
Updated golden values
Jun 24, 2024
d56143b
Modified Doxygen comments on heaps
Jun 24, 2024
15fb108
Merge branch 'master' into improve_binary_heap
Jun 24, 2024
d51f91a
Updated more golden results
Jun 24, 2024
a2e2970
Fixed bug in FourAryHeap::smallest_child()
Jun 25, 2024
a054a14
Added regression test for BinaryHeap
Jun 25, 2024
51cd8d4
Added router heap to VPRINTERNALS API
Jun 25, 2024
d906ea8
Merge branch 'master' into improve_binary_heap
Jun 25, 2024
fc49189
Added more golden results
Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,4 @@ tags
.idea
cmake-build-debug
cmake-build-release
/.metadata/
/.metadata/
1 change: 1 addition & 0 deletions doc/src/api/vprinternals/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ VPR INTERNALS
vpr_ui
draw_files
vpr_noc
vpr_router
33 changes: 33 additions & 0 deletions doc/src/api/vprinternals/router_heap.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
==============
Router Heap
==============

t_heap
----------
.. doxygenstruct:: t_heap
:project: vpr
:members:

HeapInterface
----------
.. doxygenclass:: HeapInterface
:project: vpr
:members:

HeapStorage
----------
.. doxygenclass:: HeapStorage
:project: vpr
:members:

KAryHeap
----------
.. doxygenclass:: KAryHeap
:project: vpr
:members:

FourAryHeap
----------
.. doxygenclass:: FourAryHeap
:project: vpr
:members:
10 changes: 10 additions & 0 deletions doc/src/api/vprinternals/vpr_router.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. _router:

=======
VPR Router
=======

.. toctree::
:maxdepth: 1

router_heap
6 changes: 3 additions & 3 deletions utils/route_diag/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ static void do_one_route(const Netlist<>& net_list,
segment_inf,
is_flat);

ConnectionRouter<BinaryHeap> router(
device_ctx.grid,
*router_lookahead,
ConnectionRouter<FourAryHeap> router(
device_ctx.grid,
*router_lookahead,
device_ctx.rr_graph.rr_nodes(),
&device_ctx.rr_graph,
device_ctx.rr_rc_data,
Expand Down
443 changes: 185 additions & 258 deletions vpr/src/base/ShowSetup.cpp

Large diffs are not rendered by default.

11 changes: 8 additions & 3 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,8 @@ struct ParseRouterHeap {
ConvertedValue<e_heap_type> conv_value;
if (str == "binary")
conv_value.set_value(e_heap_type::BINARY_HEAP);
else if (str == "four_ary")
conv_value.set_value(e_heap_type::FOUR_ARY_HEAP);
else if (str == "bucket")
conv_value.set_value(e_heap_type::BUCKET_HEAP_APPROXIMATION);
else {
Expand All @@ -1075,6 +1077,8 @@ struct ParseRouterHeap {
ConvertedValue<std::string> conv_value;
if (val == e_heap_type::BINARY_HEAP)
conv_value.set_value("binary");
else if (val == e_heap_type::FOUR_ARY_HEAP)
conv_value.set_value("four_ary");
else {
VTR_ASSERT(val == e_heap_type::BUCKET_HEAP_APPROXIMATION);
conv_value.set_value("bucket");
Expand All @@ -1083,7 +1087,7 @@ struct ParseRouterHeap {
}

std::vector<std::string> default_choices() {
return {"binary", "bucket"};
return {"binary", "four_ary", "bucket"};
}
};

Expand Down Expand Up @@ -2648,11 +2652,12 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help(
"Controls what type of heap to use for timing driven router.\n"
" * binary: A binary heap is used.\n"
" * four_ary: A four_ary heap is used.\n"
" * bucket: A bucket heap approximation is used. The bucket heap\n"
" * is faster because it is only a heap approximation.\n"
" * Testing has shown the approximation results in\n"
" * similiar QoR with less CPU work.\n")
.default_value("binary")
" * similar QoR with less CPU work.\n")
.default_value("four_ary")
.show_in(argparse::ShowIn::HELP_ONLY);

route_timing_grp.add_argument(args.router_first_iteration_timing_report_file, "--router_first_iter_timing_report")
Expand Down
4 changes: 2 additions & 2 deletions vpr/src/base/read_route.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#include "route_common.h"
#include "route_tree.h"
#include "read_route.h"
#include "binary_heap.h"
#include "four_ary_heap.h"

#include "old_traceback.h"

Expand Down Expand Up @@ -129,7 +129,7 @@ bool read_route(const char* route_file, const t_router_opts& router_opts, bool v
fp.close();

/*Correctly set up the clb opins*/
BinaryHeap small_heap;
FourAryHeap small_heap;
small_heap.init_heap(device_ctx.grid);
if (!flat_router) {
reserve_locally_used_opins(&small_heap, router_opts.initial_pres_fac,
Expand Down
209 changes: 23 additions & 186 deletions vpr/src/route/binary_heap.cpp
Original file line number Diff line number Diff line change
@@ -1,57 +1,23 @@
#include "binary_heap.h"
#include "rr_graph_fwd.h"
#include "vtr_log.h"

static size_t parent(size_t i) { return i >> 1; }
// child indices of a heap
static size_t left(size_t i) { return i << 1; }
static size_t right(size_t i) { return (i << 1) + 1; }

BinaryHeap::BinaryHeap()
: heap_()
, heap_size_(0)
, heap_tail_(0)
, max_index_(std::numeric_limits<size_t>::max())
, prune_limit_(std::numeric_limits<size_t>::max()) {}

BinaryHeap::~BinaryHeap() {
free_all_memory();
}
static inline size_t left(size_t i) { return i << 1; }
static inline size_t right(size_t i) { return (i << 1) + 1; }

t_heap* BinaryHeap::alloc() {
return storage_.alloc();
}
void BinaryHeap::free(t_heap* hptr) {
storage_.free(hptr);
}
inline size_t BinaryHeap::parent(size_t i) const { return i >> 1; }

void BinaryHeap::init_heap(const DeviceGrid& grid) {
size_t target_heap_size = (grid.width() - 1) * (grid.height() - 1);
if (heap_.empty() || heap_size_ < target_heap_size) {
if (!heap_.empty()) {
// coverity[offset_free : Intentional]
heap_.clear();
}
heap_size_ = (grid.width() - 1) * (grid.height() - 1);
heap_.resize(heap_size_ + 1); /* heap_size_ + 1 because heap stores from [1..heap_size] */
bool BinaryHeap::is_valid() const {
if (heap_.empty()) {
return false;
}
heap_tail_ = 1;
}

void BinaryHeap::add_to_heap(t_heap* hptr) {
expand_heap_if_full();
// start with undefined hole
++heap_tail_;
sift_up(heap_tail_ - 1, hptr);

// If we have pruned, rebuild the heap now.
if (check_prune_limit()) {
build_heap();
for (size_t i = 1; i <= heap_tail_ >> 1; ++i) {
if (left(i) < heap_tail_ && heap_[left(i)].cost < heap_[i].cost) return false;
if (right(i) < heap_tail_ && heap_[right(i)].cost < heap_[i].cost) return false;
}
}

bool BinaryHeap::is_empty_heap() const {
return (bool)(heap_tail_ == 1);
return true;
}

t_heap* BinaryHeap::get_heap_head() {
Expand All @@ -68,173 +34,44 @@ t_heap* BinaryHeap::get_heap_head() {
return (nullptr);
}

cheapest = heap_[1];
cheapest = heap_[1].elem_ptr;

hole = 1;
child = 2;

--heap_tail_;

while (child < heap_tail_) {
if (heap_[child + 1]->cost < heap_[child]->cost)
if (heap_[child + 1].cost < heap_[child].cost)
++child; // become right child

heap_[hole] = heap_[child];
hole = child;
child = left(child);
}
sift_up(hole, heap_[heap_tail_]);

sift_up(hole, heap_[heap_tail_]);
} while (!cheapest->index.is_valid()); /* Get another one if invalid entry. */

return (cheapest);
}

void BinaryHeap::empty_heap() {
for (size_t i = 1; i < heap_tail_; i++)
free(heap_[i]);

heap_tail_ = 1;
}

size_t BinaryHeap::size() const { return heap_tail_ - 1; } // heap[0] is not valid element

// make a heap rooted at index hole by **sifting down** in O(lgn) time
void BinaryHeap::sift_down(size_t hole) {
t_heap* head{heap_[hole]};
heap_elem head{heap_[hole]};
size_t child{left(hole)};

while (child < heap_tail_) {
if (child + 1 < heap_tail_ && heap_[child + 1]->cost < heap_[child]->cost)
if (child + 1 < heap_tail_ && heap_[child + 1].cost < heap_[child].cost)
++child;
if (heap_[child]->cost < head->cost) {

if (heap_[child].cost < head.cost) {
heap_[hole] = heap_[child];
hole = child;
child = left(child);
} else
break;
}
heap_[hole] = head;
}

// runs in O(n) time by sifting down; the least work is done on the most elements: 1 swap for bottom layer, 2 swap for 2nd, ... lgn swap for top
// 1*(n/2) + 2*(n/4) + 3*(n/8) + ... + lgn*1 = 2n (sum of i/2^i)
void BinaryHeap::build_heap() {
// second half of heap are leaves
for (size_t i = heap_tail_ >> 1; i != 0; --i)
sift_down(i);
}

void BinaryHeap::set_prune_limit(size_t max_index, size_t prune_limit) {
if (prune_limit != std::numeric_limits<size_t>::max()) {
VTR_ASSERT(max_index < prune_limit);
}
max_index_ = max_index;
prune_limit_ = prune_limit;
}

// O(lgn) sifting up to maintain heap property after insertion (should sift down when building heap)
void BinaryHeap::sift_up(size_t leaf, t_heap* const node) {
while ((leaf > 1) && (node->cost < heap_[parent(leaf)]->cost)) {
// sift hole up
heap_[leaf] = heap_[parent(leaf)];
leaf = parent(leaf);
}
heap_[leaf] = node;
}

//expands heap by "realloc"
void BinaryHeap::expand_heap_if_full() {
if (heap_tail_ > heap_size_) { /* Heap is full */
heap_size_ *= 2;
heap_.resize(heap_size_ + 1);
}
}

// adds an element to the back of heap and expand if necessary, but does not maintain heap property
void BinaryHeap::push_back(t_heap* const hptr) {
expand_heap_if_full();
heap_[heap_tail_] = hptr;
++heap_tail_;

check_prune_limit();
}

bool BinaryHeap::is_valid() const {
if (heap_.empty()) {
return false;
}

for (size_t i = 1; i <= heap_tail_ >> 1; ++i) {
if (left(i) < heap_tail_ && heap_[left(i)]->cost < heap_[i]->cost) return false;
if (right(i) < heap_tail_ && heap_[right(i)]->cost < heap_[i]->cost) return false;
}
return true;
}

void BinaryHeap::free_all_memory() {
if (!heap_.empty()) {
empty_heap();

// coverity[offset_free : Intentional]
heap_.clear();
}

// heap_ = nullptr; /* Defensive coding: crash hard if I use these. */

storage_.free_all_memory();
}

bool BinaryHeap::check_prune_limit() {
if (heap_tail_ > prune_limit_) {
prune_heap();
return true;
}

return false;
}

void BinaryHeap::prune_heap() {
VTR_ASSERT(max_index_ < prune_limit_);

std::vector<t_heap*> best_heap_item(max_index_, nullptr);

// Find the cheapest instance of each index and store it.
for (size_t i = 1; i < heap_tail_; i++) {
if (heap_[i] == nullptr) {
continue;
}

if (!heap_[i]->index.is_valid()) {
free(heap_[i]);
heap_[i] = nullptr;
continue;
}

auto idx = size_t(heap_[i]->index);

VTR_ASSERT(idx < max_index_);

if (best_heap_item[idx] == nullptr || best_heap_item[idx]->cost > heap_[i]->cost) {
best_heap_item[idx] = heap_[i];
}
}

// Free unused nodes.
for (size_t i = 1; i < heap_tail_; i++) {
if (heap_[i] == nullptr) {
continue;
}

auto idx = size_t(heap_[i]->index);

if (best_heap_item[idx] != heap_[i]) {
free(heap_[i]);
heap_[i] = nullptr;
}
}

heap_tail_ = 1;

for (size_t i = 0; i < max_index_; ++i) {
if (best_heap_item[i] != nullptr) {
heap_[heap_tail_++] = best_heap_item[i];
}
}
}
heap_[hole] = head;
}
Loading