awooter: (bad) router congestion heuristics
This commit is contained in:
parent
1375277171
commit
cbee9f1e5f
@ -214,27 +214,30 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
|||||||
let progress = MultiProgress::new();
|
let progress = MultiProgress::new();
|
||||||
|
|
||||||
let partitions = [
|
let partitions = [
|
||||||
(Coord::new(0, 0), Coord::new(x_part + 1, y_part + 1), &ne),
|
(Coord::new(0, 0), Coord::new(x_part + 1, y_part + 1), &ne, "NE"),
|
||||||
(
|
(
|
||||||
Coord::new(x_part - 1, 0),
|
Coord::new(x_part - 1, 0),
|
||||||
Coord::new(ctx.grid_dim_x(), y_part + 1),
|
Coord::new(ctx.grid_dim_x(), y_part + 1),
|
||||||
&se,
|
&se,
|
||||||
|
"SE"
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Coord::new(x_part - 1, y_part - 1),
|
Coord::new(x_part - 1, y_part - 1),
|
||||||
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
|
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
|
||||||
&sw,
|
&sw,
|
||||||
|
"SW"
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Coord::new(0, y_part - 1),
|
Coord::new(0, y_part - 1),
|
||||||
Coord::new(x_part + 1, ctx.grid_dim_y()),
|
Coord::new(x_part + 1, ctx.grid_dim_y()),
|
||||||
&nw,
|
&nw,
|
||||||
|
"NW"
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
partitions.par_iter().for_each(|(box_ne, box_sw, arcs)| {
|
partitions.par_iter().for_each(|(box_ne, box_sw, arcs, id)| {
|
||||||
let mut router = route::Router::new(*box_ne, *box_sw);
|
let mut router = route::Router::new(*box_ne, *box_sw);
|
||||||
router.route(ctx, &nets, wires, arcs, &progress);
|
router.route(ctx, &nets, wires, arcs, &progress, id);
|
||||||
});
|
});
|
||||||
|
|
||||||
log_info!("Routing miscellaneous arcs\n");
|
log_info!("Routing miscellaneous arcs\n");
|
||||||
@ -242,7 +245,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
|||||||
Coord::new(0, 0),
|
Coord::new(0, 0),
|
||||||
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
|
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
|
||||||
);
|
);
|
||||||
router.route(ctx, &nets, wires, &special_arcs, &progress);
|
router.route(ctx, &nets, wires, &special_arcs, &progress, "MISC");
|
||||||
|
|
||||||
let time = format!("{:.2}", (Instant::now() - start).as_secs_f32());
|
let time = format!("{:.2}", (Instant::now() - start).as_secs_f32());
|
||||||
log_info!("Routing took {}s\n", time.bold());
|
log_info!("Routing took {}s\n", time.bold());
|
||||||
|
@ -356,7 +356,11 @@ extern "C-unwind" {
|
|||||||
fn npnr_context_get_pips_leak(ctx: *const Context, pips: *mut *mut PipId) -> u64;
|
fn npnr_context_get_pips_leak(ctx: *const Context, pips: *mut *mut PipId) -> u64;
|
||||||
fn npnr_context_get_pip_location(ctx: *const Context, pip: PipId) -> Loc;
|
fn npnr_context_get_pip_location(ctx: *const Context, pip: PipId) -> Loc;
|
||||||
fn npnr_context_get_pip_direction(ctx: *const Context, pip: PipId) -> Loc;
|
fn npnr_context_get_pip_direction(ctx: *const Context, pip: PipId) -> Loc;
|
||||||
fn npnr_context_check_pip_avail_for_net(ctx: *const Context, pip: PipId, net: *const NetInfo) -> bool;
|
fn npnr_context_check_pip_avail_for_net(
|
||||||
|
ctx: *const Context,
|
||||||
|
pip: PipId,
|
||||||
|
net: *const NetInfo,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
fn npnr_context_check(ctx: *const Context);
|
fn npnr_context_check(ctx: *const Context);
|
||||||
fn npnr_context_debug(ctx: *const Context) -> bool;
|
fn npnr_context_debug(ctx: *const Context) -> bool;
|
||||||
@ -446,7 +450,9 @@ impl<'a> Nets<'a> {
|
|||||||
let index = index_to_net.len() as i32;
|
let index = index_to_net.len() as i32;
|
||||||
index_to_net.push(name);
|
index_to_net.push(name);
|
||||||
net_to_index.insert(net, index);
|
net_to_index.insert(net, index);
|
||||||
unsafe { npnr_netinfo_udata_set(net, NetIndex(index)); }
|
unsafe {
|
||||||
|
npnr_netinfo_udata_set(net, NetIndex(index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Note: the contents of `names` and `nets_ptr` are now lost.
|
// Note: the contents of `names` and `nets_ptr` are now lost.
|
||||||
Self {
|
Self {
|
||||||
|
@ -307,7 +307,11 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
let sink_coords: Coord = sink_loc.into();
|
let sink_coords: Coord = sink_loc.into();
|
||||||
let sink_is_north = sink_coords.is_north_of(&partition_coords);
|
let sink_is_north = sink_coords.is_north_of(&partition_coords);
|
||||||
let sink_is_east = sink_coords.is_east_of(&partition_coords);
|
let sink_is_east = sink_coords.is_east_of(&partition_coords);
|
||||||
let name = ctx.name_of(nets.name_from_index(arc.net())).to_str().unwrap().to_string();
|
let name = ctx
|
||||||
|
.name_of(nets.name_from_index(arc.net()))
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
|
let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
|
||||||
if source_is_north == sink_is_north && source_is_east == sink_is_east {
|
if source_is_north == sink_is_north && source_is_east == sink_is_east {
|
||||||
let seg = source_coords.segment_from(&Coord::new(x, y));
|
let seg = source_coords.segment_from(&Coord::new(x, y));
|
||||||
@ -626,7 +630,7 @@ pub fn find_partition_point_and_sanity_check(
|
|||||||
y_finish: i32,
|
y_finish: i32,
|
||||||
) -> (i32, i32, Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
|
) -> (i32, i32, Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
|
||||||
let (x_part, y_part, ne, se, sw, nw) =
|
let (x_part, y_part, ne, se, sw, nw) =
|
||||||
find_partition_point(ctx, nets, arcs, pips, x_start, x_finish, y_start, y_finish);
|
find_partition_point(ctx, nets, arcs, pips, x_start, x_finish, y_start, y_finish);
|
||||||
|
|
||||||
let mut invalid_arcs_in_ne = 0;
|
let mut invalid_arcs_in_ne = 0;
|
||||||
let mut invalid_arcs_in_se = 0;
|
let mut invalid_arcs_in_se = 0;
|
||||||
|
@ -73,20 +73,21 @@ impl Arc {
|
|||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct QueuedWire {
|
struct QueuedWire {
|
||||||
cost: f32,
|
delay: f32,
|
||||||
|
congest: f32,
|
||||||
togo: f32,
|
togo: f32,
|
||||||
wire: npnr::WireId,
|
wire: npnr::WireId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueuedWire {
|
impl QueuedWire {
|
||||||
pub fn new(cost: f32, togo: f32, wire: npnr::WireId) -> Self {
|
pub fn new(delay: f32, congest: f32, togo: f32, wire: npnr::WireId) -> Self {
|
||||||
Self { cost, togo, wire }
|
Self { delay, congest, togo, wire }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for QueuedWire {
|
impl PartialEq for QueuedWire {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.cost == other.cost && self.togo == other.togo && self.wire == other.wire
|
self.delay == other.delay && self.congest == other.congest && self.togo == other.togo && self.wire == other.wire
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +95,8 @@ impl Eq for QueuedWire {}
|
|||||||
|
|
||||||
impl Ord for QueuedWire {
|
impl Ord for QueuedWire {
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
let me = self.cost + self.togo;
|
let me = (0.9 * self.delay) + (0.1 * self.congest) + self.togo;
|
||||||
let other = other.cost + other.togo;
|
let other = (0.9 * other.delay) + (0.1 * other.congest) + other.togo;
|
||||||
other.total_cmp(&me)
|
other.total_cmp(&me)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,13 +107,12 @@ impl PartialOrd for QueuedWire {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct PerNetData {
|
struct PerNetData {
|
||||||
wires: HashMap<WireId, (PipId, u32)>,
|
wires: HashMap<WireId, (PipId, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PerWireData {
|
struct PerWireData {
|
||||||
wire: WireId,
|
wire: WireId,
|
||||||
curr_cong: u32,
|
curr_cong: u32,
|
||||||
hist_cong: f32,
|
hist_cong: f32,
|
||||||
unavailable: bool,
|
unavailable: bool,
|
||||||
@ -130,6 +130,9 @@ pub struct Router {
|
|||||||
dirty_wires: Vec<u32>,
|
dirty_wires: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PRESSURE_FACTOR: u32 = 5;
|
||||||
|
const ACCUMULATED_OVERUSE_FACTOR: f32 = 5.0;
|
||||||
|
|
||||||
impl Router {
|
impl Router {
|
||||||
pub fn new(box_ne: partition::Coord, box_sw: partition::Coord) -> Self {
|
pub fn new(box_ne: partition::Coord, box_sw: partition::Coord) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -149,10 +152,12 @@ impl Router {
|
|||||||
wires: &[npnr::WireId],
|
wires: &[npnr::WireId],
|
||||||
arcs: &[Arc],
|
arcs: &[Arc],
|
||||||
progress: &MultiProgress,
|
progress: &MultiProgress,
|
||||||
|
id: &str,
|
||||||
) {
|
) {
|
||||||
log_info!("Setting up router...\n");
|
|
||||||
for _ in 0..nets.len() {
|
for _ in 0..nets.len() {
|
||||||
self.nets.push(PerNetData { wires: HashMap::new() });
|
self.nets.push(PerNetData {
|
||||||
|
wires: HashMap::new(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (idx, &wire) in wires.iter().enumerate() {
|
for (idx, &wire) in wires.iter().enumerate() {
|
||||||
@ -163,40 +168,56 @@ impl Router {
|
|||||||
unavailable: false,
|
unavailable: false,
|
||||||
reserved_net: None,
|
reserved_net: None,
|
||||||
pip_fwd: PipId::null(),
|
pip_fwd: PipId::null(),
|
||||||
visited_fwd: false
|
visited_fwd: false,
|
||||||
});
|
});
|
||||||
self.wire_to_idx.insert(wire, idx as u32);
|
self.wire_to_idx.insert(wire, idx as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
let progress = progress.add(ProgressBar::new(arcs.len() as u64));
|
loop {
|
||||||
progress.set_style(
|
let progress = progress.add(ProgressBar::new(arcs.len() as u64));
|
||||||
ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}")
|
progress.set_style(
|
||||||
.unwrap()
|
ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}")
|
||||||
.progress_chars("━╸ "),
|
.unwrap()
|
||||||
);
|
.progress_chars("━╸ "),
|
||||||
|
);
|
||||||
|
|
||||||
for arc in arcs {
|
for arc in arcs {
|
||||||
let net = unsafe { nets.net_from_index(arc.net).as_ref().unwrap() };
|
let net = unsafe { nets.net_from_index(arc.net).as_ref().unwrap() };
|
||||||
let name = ctx
|
let name = ctx
|
||||||
.name_of(nets.name_from_index(arc.net))
|
.name_of(nets.name_from_index(arc.net))
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.to_string();
|
|
||||||
|
|
||||||
if net.is_global() {
|
if net.is_global() {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.inc(1);
|
||||||
|
progress.set_message(format!("{} @ {}", id, name));
|
||||||
|
self.route_arc(ctx, nets, arc);
|
||||||
}
|
}
|
||||||
|
progress.finish_and_clear();
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message(name);
|
let mut overused = 0;
|
||||||
self.route_arc(ctx, nets, arc);
|
for wd in &mut self.flat_wires {
|
||||||
|
if wd.curr_cong > 1 {
|
||||||
|
overused += 1;
|
||||||
|
wd.hist_cong += (wd.curr_cong as f32) * ACCUMULATED_OVERUSE_FACTOR;
|
||||||
|
}
|
||||||
|
wd.curr_cong = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if overused == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.println(format!("{}: {} wires overused", id, overused));
|
||||||
}
|
}
|
||||||
progress.finish_and_clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route_arc(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arc: &Arc) {
|
fn route_arc(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arc: &Arc) {
|
||||||
let mut queue = BinaryHeap::new();
|
let mut queue = BinaryHeap::new();
|
||||||
queue.push(QueuedWire::new(0.0, 0.0, arc.source_wire));
|
queue.push(QueuedWire::new(0.0, 0.0, 0.0, arc.source_wire));
|
||||||
|
|
||||||
let mut found_sink = false;
|
let mut found_sink = false;
|
||||||
|
|
||||||
@ -272,11 +293,13 @@ impl Router {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let node_delay = ctx.pip_delay(pip) + ctx.wire_delay(wire) + ctx.delay_epsilon();
|
||||||
|
let delay = source.delay + node_delay;
|
||||||
|
let congest = source.congest + (node_delay + nwd.hist_cong) * (1.0 + (nwd.curr_cong * PRESSURE_FACTOR) as f32);
|
||||||
|
|
||||||
self.set_visited_fwd(sink, pip);
|
self.set_visited_fwd(sink, pip);
|
||||||
|
|
||||||
let delay =
|
let qw = QueuedWire::new(delay, congest, ctx.estimate_delay(wire, arc.sink_wire), wire);
|
||||||
source.cost + ctx.pip_delay(pip) + ctx.wire_delay(wire) + ctx.delay_epsilon();
|
|
||||||
let qw = QueuedWire::new(delay, ctx.estimate_delay(wire, arc.sink_wire), wire);
|
|
||||||
queue.push(qw);
|
queue.push(qw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,7 +316,12 @@ impl Router {
|
|||||||
let mut wire = *self.wire_to_idx.get(&arc.sink_wire).unwrap();
|
let mut wire = *self.wire_to_idx.get(&arc.sink_wire).unwrap();
|
||||||
while wire != source_wire {
|
while wire != source_wire {
|
||||||
if verbose {
|
if verbose {
|
||||||
println!("Wire: {}", ctx.name_of_wire(self.flat_wires[wire as usize].wire).to_str().unwrap());
|
println!(
|
||||||
|
"Wire: {}",
|
||||||
|
ctx.name_of_wire(self.flat_wires[wire as usize].wire)
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let pip = self.flat_wires[wire as usize].pip_fwd;
|
let pip = self.flat_wires[wire as usize].pip_fwd;
|
||||||
assert!(pip != PipId::null());
|
assert!(pip != PipId::null());
|
||||||
@ -328,7 +356,7 @@ impl Router {
|
|||||||
self.flat_wires[wire as usize].curr_cong += 1;
|
self.flat_wires[wire as usize].curr_cong += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_wires(&mut self) {
|
fn reset_wires(&mut self) {
|
||||||
for &wire in &self.dirty_wires {
|
for &wire in &self.dirty_wires {
|
||||||
self.flat_wires[wire as usize].pip_fwd = PipId::null();
|
self.flat_wires[wire as usize].pip_fwd = PipId::null();
|
||||||
|
Loading…
Reference in New Issue
Block a user