Skip to content

Commit 8e7841a

Browse files
committed
Profiler
1 parent 3217f18 commit 8e7841a

24 files changed

+345
-152
lines changed

perf/man-boy.sch

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
(set! fn (lambda () (A 10 (lambda () 1) (lambda () -1) (lambda () -1) (lambda () 1) (lambda () 0))))
1010

1111
(do ((i 0 (+ i 1)))
12-
((eqv? i 1000) 0)
12+
((eqv? i 100) 0)
1313
(fn))

src/bin/compiler.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ extern crate r5rs;
22

33
use std::io::{stdin, stdout, Write};
44

5-
use r5rs::reader::*;
6-
use r5rs::lexer::*;
75
use r5rs::compiler::*;
6+
use r5rs::lexer::*;
7+
use r5rs::reader::*;
88

99
fn main() {
1010
let mut buffer = String::new();

src/bin/interpreter.rs

+50-22
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ fn main() {
1717
#[cfg(not(target_os = "emscripten"))]
1818
mod not_web {
1919

20-
use std::env::args;
2120
use env_logger;
22-
use r5rs::reader::*;
21+
use r5rs::compiler::*;
2322
use r5rs::lexer::*;
23+
use r5rs::reader::*;
2424
use r5rs::vm::*;
25-
use r5rs::compiler::*;
25+
use std::env::{args, var};
2626

2727
use rustyline;
2828
use rustyline::error::ReadlineError;
@@ -31,14 +31,15 @@ mod not_web {
3131
env_logger::init().expect("logger");
3232

3333
let file = args().nth(1);
34+
let with_profiler = var("PROFILE").map(|s| !s.is_empty()).unwrap_or(false);
3435

3536
match file {
36-
Some(file) => run_file(file),
37+
Some(file) => run_file(file, with_profiler),
3738
None => run_repl(),
3839
}
3940
}
4041

41-
fn run_file(file_path: String) {
42+
fn run_file(file_path: String, with_profiler: bool) {
4243
use std::fs::File;
4344
use std::io::Read;
4445

@@ -50,16 +51,33 @@ mod not_web {
5051
};
5152
let environment = default_env();
5253
let mut last_value = None;
54+
let mut time_profiler = None;
55+
56+
{
57+
let callback = |result: Result<_, _>| {
58+
let should_continue = result.is_ok();
59+
last_value = Some(result);
60+
should_continue
61+
};
5362

54-
interpret(&source[..], &environment, |result| {
55-
let should_continue = result.is_ok();
56-
last_value = Some(result);
57-
should_continue
58-
});
63+
if with_profiler {
64+
let mut profiler = TimeProfiler::new();
65+
interpret(&source[..], &environment, &mut profiler, callback);
66+
time_profiler = Some(profiler);
67+
} else {
68+
interpret(&source[..], &environment, &mut NoopProfiler, callback);
69+
}
70+
}
5971

6072
if let Some(Err(err)) = last_value {
6173
println!("{:?}", err);
6274
}
75+
76+
let profile_report = time_profiler.map(|p| p.report()).unwrap_or(None);
77+
78+
if let Some(report) = profile_report {
79+
eprintln!("{}", report);
80+
}
6381
}
6482

6583
fn run_repl() {
@@ -76,22 +94,32 @@ mod not_web {
7694

7795
rl.add_history_entry(&line);
7896

79-
interpret(&line[..], &environment, |result: Result<Value, _>| {
80-
let need_more = result.is_ok();
81-
match result {
82-
Ok(v) => println!("{}", v.to_repl()),
83-
Err(e) => {
84-
println!("Error: {:?}", e);
97+
interpret(
98+
&line[..],
99+
&environment,
100+
&mut NoopProfiler,
101+
|result: Result<Value, _>| {
102+
let need_more = result.is_ok();
103+
match result {
104+
Ok(v) => println!("{}", v.to_repl()),
105+
Err(e) => {
106+
println!("Error: {:?}", e);
107+
}
85108
}
86-
}
87-
need_more
88-
})
109+
need_more
110+
},
111+
)
89112
}
90113
}
91114

92-
fn interpret<F>(source: &str, environment: &GcShared<Environment>, mut cb: F)
93-
where
115+
fn interpret<F, P>(
116+
source: &str,
117+
environment: &GcShared<Environment>,
118+
profiler: &mut P,
119+
mut cb: F,
120+
) where
94121
F: FnMut(Result<Value, ExecutionError>) -> bool,
122+
P: Profiler,
95123
{
96124
let mut tokens = match Tokens::new(source.chars()).collect() {
97125
Ok(tokens) => tokens,
@@ -122,7 +150,7 @@ mod not_web {
122150
};
123151

124152
debug!("Code:\n{:?}", bytecode);
125-
let should_continue = cb(exec(&bytecode, environment.clone()));
153+
let should_continue = cb(exec(&bytecode, environment.clone(), profiler));
126154

127155
if !should_continue {
128156
break;

src/bin/lexer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
extern crate r5rs;
22

3-
use std::io::{stdin, stdout, Write};
43
use r5rs::lexer::*;
4+
use std::io::{stdin, stdout, Write};
55

66
fn main() {
77
let mut buffer = String::new();

src/bin/reader.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
extern crate r5rs;
22

3-
use std::io::{stdin, stdout, Write};
43
use r5rs::lexer::*;
54
use r5rs::reader::*;
5+
use std::io::{stdin, stdout, Write};
66

77
fn main() {
88
let mut buffer = String::new();

src/bin/web.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ fn main() {
1313

1414
#[cfg(target_os = "emscripten")]
1515
mod web {
16-
use stdweb;
17-
use r5rs::reader::*;
16+
use r5rs::compiler::*;
1817
use r5rs::lexer::*;
18+
use r5rs::reader::*;
1919
use r5rs::vm::*;
20-
use r5rs::compiler::*;
20+
use stdweb;
2121

2222
pub fn main() {
2323
stdweb::initialize();

src/compiler/mod.rs

+70-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Convert expression(s) into bytecode
22
33
use std::collections::VecDeque;
4+
use std::fmt::Debug;
5+
use std::fmt::{self, Display};
46
use std::rc::Rc;
57

6-
use lexer::Num;
7-
use reader::{AbbreviationKind, Datum};
88
use self::keywords::is_syntactic_keyword;
99
use helpers::*;
10+
use lexer::Num;
11+
use reader::{AbbreviationKind, Datum};
1012

1113
mod keywords;
1214

@@ -68,6 +70,68 @@ pub enum Instruction {
6870
Eq,
6971
}
7072

73+
#[derive(Clone, Hash, PartialEq, Eq)]
74+
pub struct InstructionRef(&'static str);
75+
76+
impl<'a> From<&'a Instruction> for InstructionRef {
77+
fn from(instruction: &Instruction) -> InstructionRef {
78+
InstructionRef(instruction.variant_name())
79+
}
80+
}
81+
82+
impl Display for InstructionRef {
83+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84+
f.pad(&self.0)
85+
}
86+
}
87+
88+
impl Debug for InstructionRef {
89+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90+
f.write_str(self.0)
91+
}
92+
}
93+
94+
impl Instruction {
95+
// TODO: this should be a custome derive or something
96+
fn variant_name(&self) -> &'static str {
97+
use self::Instruction::*;
98+
99+
match *self {
100+
String(..) => "String",
101+
Character(..) => "Character",
102+
Boolean(..) => "Boolean",
103+
Symbol(..) => "Symbol",
104+
Integer(..) => "Integer",
105+
Float(..) => "Float",
106+
InvalidNumber => "InvalidNumber",
107+
Nil => "Nil",
108+
EmptyList => "EmpytList",
109+
Call(..) => "Call",
110+
Arity(..) => "Arity",
111+
Ret => "Ret",
112+
Branch(..) => "Branch",
113+
BranchIf(..) => "BranchIf",
114+
BranchUnless(..) => "BranchUnless",
115+
ROBranchIf(..) => "ROBranchIf",
116+
ROBranchUnless(..) => "ROBranchUnless",
117+
Lambda { .. } => "Lambda",
118+
Promise { .. } => "Promise",
119+
Pair => "Pair",
120+
List(..) => "List",
121+
Vector(..) => "Vector",
122+
Pop => "Pop",
123+
LoadVar(..) => "LoadVar",
124+
DefineVar(..) => "DefineVar",
125+
SetVar(..) => "SetVar",
126+
NewEnv => "NewEnv",
127+
PopEnv => "PopEnv",
128+
And => "And",
129+
Or => "Or",
130+
Eq => "Eq",
131+
}
132+
}
133+
}
134+
71135
type LambdaFormals = (Vec<String>, Option<String>);
72136

73137
#[derive(Debug, Eq, PartialEq)]
@@ -76,11 +140,11 @@ pub enum ParsingError {
76140
}
77141

78142
macro_rules! check {
79-
($check:expr, $err:expr) => (
143+
($check:expr, $err:expr) => {
80144
if !$check {
81145
return Err($err);
82146
}
83-
)
147+
};
84148
}
85149

86150
#[derive(Debug, Clone, Copy)]
@@ -97,9 +161,9 @@ pub fn compile_expression(d: Datum) -> Option<Vec<Instruction>> {
97161

98162
fn compile_expression_inner(d: Datum, tail: bool) -> Result<Vec<Instruction>, ParsingError> {
99163
macro_rules! simple_datum {
100-
($T:ident, $c:expr) => (
164+
($T:ident, $c:expr) => {
101165
Ok(vec![Instruction::$T($c)])
102-
)
166+
};
103167
}
104168

105169
// Simple cases

src/helpers.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::rc::Rc;
2-
use std::ops::Deref;
31
use std::fmt::{Display, Error as FmtError, Formatter};
2+
use std::ops::Deref;
3+
use std::rc::Rc;
44

55
pub trait Tuple2Helper<A, B, E> {
66
fn result(self) -> Result<(A, B), E>;
@@ -46,22 +46,26 @@ impl ResultHelper for bool {
4646
// Macros
4747
//
4848
macro_rules! ret_val {
49-
($x:expr) => (return ok_some!($x));
50-
($x:expr, $s:ident, $n:expr) => ({
49+
($x:expr) => {
50+
return ok_some!($x);
51+
};
52+
($x:expr, $s:ident, $n:expr) => {{
5153
$s.advance($n);
52-
return Ok(Some($x))
53-
});
54+
return Ok(Some($x));
55+
}};
5456
}
5557

5658
macro_rules! ok_some {
57-
($x:expr) => (Ok(Some($x)))
59+
($x:expr) => {
60+
Ok(Some($x))
61+
};
5862
}
5963

6064
//
6165
// Strings
6266
//
6367

64-
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
68+
#[derive(Clone, Debug, PartialEq, Hash, Eq, Default)]
6569
pub struct ImmutableString(Rc<String>);
6670

6771
impl Deref for ImmutableString {
@@ -102,7 +106,7 @@ impl<'a> borrow::Borrow<String> for &'a ImmutableString {
102106
}
103107
}
104108

105-
#[derive(Clone, Debug, PartialEq)]
109+
#[derive(Clone, Debug, PartialEq, Default)]
106110
pub struct CowString(Rc<String>);
107111

108112
impl CowString {

src/interpreter/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
use super::vm::{exec, Environment, ExecutionError, GcShared, Value};
2+
use compiler::compile_expression;
13
use lexer::Tokens;
24
use reader::parse_datum;
3-
use compiler::compile_expression;
4-
use super::vm::{exec, Environment, ExecutionError, GcShared, Value};
55

66
#[derive(Debug, PartialEq)]
77
pub enum InterpreterError {

0 commit comments

Comments
 (0)