Skip to content

Commit

Permalink
⚡️ Swap xxh3 for ahash (vroom)
Browse files Browse the repository at this point in the history
🏎️ use faster hasher
  • Loading branch information
Philogy authored Mar 20, 2024
2 parents 97c6891 + ae67544 commit f5d4110
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 25 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
on:
push:
branches:
- main
pull_request:
branches: [main]

name: CI

jobs:
clippy:
name: "clippy"
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@clippy
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
key: "clippy"
- name: "clippy all"
run: cargo clippy --workspace --lib --examples --tests --benches --all-features
env:
RUSTFLAGS: -D warnings

build:
name: "build and fmt"
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: Swatinem/rust-cache@v2
with:
key: "buildfmt"
cache-on-failure: true

- name: "build nightly"
run: cargo build --workspace --all-features
env:
RUSTFLAGS: -D warnings

- name: "cargo fmt"
run: cargo fmt --all --check
23 changes: 21 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ahash = "0.8.11"
ariadne = "0.4.0"
chumsky = "0.9.3"
clap = { version = "4.5.1", features = ["derive"] }
Expand Down
2 changes: 2 additions & 0 deletions src/scheduling/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub fn get_actions<'a>(
let deepest_idx = total_stack_el.saturating_sub(17);

(deepest_idx..total_stack_el)
.into_iter()
.filter_map(move |i| {
(deepest_idx..total_stack_el).find_map(|j| {
if i != j && machine.stack[i] == machine.stack[j] {
Expand All @@ -38,6 +39,7 @@ pub fn get_actions<'a>(
.chain(unpoppable.clone().into_iter().map(Action::Unpop))
.chain(
(0..info.nodes.len())
.into_iter()
.filter_map(move |id| {
if machine.blocked_by[id] != Some(0) || unpoppable.contains(&id) {
return None;
Expand Down
28 changes: 16 additions & 12 deletions src/scheduling/astar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::TimeDelta;
use std::collections::{BinaryHeap, HashMap};
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::time::Instant;
use xxhash_rust::xxh3::{Xxh3, Xxh3Builder};

#[derive(Debug, Clone)]
pub struct SchedulingTracker {
Expand Down Expand Up @@ -132,17 +131,19 @@ pub struct Explored {
type ExploredMap = HashMap<u64, Explored, BuildHasherDefault<NoopHasher>>;
type ScheduleQueue = BinaryHeap<ScheduleNode>;

struct FastHasher(Xxh3);
struct FastHasher(ahash::AHasher);

impl FastHasher {
fn new() -> Self {
Self(Xxh3Builder::new().build())
Self(ahash::AHasher::default())
}

fn hash_one_off<T: Hash>(&mut self, value: &T) -> u64 {
let buf = &mut self.0 as *mut ahash::AHasher as *mut u64;
unsafe { *buf = 0 };

value.hash(&mut self.0);
let hash = self.0.finish();
self.0.reset();
hash
}
}
Expand All @@ -164,21 +165,21 @@ impl Hasher for NoopHasher {
}
}

pub trait AStarScheduler: Sized {
pub trait AStarScheduler: Sized + Sync + Send {
fn schedule(
mut self,
graph: &IRGraph,
max_stack_depth: usize,
) -> (Vec<Step>, SchedulingTracker) {
let mut tracker = SchedulingTracker::default();

let mut queue: ScheduleQueue = BinaryHeap::new();
let info = ScheduleInfo::from(graph);
let start = BackwardsMachine::new(
graph.output_ids.iter().rev().cloned().collect(),
graph.nodes.iter().map(|node| node.blocked_by).collect(),
);
let est_capacity = self.estimate_explored_map_size(info, &start, max_stack_depth);
let mut queue: ScheduleQueue = BinaryHeap::with_capacity(est_capacity);
let mut explored: ExploredMap =
HashMap::with_capacity_and_hasher(est_capacity, Default::default());

Expand Down Expand Up @@ -224,16 +225,18 @@ pub trait AStarScheduler: Sized {
}

// 2b. Not at the end so we explore all possible neighbours.
for action in get_actions(info, &node.state) {
//
queue.extend(get_actions(info, &node.state).filter_map(|action| {
let mut new_state = node.state.clone();
let mut steps = vec![];
let mut steps = Vec::with_capacity(30);
let at_end = new_state.apply(info, action, &mut steps).unwrap();
if new_state.stack.len() > max_stack_depth {
continue;
return None;
}
let new_cost = node.cost + steps.iter().map(|step| step.cost()).sum::<u32>();
tracker.total_explored += 1;
let new_state_hash = hasher.hash_one_off(&new_state);

let new_cost_better = match explored.get(&new_state_hash) {
Some(e) => new_cost < e.cost,
None => true,
Expand All @@ -249,14 +252,15 @@ pub trait AStarScheduler: Sized {
);
tracker.total_collisions += if out.is_some() { 1 } else { 0 };
let score = new_cost + self.estimate_remaining_cost(info, &new_state, new_cost);
queue.push(ScheduleNode {
return Some(ScheduleNode {
state: new_state,
cost: new_cost,
score,
at_end,
});
}
}
None
}));
}

panic!("TODO: Impossible to schedule within specified bounds (likely stack-too-deep).")
Expand All @@ -274,7 +278,7 @@ pub trait AStarScheduler: Sized {
}

fn estimate_remaining_cost(
&mut self,
&self,
_info: ScheduleInfo,
_state: &BackwardsMachine,
_cost: u32,
Expand Down
4 changes: 2 additions & 2 deletions src/scheduling/schedulers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub struct Dijkstra;

impl AStarScheduler for Dijkstra {
fn estimate_remaining_cost(
&mut self,
&self,
_info: ScheduleInfo,
_state: &BackwardsMachine,
_cost: u32,
Expand All @@ -25,7 +25,7 @@ impl Guessooor {

impl AStarScheduler for Guessooor {
fn estimate_remaining_cost(
&mut self,
&self,
_info: ScheduleInfo,
state: &BackwardsMachine,
_cost: u32,
Expand Down
3 changes: 2 additions & 1 deletion src/scheduling/swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ impl<'a, T: Eq> Swapper<'a, T> {
if last != &self.to[last_idx] {
let (swap_to_idx, _) = zip(self.from.iter(), self.to)
.enumerate()
.take(last_idx).find(|(_, (x, y))| x != y && *y == last)?;
.take(last_idx)
.find(|(_, (x, y))| x != y && *y == last)?;
return Some((swap_to_idx, true));
}

Expand Down
18 changes: 11 additions & 7 deletions src/transformer/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,7 @@ fn validate_expression(
fn validate_func(symbols: &Symbols, func: &Function) -> Vec<SemanticError> {
let mut errors = vec![];

let func_args: Vec<_> = func
.macro_args
.iter()
.chain(func.inputs.iter())
.collect();
let func_args: Vec<_> = func.macro_args.iter().chain(func.inputs.iter()).collect();

errors.extend(check_duplicate_identifiers("function argument", &func_args));

Expand Down Expand Up @@ -372,11 +368,19 @@ pub fn validate_and_get_symbols(nodes: Vec<Spanned<Ast>>) -> Result<Symbols, Vec
let (std_deps, std_ops) = get_standard_opcodes_and_deps();
for dep in std_deps {
if symbols
.insert(dep.into(), Spanned::new(Symbol::Dependency, 0..0)).is_some() { panic!("Duplicate symbol from std_lib") }
.insert(dep.into(), Spanned::new(Symbol::Dependency, 0..0))
.is_some()
{
panic!("Duplicate symbol from std_lib")
}
}
for op in &std_ops {
if symbols
.insert(op.ident.clone(), Spanned::new(Symbol::Op(op.clone()), 0..0)).is_some() { panic!("Duplicate symbol from std_lib") }
.insert(op.ident.clone(), Spanned::new(Symbol::Op(op.clone()), 0..0))
.is_some()
{
panic!("Duplicate symbol from std_lib")
}
}
for op in std_ops {
if let Some((other_ident, _)) = &op.other {
Expand Down
1 change: 0 additions & 1 deletion src/transformer/semantics.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@


0 comments on commit f5d4110

Please sign in to comment.