Benchmarking

This commit is contained in:
2026-01-30 15:08:01 +01:00
parent 2d79b1dfbb
commit 41e7b2a10c
5 changed files with 53 additions and 121 deletions
+24 -2
View File
@@ -4,12 +4,34 @@ use osui::prelude::*;
pub fn main() { pub fn main() {
let engine = Benchmark::new(Console::new()); let engine = Benchmark::new(Console::new());
engine.run(app).expect("Failed to run engine");
let mut benchmark_result = Vec::new();
for flat in 0..10 {
// for nest in 0..10 {
benchmark_result.push(
engine
.run(move |cx| {
// let sync_nest = use_state(nest);
cx.scope().child(app, None);
// use_sync_effect(cx, &sync_nest, |s| s.get_dl(), &[&sync_nest]);
rsx! {
app
}
.view(cx.clone())
})
.expect("Failed to run engine"),
);
// }
}
} }
fn app(cx: &Arc<Context>) -> View { fn app(cx: &Arc<Context>) -> View {
// let nest = use_sync_state(cx, 0, |v| *v);
rsx! { rsx! {
"Hello, world!" "hello_world"
} }
.view(cx.clone()) .view(cx.clone())
} }
+7 -2
View File
@@ -3,8 +3,13 @@ use std::sync::Arc;
use osui::prelude::*; use osui::prelude::*;
pub fn main() { pub fn main() {
let engine = SimpleBenchmark::new(Console::new()); let engine = Benchmark::new(Console::new());
engine.run(app).expect("Failed to run engine"); let benchmark_result = engine.run(app).expect("Failed to run engine");
println!("Avg: {} μs", benchmark_result.average);
println!("Min: {} μs", benchmark_result.min);
println!("Max: {} μs", benchmark_result.max);
println!("Tot: {} μs", benchmark_result.total);
println!("Tot Render: {} μs", benchmark_result.total_render);
} }
fn app(cx: &Arc<Context>) -> View { fn app(cx: &Arc<Context>) -> View {
+22 -22
View File
@@ -6,6 +6,15 @@ use crate::{prelude::Context, render::Area, DrawContext, View};
use super::Engine; use super::Engine;
#[derive(Debug, Clone)]
pub struct BenchmarkResult {
pub average: u128,
pub min: u128,
pub max: u128,
pub total_render: u128,
pub total: u128,
}
pub struct Benchmark<T: Engine>(T); pub struct Benchmark<T: Engine>(T);
impl<T: Engine> Benchmark<T> { impl<T: Engine> Benchmark<T> {
@@ -14,12 +23,12 @@ impl<T: Engine> Benchmark<T> {
} }
} }
impl<T: Engine> Engine for Benchmark<T> { impl<T: Engine> Engine<BenchmarkResult> for Benchmark<T> {
fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>( fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
&self, &self,
component: F, component: F,
) -> crate::Result<()> { ) -> crate::Result<BenchmarkResult> {
let mut times: Vec<u64> = Vec::new(); let mut times: Vec<u128> = Vec::new();
let cx = self.init(component); let cx = self.init(component);
let start = Instant::now(); let start = Instant::now();
@@ -28,7 +37,7 @@ impl<T: Engine> Engine for Benchmark<T> {
let start = Instant::now(); let start = Instant::now();
self.render(&cx); self.render(&cx);
let end = Instant::now(); let end = Instant::now();
times.push(end.duration_since(start).as_micros() as u64); times.push(end.duration_since(start).as_micros());
self.0.render_delay(); self.0.render_delay();
} }
@@ -38,26 +47,17 @@ impl<T: Engine> Engine for Benchmark<T> {
execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap(); execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap();
execute!(stdout(), MoveTo(0, 0)).unwrap(); execute!(stdout(), MoveTo(0, 0)).unwrap();
println!( Ok(BenchmarkResult {
"Average time: {} µs", min: *times.iter().min().unwrap_or(&0),
if times.len() > 0 { max: *times.iter().max().unwrap_or(&0),
times.iter().sum::<u64>() / (times.len() as u64) total: end.duration_since(start).as_micros(),
total_render: times.iter().sum::<u128>(),
average: if times.len() > 0 {
times.iter().sum::<u128>() / (times.len() as u128)
} else { } else {
0 0
} },
); })
println!("Min time: {} µs", times.iter().min().unwrap_or(&0));
println!("Max time: {} µs", times.iter().max().unwrap_or(&0));
println!("Total time: {} µs", end.duration_since(start).as_micros());
println!("Total render time: {} µs", times.iter().sum::<u64>());
println!(
"\n{},{},{}",
times.iter().min().unwrap_or(&0),
times.iter().max().unwrap_or(&0),
end.duration_since(start).as_micros()
);
Ok(())
} }
fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>( fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
-2
View File
@@ -1,11 +1,9 @@
pub mod benchmark; pub mod benchmark;
pub mod commands; pub mod commands;
pub mod console; pub mod console;
pub mod simple_benchmark;
pub use benchmark::*; pub use benchmark::*;
pub use console::*; pub use console::*;
pub use simple_benchmark::*;
use std::{any::Any, sync::Arc}; use std::{any::Any, sync::Arc};
-93
View File
@@ -1,93 +0,0 @@
use std::{io::stdout, sync::Arc, time::Instant};
use crossterm::{cursor::MoveTo, execute, terminal::Clear};
use crate::{prelude::Context, render::Area, DrawContext, View};
use super::Engine;
pub struct SimpleBenchmark<T: Engine>(T);
impl<T: Engine> SimpleBenchmark<T> {
pub fn new(engine: T) -> Self {
Self(engine)
}
}
impl<T: Engine> Engine for SimpleBenchmark<T> {
fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
&self,
component: F,
) -> crate::Result<()> {
let mut times: Vec<u64> = Vec::new();
let cx = self.init(component);
let start = Instant::now();
for _ in 0..100 {
let start = Instant::now();
self.render(&cx);
let end = Instant::now();
times.push(end.duration_since(start).as_nanos() as u64);
self.0.render_delay();
}
let end = Instant::now();
execute!(stdout(), Clear(crossterm::terminal::ClearType::Purge)).unwrap();
execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap();
execute!(stdout(), MoveTo(0, 0)).unwrap();
println!(
"Average time: {} nanoseconds",
if times.len() > 0 {
times.iter().sum::<u64>() / (times.len() as u64)
} else {
0
}
);
println!("Min time: {} nanoseconds", times.iter().min().unwrap_or(&0));
println!("Max time: {} nanoseconds", times.iter().max().unwrap_or(&0));
println!(
"Median time: {} nanoseconds",
times.iter().nth(times.len() / 2).unwrap_or(&0)
);
println!(
"Total time: {} nanoseconds",
end.duration_since(start).as_nanos()
);
println!(
"Total render time: {} nanoseconds",
times.iter().sum::<u64>()
);
Ok(())
}
fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
&self,
component: F,
) -> Arc<Context> {
self.0.init(component)
}
fn draw_context(&self, ctx: &DrawContext) {
self.0.draw_context(ctx)
}
fn render(&self, cx: &Arc<Context>) {
self.0.render(cx)
}
fn render_view(&self, area: &Area, view: &View) -> DrawContext {
self.0.render_view(area, view)
}
fn render_delay(&self) {
self.0.render_delay();
}
fn executor(&self) -> Arc<dyn super::CommandExecutor> {
self.0.executor()
}
}