WIP benchmarks

This commit is contained in:
Dawid Pietrykowski 2025-03-30 12:13:39 +02:00
parent 0b9243dc4c
commit dd982a9f42
6 changed files with 353 additions and 60 deletions

243
Cargo.lock generated
View File

@ -57,6 +57,15 @@ dependencies = [
"zerocopy 0.7.35", "zerocopy 0.7.35",
] ]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "aligned-vec" name = "aligned-vec"
version = "0.5.0" version = "0.5.0"
@ -313,6 +322,17 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
@ -515,6 +535,12 @@ dependencies = [
"wayland-client", "wayland-client",
] ]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.17" version = "1.2.17"
@ -560,6 +586,17 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags 1.3.2",
"textwrap",
"unicode-width",
]
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"
version = "5.4.0" version = "5.4.0"
@ -780,6 +817,42 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "criterion"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools 0.10.5",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
dependencies = [
"cast",
"itertools 0.10.5",
]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.6" version = "0.8.6"
@ -821,6 +894,27 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "csv"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "ctor-lite" name = "ctor-lite"
version = "0.1.0" version = "0.1.0"
@ -1076,7 +1170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"half", "half 2.5.0",
"lebe", "lebe",
"miniz_oxide", "miniz_oxide",
"rayon-core", "rayon-core",
@ -1442,6 +1536,12 @@ dependencies = [
"svg_fmt", "svg_fmt",
] ]
[[package]]
name = "half"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]] [[package]]
name = "half" name = "half"
version = "2.5.0" version = "2.5.0"
@ -1498,6 +1598,15 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.9" version = "0.3.9"
@ -1594,7 +1703,7 @@ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"bytemuck", "bytemuck",
"cosmic-text", "cosmic-text",
"half", "half 2.5.0",
"iced_core", "iced_core",
"iced_futures", "iced_futures",
"image 0.24.9", "image 0.24.9",
@ -1761,9 +1870,10 @@ dependencies = [
name = "imflow" name = "imflow"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"criterion",
"iced", "iced",
"image 0.25.6", "image 0.25.6",
"itertools", "itertools 0.12.1",
"memmap2", "memmap2",
"tokio", "tokio",
"tracing-subscriber", "tracing-subscriber",
@ -1806,6 +1916,15 @@ dependencies = [
"syn 2.0.100", "syn 2.0.100",
] ]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.12.1" version = "0.12.1"
@ -1815,6 +1934,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@ -2695,6 +2820,12 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]] [[package]]
name = "orbclient" name = "orbclient"
version = "0.3.48" version = "0.3.48"
@ -2920,6 +3051,34 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]] [[package]]
name = "png" name = "png"
version = "0.17.16" version = "0.17.16"
@ -3095,7 +3254,7 @@ dependencies = [
"built", "built",
"cfg-if", "cfg-if",
"interpolate_name", "interpolate_name",
"itertools", "itertools 0.12.1",
"libc", "libc",
"libfuzzer-sys", "libfuzzer-sys",
"log", "log",
@ -3205,6 +3364,35 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "renderdoc-sys" name = "renderdoc-sys"
version = "1.1.0" version = "1.1.0"
@ -3300,6 +3488,12 @@ dependencies = [
"unicode-script", "unicode-script",
] ]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@ -3349,6 +3543,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half 1.8.3",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.219" version = "1.0.219"
@ -3360,6 +3564,18 @@ dependencies = [
"syn 2.0.100", "syn 2.0.100",
] ]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.20" version = "0.1.20"
@ -3657,6 +3873,15 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.69" version = "1.0.69"
@ -3737,6 +3962,16 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.9.0" version = "1.9.0"

View File

@ -15,3 +15,10 @@ tracing-subscriber = "0.3"
zune-image = {version = "0.4.15", features = ["all"]} zune-image = {version = "0.4.15", features = ["all"]}
[profile.dev.package.zune-jpeg] [profile.dev.package.zune-jpeg]
opt-level = 3 opt-level = 3
[dev-dependencies]
criterion = "0.3"
[[bench]]
name = "image_load"
harness = false

