diff --git a/examples/closure_cracking.myc b/examples/closure_cracking.myc index 64b4db2..83d8aab 100644 --- a/examples/closure_cracking.myc +++ b/examples/closure_cracking.myc @@ -1,4 +1,4 @@ -;; Benchmark: 143ns -;; Benchmark-Repeat: 14093 +;; Benchmark: 130ns +;; Benchmark-Repeat: 15355 ;; Output: 5 (((fn [x] (fn [] x)) 5)) diff --git a/examples/def_local_inlining.myc b/examples/def_local_inlining.myc index 6d1accd..8b46a58 100644 --- a/examples/def_local_inlining.myc +++ b/examples/def_local_inlining.myc @@ -1,5 +1,5 @@ -;; Benchmark: 363ns -;; Benchmark-Repeat: 5561 +;; Benchmark: 336ns +;; Benchmark-Repeat: 5959 ;; examples/def_local_inlining.myc ;; Demonstrates potential for DefLocal-Inlining (Phase 2.5) diff --git a/examples/macro_hygiene.myc b/examples/macro_hygiene.myc index ef205fc..5dc0571 100644 --- a/examples/macro_hygiene.myc +++ b/examples/macro_hygiene.myc @@ -1,5 +1,5 @@ -;; Benchmark: 339ns -;; Benchmark-Repeat: 6100 +;; Benchmark: 237ns +;; Benchmark-Repeat: 8555 ;; Output: 5 (do (def y 1) diff --git a/examples/macro_power.myc b/examples/macro_power.myc index 4818a35..246ca6c 100644 --- a/examples/macro_power.myc +++ b/examples/macro_power.myc @@ -1,5 +1,5 @@ -;; Benchmark: 217ns -;; Benchmark-Repeat: 9500 +;; Benchmark: 198ns +;; Benchmark-Repeat: 10207 ;; Nested Macro and Arithmetic example ;; Output: 81 diff --git a/examples/optimizer_purity.myc b/examples/optimizer_purity.myc index 1a1fe80..19b8d19 100644 --- a/examples/optimizer_purity.myc +++ b/examples/optimizer_purity.myc @@ -1,5 +1,5 @@ -;; Benchmark: 503ns -;; Benchmark-Repeat: 3987 +;; Benchmark: 448ns +;; Benchmark-Repeat: 4564 (do (def area (fn [x] (* PI x))) (area 10) diff --git a/src/ast/environment.rs b/src/ast/environment.rs index f04ce96..29e9754 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -274,13 +274,13 @@ impl Environment { // 2. Auto-apply: If the script returned a closure, we apply arguments to it. let mut final_res = res; - if let Value::Object(obj) = &final_res { - if let Some(closure) = obj.as_any().downcast_ref::() { - final_res = match vm.run_with_args(closure, args) { - Ok(v) => v, - Err(e) => panic!("Myc Runtime Error (Closure): {}", e), - }; - } + if let Value::Object(obj) = &final_res + && let Some(closure) = obj.as_any().downcast_ref::() + { + final_res = match vm.run_with_args(closure, args) { + Ok(v) => v, + Err(e) => panic!("Myc Runtime Error (Closure): {}", e), + }; } // 3. Resolve Tail Calls diff --git a/src/bin/ast.rs b/src/bin/ast.rs index 5aa9be9..a8ebf8a 100644 --- a/src/bin/ast.rs +++ b/src/bin/ast.rs @@ -49,7 +49,12 @@ fn main() { } println!("🚀 Running benchmarks in RELEASE mode...\n"); - let results = tester::run_benchmarks(cli.update_bench); + let filter = cli + .file + .as_ref() + .and_then(|p| p.file_name()) + .map(|n| n.to_string_lossy().to_string()); + let results = tester::run_benchmarks(cli.update_bench, filter.as_deref()); for res in results { let diff = res .diff_pct diff --git a/src/main.rs b/src/main.rs index 32b1fe0..e261e01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -252,21 +252,34 @@ impl CompilerApp { self.output_log = log; } - fn run_benchmarks(&mut self, update: bool) { + fn run_benchmarks(&mut self, update: bool, only_current: bool) { use myc::utils::tester; + + let filter = if only_current { + self.current_example_path + .as_ref() + .and_then(|p| p.file_name()) + .map(|n| n.to_string_lossy().to_string()) + } else { + None + }; + if cfg!(debug_assertions) && !update { self.output_log = String::from( "⚠️ WARNING: Benchmarks in Debug mode are inaccurate!\nUse Release build for real measurements.\n\n", ); } else { - self.output_log = String::from(if update { - "UPDATING BASELINES...\n\n" - } else { - "RUNNING BENCHMARKS...\n\n" - }); + self.output_log = format!( + "{}...\n\n", + match (update, only_current) { + (true, true) => "UPDATING BASELINE FOR CURRENT SCRIPT", + (true, false) => "UPDATING ALL BASELINES", + (false, _) => "RUNNING BENCHMARKS", + } + ); } - let results = tester::run_benchmarks(update); + let results = tester::run_benchmarks(update, filter.as_deref()); let mut log = self.output_log.clone(); for res in results { @@ -331,21 +344,31 @@ impl eframe::App for CompilerApp { let is_debug = cfg!(debug_assertions); ui.add_enabled_ui(!is_debug, |ui: &mut egui::Ui| { - let btn = ui.button("Run Benchmarks"); + let btn = ui.button("Run All Benchmarks"); if is_debug { btn.on_hover_text("Benchmarks are only available in Release builds."); } else if btn.clicked() { - self.run_benchmarks(false); + self.run_benchmarks(false, false); ui.close(); } - let btn_base = ui.button("Update Baselines"); + let btn_base_all = ui.button("Update All Baselines"); if is_debug { - btn_base.on_hover_text( + btn_base_all.on_hover_text( "Updating baselines is only allowed in Release builds.", ); - } else if btn_base.clicked() { - self.run_benchmarks(true); + } else if btn_base_all.clicked() { + self.run_benchmarks(true, false); + ui.close(); + } + + let btn_base_curr = ui.button("Update Current Baseline"); + if is_debug { + btn_base_curr.on_hover_text( + "Updating baselines is only allowed in Release builds.", + ); + } else if btn_base_curr.clicked() { + self.run_benchmarks(true, true); ui.close(); } }); @@ -406,7 +429,7 @@ impl eframe::App for CompilerApp { if is_debug { bench_btn.on_hover_text("Benchmarks are only available in Release builds."); } else if bench_btn.clicked() { - self.run_benchmarks(false); + self.run_benchmarks(false, false); } }); }); diff --git a/src/utils/tester.rs b/src/utils/tester.rs index c57e49b..3ee950c 100644 --- a/src/utils/tester.rs +++ b/src/utils/tester.rs @@ -77,7 +77,7 @@ pub fn run_functional_tests_with_optimization(enabled: bool) -> Vec results } -pub fn run_benchmarks(update: bool) -> Vec { +pub fn run_benchmarks(update: bool, filter: Option<&str>) -> Vec { let mut results = Vec::new(); let entries = fs::read_dir("examples").unwrap(); let is_release = !cfg!(debug_assertions); @@ -90,8 +90,14 @@ pub fn run_benchmarks(update: bool) -> Vec { continue; } - let content = fs::read_to_string(&path).unwrap(); let name = path.file_name().unwrap().to_string_lossy().to_string(); + if let Some(f) = filter + && name != f + { + continue; + } + + let content = fs::read_to_string(&path).unwrap(); let baseline_match = baseline_re.captures(&content); let repeat_match = repeat_re.captures(&content); @@ -311,7 +317,7 @@ mod tests { #[cfg(not(debug_assertions))] fn benchmark_regression_test() { use super::*; - let results = run_benchmarks(false); + let results = run_benchmarks(false, None); let failures: Vec<_> = results.iter().filter(|r| r.status == "FAILED").collect(); if !failures.is_empty() {