use criterion::{black_box, criterion_group, criterion_main, Criterion}; use font_loader::system_fonts; use image::{ImageBuffer, Rgba}; use imageproc::drawing; use log::error; use sensor_core::{ get_cache_dir, hex_to_rgba, text_renderer, ElementType, SensorType, SensorValue, SensorValueModifier, TextAlign, TextConfig, }; use std::collections::HashMap; use std::fs; use std::path::Path; use std::sync::{Arc, Mutex}; fn criterion_benchmark(criterion: &mut Criterion) { std::env::set_var("SENSOR_BRIDGE_APP_NAME", "sensor-display"); let base_image: ImageBuffer, Vec> = ImageBuffer::new(100, 100); let element_id = "test"; let text_config = TextConfig { sensor_id: "test".to_string(), value_modifier: SensorValueModifier::None, font_family: "Arial".to_string(), font_size: 12, font_color: "#FFFFFFFF".to_string(), width: 100, height: 100, format: "{value} {unit}".to_string(), alignment: TextAlign::Left, }; let x = 0; let y = 0; let sensor_value = SensorValue { id: "test".to_string(), value: "test".to_string(), unit: "test".to_string(), label: "".to_string(), sensor_type: SensorType::Text, }; // Get font cache dir let cache_dir = get_cache_dir(element_id, &ElementType::Text).join(element_id); fs::remove_dir_all(cache_dir.parent().unwrap()).unwrap_or_default(); fs::create_dir_all(cache_dir.parent().unwrap()).unwrap(); // Write font data to it let font_family = system_fonts::FontPropertyBuilder::new() .family(&text_config.font_family) .build(); let font_data = system_fonts::get(&font_family).unwrap().0; fs::write(cache_dir, &font_data).unwrap(); let font = rusttype::Font::try_from_bytes(&font_data).unwrap(); // Create a arc mutex that holds a hashmap of fonts let mut font_data_table = HashMap::new(); font_data_table.insert("Arial".to_string(), font_data.clone()); let font_data_mutex: Arc>>> = Arc::new(Mutex::new(font_data_table)); // Start benchmarking criterion.bench_function("draw text fs", |bencher| { bencher.iter(|| { draw_text_fs( black_box(&mut base_image.clone()), black_box(element_id), black_box(text_config.clone()), black_box(x), black_box(y), black_box(Some(&sensor_value)), ); }) }); criterion.bench_function("draw text memory", |bencher| { bencher.iter(|| { draw_text_memory( black_box(&mut base_image.clone()), black_box(&font_data_mutex), black_box(text_config.clone()), black_box(x), black_box(y), black_box(Some(&sensor_value)), ); }) }); criterion.bench_function("draw text neo", |bencher| { bencher.iter(|| { text_renderer::render( black_box(base_image.width()), black_box(base_image.height()), black_box(&text_config), black_box(&[vec![sensor_value.clone()]]), black_box(&font), ) }) }); } criterion_group!(benches, criterion_benchmark); criterion_main!(benches); fn draw_text_fs( image: &mut ImageBuffer, Vec>, element_id: &str, text_config: TextConfig, x: i32, y: i32, sensor_value: Option<&SensorValue>, ) { let font_scale = rusttype::Scale::uniform(text_config.font_size as f32); let font_color: Rgba = hex_to_rgba(&text_config.font_color); let text_format = text_config.format; let (value, unit): (&str, &str) = match sensor_value { Some(sensor_value) => (&sensor_value.value, &sensor_value.unit), _ => ("N/A", ""), }; let text = text_format .replace("{value}", value) .replace("{unit}", unit); let cache_dir = get_cache_dir(element_id, &ElementType::Text).join(element_id); let font_path = cache_dir.to_str().unwrap(); if !Path::new(&font_path).exists() { error!("File {} does not exist", font_path); return; } let font_data = fs::read(font_path).unwrap(); let font = rusttype::Font::try_from_bytes(&font_data).unwrap(); drawing::draw_text_mut(image, font_color, x, y, font_scale, &font, text.as_str()); } fn draw_text_memory( image: &mut ImageBuffer, Vec>, font_data_cache: &Arc>>>, text_config: TextConfig, x: i32, y: i32, sensor_value: Option<&SensorValue>, ) { let font_scale = rusttype::Scale::uniform(text_config.font_size as f32); let font_color: Rgba = hex_to_rgba(&text_config.font_color); let text_format = text_config.format; let (value, unit): (&str, &str) = match sensor_value { Some(sensor_value) => (&sensor_value.value, &sensor_value.unit), _ => ("N/A", ""), }; let text = text_format .replace("{value}", value) .replace("{unit}", unit); let font_data_cache = font_data_cache.lock().unwrap(); let font_data = font_data_cache.get(&text_config.font_family).unwrap(); let font = rusttype::Font::try_from_bytes(font_data).unwrap(); drawing::draw_text_mut(image, font_color, x, y, font_scale, &font, text.as_str()); }