fix profiling (still not entirely good)

This commit is contained in:
nora 2022-04-15 22:06:54 +02:00
parent 9d140c45d7
commit 6575e09957
5 changed files with 58 additions and 26 deletions

View file

@ -26,7 +26,7 @@ fn run_bf(bf: &str) {
let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap(); let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap();
let ir = brainfuck::opts::optimize(&bump, &ast); let ir = brainfuck::opts::optimize(&bump, &ast);
let code = brainfuck::codegen::generate(&bump, &ir); 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) { fn optimized(c: &mut Criterion) {

View file

@ -7,19 +7,21 @@ const MEM_SIZE: usize = 32_000;
type Memory = [Wrapping<u8>; MEM_SIZE]; type Memory = [Wrapping<u8>; MEM_SIZE];
// TODO maybe repr(C) to prevent field reordering? // TODO maybe repr(C) to prevent field reordering?
struct Interpreter<'c, W, R> { struct Interpreter<'c, W, R, P> {
code: &'c Code<'c>, code: &'c Code<'c>,
ip: usize, ip: usize,
ptr: usize, ptr: usize,
stdout: W, stdout: W,
stdin: R, stdin: R,
mem: Memory, mem: Memory,
profile_collector: P,
} }
pub fn run<W, R>(code: &Code<'_>, stdout: W, stdin: R) pub fn run<W, R, P>(code: &Code<'_>, stdout: W, stdin: R, profile_collector: P)
where where
W: Write, W: Write,
R: Read, R: Read,
P: FnMut(usize),
{ {
let mut interpreter = Interpreter { let mut interpreter = Interpreter {
code, code,
@ -28,6 +30,7 @@ where
stdout, stdout,
stdin, stdin,
mem: [Wrapping(0u8); MEM_SIZE], mem: [Wrapping(0u8); MEM_SIZE],
profile_collector,
}; };
// SAFETY: `Code` can only be produced by the `crate::codegen` module, which is trusted to not // 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) { unsafe fn execute(&mut self) {
let stmts = self.code.stmts(); let stmts = self.code.stmts();
loop { loop {
@ -93,6 +99,9 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> {
} }
Stmt::End => break, 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<u8> { fn elem_mut(&mut self) -> &mut Wrapping<u8> {

View file

@ -5,6 +5,7 @@
use crate::parse::ParseError; use crate::parse::ParseError;
use bumpalo::Bump; use bumpalo::Bump;
use owo_colors::OwoColorize;
use std::fmt::Display; use std::fmt::Display;
use std::io::{Read, Write}; use std::io::{Read, Write};
@ -20,14 +21,14 @@ pub enum UseProfile {
No, No,
} }
pub fn run<R, W>(str: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError> pub fn run<R, W>(src: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError>
where where
W: Write, W: Write,
R: Read, R: Read,
{ {
let ast_alloc = Bump::new(); 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(); let ir_alloc = Bump::new();
@ -45,16 +46,28 @@ where
match use_profile { match use_profile {
UseProfile::Yes => { UseProfile::Yes => {
// let profile = ir_interpreter::run_profile(&optimized_ir, stdout, stdin); let mut code_profile_count = vec![0; code.debug().len()];
// let max = profile.iter().max().copied().unwrap_or(0);
// println!("---------------- Profile ----------------"); codegen_interpreter::run(&code, stdout, stdin, |ip| unsafe {
// for (i, char) in str.bytes().enumerate() { *code_profile_count.get_unchecked_mut(ip) += 1;
// print!("{}", color_by_profile(char as char, profile[i], max)); });
// }
println!("no supported lol"); 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 => { 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 { 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 logged {
0..=15 => char.bright_red().to_string(),
match percentage { 16..=70 => char.yellow().to_string(),
0..=1 => char.default_color().to_string(), 71..=300 => char.green().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(),
_ => char.default_color().to_string(), _ => char.default_color().to_string(),
} }
} }

View file

@ -20,7 +20,7 @@ fn main() {
let stdin = io::stdin(); let stdin = io::stdin();
let stdin = stdin.lock(); 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"); eprintln!("error: Failed to parse brainfuck code");
process::exit(1); process::exit(1);
}); });

View file

@ -15,6 +15,7 @@ impl Span {
} }
} }
/// start..end
fn start_end(start: usize, end: usize) -> Span { fn start_end(start: usize, end: usize) -> Span {
Self { Self {
start: start.try_into().unwrap(), 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] #[must_use]
pub fn until(&self, other: Self) -> Self { pub fn until(&self, other: Self) -> Self {
Self { Self {
@ -46,8 +55,9 @@ impl Span {
self.len.try_into().unwrap() self.len.try_into().unwrap()
} }
/// ..end
pub fn end(&self) -> usize { 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)] #[cfg(test)]