From 6575e099574983648a5a44dd1697d49eacbde4b4 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:06:54 +0200 Subject: [PATCH] fix profiling (still not entirely good) --- rust2/benches/opts.rs | 2 +- rust2/src/codegen_interpreter.rs | 15 ++++++++-- rust2/src/lib.rs | 51 ++++++++++++++++++++------------ rust2/src/main.rs | 2 +- rust2/src/parse.rs | 14 +++++++-- 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/rust2/benches/opts.rs b/rust2/benches/opts.rs index 6f487ef..8308592 100644 --- a/rust2/benches/opts.rs +++ b/rust2/benches/opts.rs @@ -26,7 +26,7 @@ fn run_bf(bf: &str) { let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap(); let ir = brainfuck::opts::optimize(&bump, &ast); let code = brainfuck::codegen::generate(&bump, &ir); - brainfuck::codegen_interpreter::run(&code, MockReadWrite, MockReadWrite); + brainfuck::codegen_interpreter::run(&code, MockReadWrite, MockReadWrite, |_| {}); } fn optimized(c: &mut Criterion) { diff --git a/rust2/src/codegen_interpreter.rs b/rust2/src/codegen_interpreter.rs index c22663d..ec34b75 100644 --- a/rust2/src/codegen_interpreter.rs +++ b/rust2/src/codegen_interpreter.rs @@ -7,19 +7,21 @@ const MEM_SIZE: usize = 32_000; type Memory = [Wrapping; MEM_SIZE]; // TODO maybe repr(C) to prevent field reordering? -struct Interpreter<'c, W, R> { +struct Interpreter<'c, W, R, P> { code: &'c Code<'c>, ip: usize, ptr: usize, stdout: W, stdin: R, mem: Memory, + profile_collector: P, } -pub fn run(code: &Code<'_>, stdout: W, stdin: R) +pub fn run(code: &Code<'_>, stdout: W, stdin: R, profile_collector: P) where W: Write, R: Read, + P: FnMut(usize), { let mut interpreter = Interpreter { code, @@ -28,6 +30,7 @@ where stdout, stdin, mem: [Wrapping(0u8); MEM_SIZE], + profile_collector, }; // SAFETY: `Code` can only be produced by the `crate::codegen` module, which is trusted to not @@ -37,7 +40,10 @@ where } } -impl<'c, W: Write, R: Read> Interpreter<'c, W, R> { +impl<'c, W: Write, R: Read, P> Interpreter<'c, W, R, P> +where + P: FnMut(usize), +{ unsafe fn execute(&mut self) { let stmts = self.code.stmts(); loop { @@ -93,6 +99,9 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> { } Stmt::End => break, } + + // this should be a no-op if `profile_collector` is does nothing + (self.profile_collector)(self.ip); } } fn elem_mut(&mut self) -> &mut Wrapping { diff --git a/rust2/src/lib.rs b/rust2/src/lib.rs index fee2c28..c5de172 100644 --- a/rust2/src/lib.rs +++ b/rust2/src/lib.rs @@ -5,6 +5,7 @@ use crate::parse::ParseError; use bumpalo::Bump; +use owo_colors::OwoColorize; use std::fmt::Display; use std::io::{Read, Write}; @@ -20,14 +21,14 @@ pub enum UseProfile { No, } -pub fn run(str: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError> +pub fn run(src: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError> where W: Write, R: Read, { let ast_alloc = Bump::new(); - let parsed = parse::parse(&ast_alloc, str.bytes().enumerate())?; + let parsed = parse::parse(&ast_alloc, src.bytes().enumerate())?; let ir_alloc = Bump::new(); @@ -45,16 +46,28 @@ where match use_profile { UseProfile::Yes => { - // let profile = ir_interpreter::run_profile(&optimized_ir, stdout, stdin); - // let max = profile.iter().max().copied().unwrap_or(0); - // println!("---------------- Profile ----------------"); - // for (i, char) in str.bytes().enumerate() { - // print!("{}", color_by_profile(char as char, profile[i], max)); - // } - println!("no supported lol"); + let mut code_profile_count = vec![0; code.debug().len()]; + + codegen_interpreter::run(&code, stdout, stdin, |ip| unsafe { + *code_profile_count.get_unchecked_mut(ip) += 1; + }); + + let mut src_profile_count = vec![0u64; src.len()]; + + for (stmt_span, stmt_count) in code.debug().iter().zip(&code_profile_count) { + for i in &mut src_profile_count[stmt_span.start()..stmt_span.end()] { + *i += stmt_count; + } + } + + let max = src_profile_count.iter().max().copied().unwrap_or(0); + println!("---------------- Profile ----------------"); + for (char, value) in src.bytes().zip(src_profile_count) { + print!("{}", color_by_profile(char as char, value, max)); + } } UseProfile::No => { - codegen_interpreter::run(&code, stdout, stdin); + codegen_interpreter::run(&code, stdout, stdin, |_| {}); } } @@ -62,16 +75,16 @@ where } fn color_by_profile(char: char, value: u64, max: u64) -> impl Display { - use owo_colors::OwoColorize; + let max = max as f64; + let value = value as f64; + let ratio = value / max; + let logged = -ratio.log10(); + let logged = (logged * 100.) as u64; - let percentage = ((max as f64) / (value as f64) * 100.0) as u64; - - match percentage { - 0..=1 => char.default_color().to_string(), - 2..=10 => char.green().to_string(), - 11..=30 => char.yellow().to_string(), - 31..=90 => char.red().to_string(), - 91..=100 => char.bright_red().to_string(), + match logged { + 0..=15 => char.bright_red().to_string(), + 16..=70 => char.yellow().to_string(), + 71..=300 => char.green().to_string(), _ => char.default_color().to_string(), } } diff --git a/rust2/src/main.rs b/rust2/src/main.rs index 4a25adc..0aafec6 100644 --- a/rust2/src/main.rs +++ b/rust2/src/main.rs @@ -20,7 +20,7 @@ fn main() { let stdin = io::stdin(); let stdin = stdin.lock(); - brainfuck::run(&file, stdout, stdin, UseProfile::No).unwrap_or_else(|_| { + brainfuck::run(&file, stdout, stdin, UseProfile::Yes).unwrap_or_else(|_| { eprintln!("error: Failed to parse brainfuck code"); process::exit(1); }); diff --git a/rust2/src/parse.rs b/rust2/src/parse.rs index f02b402..9e0c64d 100644 --- a/rust2/src/parse.rs +++ b/rust2/src/parse.rs @@ -15,6 +15,7 @@ impl Span { } } + /// start..end fn start_end(start: usize, end: usize) -> Span { Self { start: start.try_into().unwrap(), @@ -22,6 +23,14 @@ impl Span { } } + // start..=end + fn start_end_incl(start: usize, end: usize) -> Span { + Self { + start: start.try_into().unwrap(), + len: (end - start + 1).try_into().unwrap(), + } + } + #[must_use] pub fn until(&self, other: Self) -> Self { Self { @@ -46,8 +55,9 @@ impl Span { self.len.try_into().unwrap() } + /// ..end pub fn end(&self) -> usize { - self.start() + self.len() - 1 + self.start() + self.len() } } @@ -129,7 +139,7 @@ where } }; - Ok((instrs, Span::start_end(start_idx, end_idx))) + Ok((instrs, Span::start_end_incl(start_idx, end_idx))) } #[cfg(test)]