mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 22:35:03 +01:00
fix profiling (still not entirely good)
This commit is contained in:
parent
9d140c45d7
commit
6575e09957
5 changed files with 58 additions and 26 deletions
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue