From e67b28aa451c492b87423825923434ae19864735 Mon Sep 17 00:00:00 2001 From: Sergejs Pugacs Date: Wed, 8 Oct 2025 11:14:55 +0300 Subject: [PATCH 1/5] README change --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8e9c5be..1bd02ce 100644 --- a/README.md +++ b/README.md @@ -33,4 +33,5 @@ cargo codspeed build -m walltime cargo codspeed run -m walltime ``` + Note: You can also set the `CODSPEED_RUNNER_MODE` environment variable to `walltime` to avoid passing `-m walltime` every time. From da1f68ccdfec37d3be59875e5d1aad3ef3f8c14b Mon Sep 17 00:00:00 2001 From: Sergejs Pugacs Date: Wed, 8 Oct 2025 11:56:51 +0300 Subject: [PATCH 2/5] Replace Vec with VecDeque in bfs --- src/bfs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bfs.rs b/src/bfs.rs index 487fddc..b3bafd0 100644 --- a/src/bfs.rs +++ b/src/bfs.rs @@ -1,4 +1,5 @@ use std::collections::HashSet; +use std::collections::VecDeque; /// A simple graph represented as an adjacency list #[derive(Debug, Clone)] @@ -27,21 +28,20 @@ impl Graph { /// Returns the order in which nodes were visited pub fn bfs_naive(graph: &Graph, start: usize) -> Vec { let mut visited = HashSet::new(); - let mut queue = Vec::new(); // Using Vec instead of VecDeque - intentionally inefficient! + let mut queue = VecDeque::new(); let mut result = Vec::new(); - queue.push(start); + queue.push_back(start); visited.insert(start); while !queue.is_empty() { - // remove(0) is O(n) - this makes BFS slow! - let node = queue.remove(0); + let node = queue.pop_front().unwrap(); result.push(node); if let Some(neighbors) = graph.adjacency.get(node) { for &neighbor in neighbors { if visited.insert(neighbor) { - queue.push(neighbor); + queue.push_back(neighbor); } } } From 63333d2bd69d3fbaeb88035894379b631bc46318 Mon Sep 17 00:00:00 2001 From: Sergejs Pugacs Date: Wed, 8 Oct 2025 12:11:17 +0300 Subject: [PATCH 3/5] replace HashSet with BitSet --- Cargo.lock | 16 ++++++++++++++++ Cargo.toml | 1 + src/bfs.rs | 5 +++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c337c95..9d0b430 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,21 @@ dependencies = [ "syn", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bit_field" version = "0.10.3" @@ -421,6 +436,7 @@ dependencies = [ name = "eurorust-2025-workshop" version = "0.1.0" dependencies = [ + "bit-set", "codspeed-divan-compat", "image", "image-compare", diff --git a/Cargo.toml b/Cargo.toml index f4172be..5eb089c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ path = "src/lib.rs" rand = "0.8" image = "0.25" image-compare = "0.5.0" +bit-set = "0.8.0" [dev-dependencies] divan = { version = "4.0.2", package = "codspeed-divan-compat" } diff --git a/src/bfs.rs b/src/bfs.rs index b3bafd0..1cd5130 100644 --- a/src/bfs.rs +++ b/src/bfs.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use bit_set::BitSet; use std::collections::VecDeque; /// A simple graph represented as an adjacency list @@ -27,7 +27,8 @@ impl Graph { /// Naive BFS implementation using Vec as a queue (intentionally slow) /// Returns the order in which nodes were visited pub fn bfs_naive(graph: &Graph, start: usize) -> Vec { - let mut visited = HashSet::new(); + let mut visited = BitSet::new(); + let mut queue = VecDeque::new(); let mut result = Vec::new(); From f74651b8fe8a8479926772b8881361aaeffdbb74 Mon Sep 17 00:00:00 2001 From: Sergejs Pugacs Date: Wed, 8 Oct 2025 15:01:32 +0300 Subject: [PATCH 4/5] Use lightness LUT --- src/lut_filters.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/lut_filters.rs b/src/lut_filters.rs index a73068c..40de8a2 100644 --- a/src/lut_filters.rs +++ b/src/lut_filters.rs @@ -38,30 +38,40 @@ pub fn apply_brightness_contrast_gamma( mod naive { use super::*; + pub struct BrightnessLut { + lut: [u8; 256], + } + + impl BrightnessLut { + fn new(brightness: i16, contrast: f32) -> Self { + let mut lut = [0u8; 256]; + + for i in 0..256 { + lut[i] = (((i as f32 - 128.0) * (1.0 + contrast)) + 128.0 + brightness as f32) + .clamp(0.0, 255.0) as u8; + } + + Self { lut } + } + } + /// Apply brightness and contrast with floating-point math per pixel pub fn apply_brightness_contrast(img: &RgbImage, brightness: i16, contrast: f32) -> RgbImage { let (width, height) = img.dimensions(); let mut output = ImageBuffer::new(width, height); + let lut = BrightnessLut::new(brightness, contrast); + for (x, y, pixel) in img.enumerate_pixels() { let r = pixel[0] as f32; let g = pixel[1] as f32; let b = pixel[2] as f32; // Apply contrast and brightness (5 FP ops per channel!) - let r = ((r - 128.0) * (1.0 + contrast)) + 128.0 + brightness as f32; - let g = ((g - 128.0) * (1.0 + contrast)) + 128.0 + brightness as f32; - let b = ((b - 128.0) * (1.0 + contrast)) + 128.0 + brightness as f32; - - output.put_pixel( - x, - y, - Rgb([ - r.clamp(0.0, 255.0) as u8, - g.clamp(0.0, 255.0) as u8, - b.clamp(0.0, 255.0) as u8, - ]), - ); + let r = lut.lut[r.clamp(0.0, 255.0) as usize]; + let g = lut.lut[g.clamp(0.0, 255.0) as usize]; + let b = lut.lut[b.clamp(0.0, 255.0) as usize]; + output.put_pixel(x, y, Rgb([r, g, b])); } output From daffefe02eb319a03b904e1ebe5d22ec5a2002dd Mon Sep 17 00:00:00 2001 From: Sergejs Pugacs Date: Wed, 8 Oct 2025 15:31:48 +0300 Subject: [PATCH 5/5] Bigger is better --- src/blob_corruption_checker.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/blob_corruption_checker.rs b/src/blob_corruption_checker.rs index 2515c20..8eecbe3 100644 --- a/src/blob_corruption_checker.rs +++ b/src/blob_corruption_checker.rs @@ -14,8 +14,9 @@ pub fn find_corruptions_sequential( corrupted_path: &str, chunk_size: usize, ) -> Vec { - let mut ref_file = BufReader::new(File::open(reference_path).unwrap()); - let mut corrupt_file = BufReader::new(File::open(corrupted_path).unwrap()); + let mut ref_file = BufReader::with_capacity(1024 * 1024, File::open(reference_path).unwrap()); + let mut corrupt_file = + BufReader::with_capacity(1024 * 1024, File::open(corrupted_path).unwrap()); let mut ref_buffer = vec![0u8; chunk_size]; let mut corrupt_buffer = vec![0u8; chunk_size]; @@ -92,10 +93,7 @@ mod tests { "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].offset, 507871232, "Last corruption offset"); assert_eq!(corruptions[49].length, 5120, "Last corruption length"); } }