Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 1 addition & 17 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
name: CodSpeed Benchmarks

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

on:
push:
branches:
Expand All @@ -18,21 +14,9 @@ jobs:
strategy:
matrix:
include:
- runner: ubuntu-latest
mode: instrumentation
bench: [hello_world, bfs]
- runner: codspeed-macro
mode: walltime
bench:
[
dna_matcher,
lut_grayscale_bench,
lut_filters_bench,
simd_brightness_bench,
simd_filters_bench,
blob_corruption_checker,
blob_corruption_checker,
]
bench: [dna_matcher]
steps:
- uses: actions/checkout@v4
with:
Expand Down
12 changes: 12 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ path = "src/lib.rs"
rand = "0.8"
image = "0.25"
image-compare = "0.5.0"
rayon = "1.10"
memmap2 = "0.9"
memchr = "2.7.6"

[dev-dependencies]
divan = { version = "4.0.2", package = "codspeed-divan-compat" }
Expand Down
87 changes: 84 additions & 3 deletions benches/blob_corruption_checker.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,95 @@
use divan::Bencher;
use eurorust_2025_workshop::blob_corruption_checker::find_corruptions_sequential;
use eurorust_2025_workshop::blob_corruption_checker::{find_corruptions_parallel, find_corruptions_simd, find_corruptions_simd_parallel};

fn main() {
divan::main();
}

#[divan::bench(sample_count = 3, sample_size = 5)]
fn corruption_check(bencher: Bencher) {
fn corruption_check_sequential(bencher: Bencher) {
bencher.bench_local(|| {
let corruptions = divan::black_box(find_corruptions_sequential(
let corruptions = divan::black_box(find_corruptions_simd_parallel(
"reference.bin",
"corrupted.bin",
1024, // 1KB chunks
));

assert_eq!(corruptions.len(), 50, "Should find 50 corruptions");

// All corruptions should be 1KB aligned
for corruption in &corruptions {
assert_eq!(corruption.offset % 1024, 0, "Corruption offset should be 1KB aligned");
assert_eq!(corruption.length % 1024, 0, "Corruption length should be multiple of 1KB");
}

// Check specific corruptions
assert_eq!(corruptions[0].offset, 14801920, "First corruption offset");
assert_eq!(corruptions[0].length, 2048, "First corruption length");
assert_eq!(corruptions[25].offset, 243891200, "Middle corruption offset");
assert_eq!(corruptions[25].length, 4096, "Middle corruption length");
assert_eq!(corruptions[49].offset, 507871232, "Last corruption offset");
assert_eq!(corruptions[49].length, 5120, "Last corruption length");
});
}

#[divan::bench(sample_count = 3, sample_size = 5)]
fn corruption_check_parallel(bencher: Bencher) {
bencher.bench_local(|| {
let corruptions = divan::black_box(find_corruptions_parallel(
"reference.bin",
"corrupted.bin",
1024, // 1KB chunks
));

assert_eq!(corruptions.len(), 50, "Should find 50 corruptions");

// All corruptions should be 1KB aligned
for corruption in &corruptions {
assert_eq!(corruption.offset % 1024, 0, "Corruption offset should be 1KB aligned");
assert_eq!(corruption.length % 1024, 0, "Corruption length should be multiple of 1KB");
}

// Check specific corruptions
assert_eq!(corruptions[0].offset, 14801920, "First corruption offset");
assert_eq!(corruptions[0].length, 2048, "First corruption length");
assert_eq!(corruptions[25].offset, 243891200, "Middle corruption offset");
assert_eq!(corruptions[25].length, 4096, "Middle corruption length");
assert_eq!(corruptions[49].offset, 507871232, "Last corruption offset");
assert_eq!(corruptions[49].length, 5120, "Last corruption length");
});
}

#[divan::bench(sample_count = 3, sample_size = 5)]
fn corruption_check_simd(bencher: Bencher) {
bencher.bench_local(|| {
let corruptions = divan::black_box(find_corruptions_simd(
"reference.bin",
"corrupted.bin",
1024, // 1KB chunks
));

assert_eq!(corruptions.len(), 50, "Should find 50 corruptions");

// All corruptions should be 1KB aligned
for corruption in &corruptions {
assert_eq!(corruption.offset % 1024, 0, "Corruption offset should be 1KB aligned");
assert_eq!(corruption.length % 1024, 0, "Corruption length should be multiple of 1KB");
}

// Check specific corruptions
assert_eq!(corruptions[0].offset, 14801920, "First corruption offset");
assert_eq!(corruptions[0].length, 2048, "First corruption length");
assert_eq!(corruptions[25].offset, 243891200, "Middle corruption offset");
assert_eq!(corruptions[25].length, 4096, "Middle corruption length");
assert_eq!(corruptions[49].offset, 507871232, "Last corruption offset");
assert_eq!(corruptions[49].length, 5120, "Last corruption length");
});
}

#[divan::bench(sample_count = 3, sample_size = 5)]
fn corruption_check_simd_parallel(bencher: Bencher) {
bencher.bench_local(|| {
let corruptions = divan::black_box(find_corruptions_simd_parallel(
"reference.bin",
"corrupted.bin",
1024, // 1KB chunks
Expand Down
61 changes: 60 additions & 1 deletion benches/dna_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fn main() {
}

#[divan::bench(sample_count = 2, sample_size = 3)]
fn dna_matcher() {
fn dna_matcher_old() {
let genome = std::fs::read_to_string("genome.fasta").expect(
"Failed to read genome.fasta\n\n Make sure to run 'cargo run --release --bin generate_fasta'",
);
Expand All @@ -22,3 +22,62 @@ fn dna_matcher() {
matches.len()
);
}

#[divan::bench(sample_count = 2, sample_size = 3)]
fn dna_matcher_memchr() {
let genome = std::fs::read_to_string("genome.fasta").expect(
"Failed to read genome.fasta\n\n Make sure to run 'cargo run --release --bin generate_fasta'",
);
let pattern = "AGTCCGTA";

let matches = divan::black_box(memchr_search(
divan::black_box(&genome),
divan::black_box(pattern),
));

assert!(
matches.len() == 4927,
"Expected 4927 matches, found {}",
matches.len()
);
}

#[divan::bench(sample_count = 2, sample_size = 3)]
fn dna_matcher_mmap() {
let file = std::fs::File::open("genome.fasta").expect(
"Failed to read genome.fasta\n\n Make sure to run 'cargo run --release --bin generate_fasta'",
);
let mmap = unsafe { memmap2::Mmap::map(&file).expect("Failed to mmap genome.fasta") };
let pattern = b"AGTCCGTA";

let matches = divan::black_box(memchr_search_bytes(
divan::black_box(&mmap),
divan::black_box(pattern),
));

assert!(
matches.len() == 4927,
"Expected 4927 matches, found {}",
matches.len()
);
}

#[divan::bench(sample_count = 2, sample_size = 3)]
fn dna_matcher() {
let file = std::fs::File::open("genome.fasta").expect(
"Failed to read genome.fasta\n\n Make sure to run 'cargo run --release --bin generate_fasta'",
);
let mmap = unsafe { memmap2::Mmap::map(&file).expect("Failed to mmap genome.fasta") };
let pattern = b"AGTCCGTA";

let matches = divan::black_box(memchr_search_bytes_parallel(
divan::black_box(&mmap),
divan::black_box(pattern),
));

assert!(
matches.len() == 4927,
"Expected 4927 matches, found {}",
matches.len()
);
}
Loading