Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 51 additions & 29 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,9 @@ use new_nu_parser::resolver::Resolver;
use new_nu_parser::typechecker::Typechecker;

/// Files in benches/nu/ we want to benchmark (without .nu suffix)
const BENCHMARKS: &[&str] = &[
"def",
"if",
"combined",
"combined10",
"combined100",
"combined1000",
"int100",
];
const BENCHMARKS: &[&str] = &["def", "if", "combined", "int100"];

const ITERATIONS: &[usize] = &[1, 10, 100, 1_000, 10_000];

enum Stage {
Lex,
Expand Down Expand Up @@ -53,12 +47,21 @@ fn setup_compiler(
do_parse: bool,
do_resolve: bool,
do_typecheck: bool,
count: usize,
) -> Result<(Compiler, usize), String> {
let mut compiler = Compiler::new();
let span_offset = compiler.span_offset();

let contents = std::fs::read(fname).map_err(|_| format!("Cannot find file {fname}"))?;
compiler.add_file(&fname, &contents);
let mut repeated_contents = String::new();
for i in 0..count {
let contents =
String::from_utf8(contents.clone()).expect("{fname} does not contain valid UTF-8");
repeated_contents += &contents.replace("_BENCH_ITERATION", &i.to_string());
}
let contents = repeated_contents.as_bytes().to_vec();

compiler.add_file(fname, &contents);

let (tokens, err) = lex(&contents, span_offset);
if let Err(e) = err {
Expand Down Expand Up @@ -218,18 +221,29 @@ fn parse_nu_old(engine_state: &EngineState, contents: &[u8]) {
assert!(working_set.parse_errors.is_empty());
}

fn compiler_benchmarks() -> impl IntoBenchmarks {
fn compiler_benchmarks(count: usize) -> Vec<Benchmark> {
let mut benchmarks: Vec<Benchmark> = vec![];

for bench_name in BENCHMARKS {
for stage in STAGES {
let bench_file = format!("benches/nu/{bench_name}.nu");
let bench_contents =
std::fs::read(&bench_file).expect(&format!("Cannot find file {bench_file}"));
let bench_contents = std::fs::read(&bench_file)
.unwrap_or_else(|_| panic!("Cannot find file {bench_file}"));
let mut repeated_bench_contents = String::new();

for i in 0..count {
let bench_contents = String::from_utf8(bench_contents.clone())
.expect("{bench_file} does not contain valid UTF-8 strings");

repeated_bench_contents +=
&bench_contents.replace("_BENCH_ITERATION", &i.to_string());
}

let bench_contents: Vec<_> = repeated_bench_contents.as_bytes().to_vec();

let bench = match stage {
Stage::Lex => {
let name = format!("{bench_name}_lex");
let name = format!("{bench_name}_lex_iter{count}");
benchmark_fn(name, move |b| {
let contents = bench_contents.clone();
b.iter(move || {
Expand All @@ -243,10 +257,10 @@ fn compiler_benchmarks() -> impl IntoBenchmarks {
})
}
Stage::Parse => {
let name = format!("{bench_name}_parse");
let name = format!("{bench_name}_parse_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_init, span_offset) =
setup_compiler(&bench_file, false, false, false)
setup_compiler(&bench_file, false, false, false, count)
.expect("Error setting up compiler");
let contents = bench_contents.clone();
let (tokens, err) = lex(&contents, span_offset);
Expand All @@ -259,52 +273,52 @@ fn compiler_benchmarks() -> impl IntoBenchmarks {
})
}
Stage::Resolve => {
let name = format!("{bench_name}_resolve");
let name = format!("{bench_name}_resolve_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_parsed, _) =
setup_compiler(&bench_file.clone(), true, false, false)
setup_compiler(&bench_file.clone(), true, false, false, count)
.expect("Error setting up compiler");
b.iter(move || resolve(compiler_def_parsed.clone(), false))
})
}
Stage::ResolveMerge => {
let name = format!("{bench_name}_resolve_merge");
let name = format!("{bench_name}_resolve_merge_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_parsed, _) =
setup_compiler(&bench_file.clone(), true, false, false)
setup_compiler(&bench_file.clone(), true, false, false, count)
.expect("Error setting up compiler");
b.iter(move || resolve(compiler_def_parsed.clone(), true))
})
}
Stage::Typecheck => {
let name = format!("{bench_name}_typecheck");
let name = format!("{bench_name}_typecheck_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_parsed, _) =
setup_compiler(&bench_file.clone(), true, true, false)
setup_compiler(&bench_file.clone(), true, true, false, count)
.expect("Error setting up compiler");
b.iter(move || typecheck(compiler_def_parsed.clone(), false))
})
}
Stage::TypecheckMerge => {
let name = format!("{bench_name}_typecheck_merge");
let name = format!("{bench_name}_typecheck_merge_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_parsed, _) =
setup_compiler(&bench_file.clone(), true, true, false)
setup_compiler(&bench_file.clone(), true, true, false, count)
.expect("Error setting up compiler");
b.iter(move || typecheck(compiler_def_parsed.clone(), true))
})
}
Stage::Compile => {
let name = format!("{bench_name}_compile");
let name = format!("{bench_name}_compile_iter{count}");
benchmark_fn(name, move |b| {
let (compiler_def_init, span_offset) =
setup_compiler(&bench_file.clone(), false, false, false)
setup_compiler(&bench_file.clone(), false, false, false, count)
.expect("Error setting up compiler");
b.iter(move || compile(compiler_def_init.clone(), span_offset))
})
}
Stage::Nu => {
let name = format!("{bench_name}_nu_old");
let name = format!("{bench_name}_nu_old_iter{count}");
benchmark_fn(name, move |b| {
let engine_state = make_engine_state();
let contents = bench_contents.clone();
Expand All @@ -317,13 +331,21 @@ fn compiler_benchmarks() -> impl IntoBenchmarks {
}
}

benchmarks.push(benchmark_fn(format!("nu_old_empty"), move |b| {
benchmarks.push(benchmark_fn("nu_old_empty".to_string(), move |b| {
let engine_state = make_engine_state();
b.iter(move || parse_nu_old(&engine_state, &[]))
}));

benchmarks
}

tango_benchmarks!(compiler_benchmarks());
fn repeated_compiler_benchmarks() -> impl IntoBenchmarks {
ITERATIONS
.iter()
.cloned()
.flat_map(compiler_benchmarks)
.collect::<Vec<_>>()
}

tango_benchmarks!(repeated_compiler_benchmarks());
tango_main!();
9 changes: 6 additions & 3 deletions benches/nu/combined.nu
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
def foo [ x: bool, y: int, z: list<list<int>> ] {
def bar [ y: int ] {
# the benchmarking tool replicates the content internally and causes conflicting
# definitions to arise
# _BENCH_ITERATION will be replaced by the iteration number internally
def foo_BENCH_ITERATION [ x: bool, y: int, z: list<list<int>> ] {
def bar_BENCH_ITERATION [ y: int ] {
$y * 10 * (($y * 10 + $y * 10) - ($y * 10 * 10))
}

def baz [ y: int ] {
def baz_BENCH_ITERATION [ y: int ] {
$y * 20 * (($y * 20 + $y * 20) - ($y * 20 * 20))
}

Expand Down
Loading