awooter: (bad) router congestion heuristics

This commit is contained in:
Lofty 2022-12-03 21:07:07 +00:00
parent 1375277171
commit cbee9f1e5f
4 changed files with 86 additions and 45 deletions

View File

@ -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());

View File

@ -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 {

View File

@ -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;

View File

@ -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();