Skip to content

Commit

Permalink
test: Add benchmark with criterion, add benchmark job to test workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
vemonet committed Dec 23, 2023
1 parent 6c5b144 commit 79a15d7
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 1 deletion.
31 changes: 30 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ jobs:
rustup component add clippy rustfmt
- run: cargo fmt -- --check
- run: cargo clippy --all --all-targets --all-features
- run: cargo bench

test:
name: 🧪 Tests
Expand Down Expand Up @@ -53,3 +52,33 @@ jobs:
with:
fail_ci_if_error: false
token: ${{secrets.CODECOV_TOKEN}}

benchmark:
name: ⏱️ Benchmark
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- run: |
rustup update
rustup toolchain install nightly
rustup default nightly
rustup component add clippy rustfmt
- name: Run benchmarks
run: cargo bench

- name: Checkout previous commit
uses: actions/checkout@v4
with:
ref: ${{ github.event.before }}

- name: Run benchmarks on previous commit
run: cargo bench

- name: Save benchmark result of previous commit
uses: actions/upload-artifact@v4
with:
name: benchmark
path: target/criterion/
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@ serde = { version = "1.0", optional = true, features = ["derive"] }

[dev-dependencies]
serde_json = "1.0"
criterion = "0.5"


[features]
serde = ["dep:serde"]

[profile.release]
lto = true


[[bench]]
name = "criterion_benchmark"
harness = false
224 changes: 224 additions & 0 deletions benches/criterion_benchmark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use std::collections::HashMap;

fn generate_keys() -> Vec<String> {
let mut keys = Vec::new();
for i in 1..9 {
for j in 1..9 {
for k in 1..9 {
for l in 1..9 {
keys.push(format!("{}{}{}{}", i, j, k, l));
}
}
}
}
keys
}

fn trie_benchmark(c: &mut Criterion) {
c.bench_function("trie_match", |b| {
let mut t = ptrie::Trie::new();
t.insert(black_box("test".bytes()), black_box(String::from("test")));
b.iter(|| {
assert!(t.contains_key(black_box("test".bytes())));
});
});

c.bench_function("trie_mismatch", |b| {
let mut t = ptrie::Trie::new();
t.insert("test".bytes(), String::from("test"));
b.iter(|| {
assert!(!t.contains_key("tst".bytes()));
});
});

c.bench_function("trie_massive_match", |b| {
let mut t = ptrie::Trie::new();
let keys = generate_keys();
for key in &keys {
t.insert(key.bytes(), key.clone());
}
b.iter(|| {
for key in &keys {
assert!(t.contains_key(key.bytes()));
}
});
});

c.bench_function("trie_massive_mismatch_on_0", |b| {
let mut t = ptrie::Trie::new();
let mismatching = String::from("0999");
let keys = generate_keys();

for key in &keys {
t.insert(key.bytes(), key.clone());
}

b.iter(|| {
for _ in 0..keys.len() {
assert!(!t.contains_key(mismatching.bytes()));
}
});
});

c.bench_function("trie_massive_mismatch_on_1", |b| {
let mut t = ptrie::Trie::new();
let mismatching = String::from("9099");
let keys = generate_keys();

for key in &keys {
t.insert(key.bytes(), key.clone());
}

b.iter(|| {
for _ in 0..keys.len() {
assert!(!t.contains_key(mismatching.bytes()));
}
});
});

c.bench_function("trie_massive_mismatch_on_2", |b| {
let mut t = ptrie::Trie::new();
let mismatching = String::from("9909");
let keys = generate_keys();

for key in &keys {
t.insert(key.bytes(), key.clone());
}

b.iter(|| {
for _ in 0..keys.len() {
assert!(!t.contains_key(mismatching.bytes()));
}
});
});

c.bench_function("trie_massive_mismatch_on_3", |b| {
let mut t = ptrie::Trie::new();
let mismatching = String::from("9990");
let keys = generate_keys();
for key in &keys {
t.insert(key.bytes(), key.clone());
}
b.iter(|| {
for _ in 0..keys.len() {
assert!(!t.contains_key(mismatching.bytes()));
}
});
});

c.bench_function("trie_prefixes_match", |b| {
let mut t = ptrie::Trie::new();
let keys = generate_keys();
for key in &keys {
t.insert(key.bytes(), key.clone());
}
b.iter(|| {
for key in &keys {
assert!(!t.find_prefixes(key.bytes()).is_empty());
}
});
});

c.bench_function("trie_postfixes_match", |b| {
let mut t = ptrie::Trie::new();
let keys = generate_keys();
for key in &keys {
t.insert(key.bytes(), key.clone());
}
b.iter(|| {
for key in &keys {
assert!(!t.find_postfixes(key.bytes()).is_empty());
}
});
});

c.bench_function("trie_prefix_longest_match", |b| {
let mut t = ptrie::Trie::new();
let keys = generate_keys();
for key in &keys {
t.insert(key.bytes(), key.clone());
}
b.iter(|| {
for key in &keys {
assert!(t.find_longest_prefix(key.bytes()).is_some());
}
});
});
}

fn hashmap_benchmark(c: &mut Criterion) {
c.bench_function("hashmap_match", |b| {
let mut h = HashMap::new();
let key = String::from("test");

h.insert(key.clone(), true);

b.iter(|| {
h.get(&key);
});
});

c.bench_function("hashmap_mismatch", |b| {
let mut h = HashMap::new();
let key = String::from("test");
let notkey = String::from("tst");

h.insert(key, true);

b.iter(|| {
h.get(&notkey);
});
});

c.bench_function("hashmap_massive_match", |b| {
let mut h = HashMap::new();
let keys = generate_keys();

for key in &keys {
h.insert(key.clone(), key.clone());
}

b.iter(|| {
for key in &keys {
assert!(h.contains_key(key));
}
});
});

c.bench_function("hashmap_massive_mismatch_on_0", |b| {
let mut h = HashMap::new();
let mismatching = String::from("0999");
let keys = generate_keys();

for key in &keys {
h.insert(key.clone(), key.clone());
}

b.iter(|| {
for _ in 0..keys.len() {
assert!(!h.contains_key(&mismatching));
}
});
});

c.bench_function("hashmap_massive_mismatch_on_0_one_symbol_key", |b| {
let mut h = HashMap::new();
let mismatching = String::from("0");
let keys = generate_keys();

for key in &keys {
h.insert(key.clone(), key.clone());
}

b.iter(|| {
for _ in 0..keys.len() {
assert!(!h.contains_key(&mismatching));
}
});
});
}

criterion_group!(benches, trie_benchmark, hashmap_benchmark,);
criterion_main!(benches);
12 changes: 12 additions & 0 deletions tests/trie_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ mod tests {
assert!(!t.contains_key(data));
}

#[test]
fn find_prefixes() {
let mut trie = Trie::new();
trie.insert("abc".bytes(), "ABC");
trie.insert("abcd".bytes(), "ABCD");
trie.insert("abcde".bytes(), "ABCDE");
let prefixes = trie.find_prefixes("abcd".bytes());
assert_eq!(prefixes, vec!["ABC", "ABCD"]);
assert_eq!(trie.find_prefixes("efghij".bytes()), Vec::<&str>::new());
assert_eq!(trie.find_prefixes("abz".bytes()), Vec::<&str>::new());
}

#[test]
fn iterator() {
let mut t = Trie::new();
Expand Down

0 comments on commit 79a15d7

Please sign in to comment.