19
benches/image_load.rs Normal file
View File

@ -0,0 +1,19 @@
#![allow(unused)]
use std::iter;
use criterion::BenchmarkId;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use imflow::image::{Approach, load_thumbnail};
const PATH: &str = "test_images/20240811-194516_DSC02274.JPG";
pub fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("from_elem");
group.bench_function("mmap", |b| b.iter(|| load_thumbnail(PATH, Approach::Mmap)));
group.bench_function("path", |b| b.iter(|| load_thumbnail(PATH, Approach::Path)));
group.bench_function("iced", |b| b.iter(|| load_thumbnail(PATH, Approach::Iced)));
group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

77
src/image.rs Normal file
View File

@ -0,0 +1,77 @@
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
use std::fs::File;
pub enum Approach {
Mmap,
Path,
Iced,
}
fn convert_rgb_to_rgba(rgb_data: Vec<Vec<u8>>) -> Vec<u8> {
let r_channel = &rgb_data[0];
let num_pixels = r_channel.len() / 3;
let mut rgba_data: Vec<u8> = Vec::with_capacity(num_pixels * 4);
for i in 0..num_pixels {
rgba_data.push(r_channel[i * 3]);
rgba_data.push(r_channel[i * 3 + 1]);
rgba_data.push(r_channel[i * 3 + 2]);
rgba_data.push(255); // Fully opaque Alpha value
}
rgba_data
}
pub fn load_thumbnail(
path: &str,
approach: Approach,
) -> Result<iced::widget::image::Handle, String> {
match approach {
Approach::Mmap => {
let file = File::open(path).map_err(|e| e.to_string())?;
let mmap = unsafe { memmap2::Mmap::map(&file) }.map_err(|e| e.to_string())?;
println!("mapped file");
let img = zune_image::image::Image::read(&*mmap, DecoderOptions::default()).unwrap();
let width = img.dimensions().0 as u32;
let height = img.dimensions().1 as u32;
println!("loaded");
let flat = img.flatten_to_u8();
println!("flattened");
let rgba = convert_rgb_to_rgba(flat);
println!("rgbad");
let conv = iced::widget::image::Handle::from_rgba(width, height, rgba);
println!("iced");
Ok(conv)
}
Approach::Path => {
let img = zune_image::image::Image::open_with_options(path, DecoderOptions::default())
.unwrap();
let width = img.dimensions().0 as u32;
let height = img.dimensions().1 as u32;
println!("loaded");
let flat = img.flatten_to_u8();
println!("flattened");
let rgba = convert_rgb_to_rgba(flat);
println!("rgbad");
let conv = iced::widget::image::Handle::from_rgba(width, height, rgba);
println!("iced");
Ok(conv)
}
Approach::Iced => {
let file = File::open(path).map_err(|e| e.to_string())?;
let mmap = unsafe { memmap2::Mmap::map(&file) }.map_err(|e| e.to_string())?;
let img = image::load_from_memory(&mmap).map_err(|e| e.to_string())?;
let width = img.width();
let height = img.height();
println!("loaded");
let rgba = img.into_rgba8().into_raw();
println!("rgbad");
let conv = iced::widget::image::Handle::from_rgba(width, height, rgba);
println!("iced");
Ok(conv)
}
}
}

1
src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod image;

View File

@ -3,7 +3,7 @@
// use grid::Grid; // use grid::Grid;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::{self, File}; use std::fs::{self};
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::{self, Duration}; use std::time::{self, Duration};
@ -15,9 +15,10 @@ use iced::widget::image::FilterMethod;
use iced::widget::{ use iced::widget::{
Column, Container, button, center, checkbox, column, container, pick_list, row, slider, text, Column, Container, button, center, checkbox, column, container, pick_list, row, slider, text,
}; };
use iced::{Center, Element, Fill, Length, Size, Subscription, Task, Theme}; use iced::{Center, Element, Fill, Length, Size, Subscription, Task, Theme, keyboard};
use image::{self, DynamicImage, EncodableLayout, ImageBuffer, ImageReader}; use image::{self, DynamicImage, EncodableLayout, ImageBuffer, ImageReader};
use itertools::Itertools;
use imflow::image::{Approach, load_thumbnail};
use zune_image::codecs::qoi::zune_core::options::DecoderOptions; // for general image operations use zune_image::codecs::qoi::zune_core::options::DecoderOptions; // for general image operations
// use image::io::Reader as ImageReader; // specifically for Reader // use image::io::Reader as ImageReader; // specifically for Reader
@ -144,7 +145,7 @@ impl GameOfLife {
if !self.loaded_images.contains_key(&path.to_path_buf()) { if !self.loaded_images.contains_key(&path.to_path_buf()) {
self.loaded_images.insert( self.loaded_images.insert(
path.to_path_buf(), path.to_path_buf(),
load_thumbnail(path.to_str().unwrap()).unwrap(), load_thumbnail(path.to_str().unwrap(), Approach::Iced).unwrap(),
); );
} }
} }
@ -154,12 +155,11 @@ impl GameOfLife {
} }
fn subscription(&self) -> Subscription<Message> { fn subscription(&self) -> Subscription<Message> {
if self.is_playing { keyboard::on_key_press(|key, _modifiers| match key {
iced::time::every(Duration::from_millis(1000 / self.speed as u64)) keyboard::Key::Named(keyboard::key::Named::ArrowRight) => Some(Message::Next(1)),
.map(|_| Message::Tick) keyboard::Key::Named(keyboard::key::Named::ArrowLeft) => Some(Message::Next(-1)),
} else { _ => None,
Subscription::none() })
}
} }
fn view(&self) -> Element<'_, Message> { fn view(&self) -> Element<'_, Message> {
@ -278,49 +278,3 @@ fn view_controls<'a>(
.align_y(Center) .align_y(Center)
.into() .into()
} }
fn load_thumbnail(path: &str) -> Result<iced::widget::image::Handle, String> {
// let file = File::open(path).map_err(|e| e.to_string())?;
// let mmap = unsafe { memmap2::Mmap::map(&file) }.map_err(|e| e.to_string())?;
// println!("mapped file");
// let img = zune_image::image::Image::read(&*mmap, DecoderOptions::default()).unwrap();
let img = zune_image::image::Image::open_with_options(path, DecoderOptions::default()).unwrap();
// let img = image::load_from_memory(&mmap)
// .map_err(|e| e.to_string())?
// .decode()
// .map_err(|e| e.to_string())?;
// let thumbnail = img.thumbnail(128, 128);
let width = img.dimensions().0 as u32;
let height = img.dimensions().1 as u32;
println!("loaded");
let flat = img.flatten_to_u8();
println!("flattened");
let rgba = convert_rgb_to_rgba(flat);
println!("rgbad");
// let leaked_slice = Box::leak(rgba[0].clone().into_boxed_slice());
// let slice = rgba[0].as_slice().clone();
let conv = iced::widget::image::Handle::from_rgba(
width, height, // leaked_slice.as_bytes(),
rgba,
);
println!("iced");
Ok((conv))
}
fn convert_rgb_to_rgba(rgb_data: Vec<Vec<u8>>) -> Vec<u8> {
let r_channel = &rgb_data[0];
let num_pixels = r_channel.len() / 3;
let mut rgba_data: Vec<u8> = Vec::with_capacity(num_pixels * 4);
for i in 0..num_pixels {
rgba_data.push(r_channel[i * 3]);
rgba_data.push(r_channel[i * 3 + 1]);
rgba_data.push(r_channel[i * 3 + 2]);
rgba_data.push(255); // Fully opaque Alpha value
}
rgba_data
}