25fb843c40
The prior commit switched the recipe to `[source] path = "source"`, but .gitignore:77 still listed `local/recipes/shells/brush/source` (a leftover from when brush was a transient upstream git fetch), so the vendored tree was not tracked — a fresh clone would have no brush source and the build would fail. Drop that ignore line and commit the vendored working tree (reubeno/brush @ 897b373e, with the Redox port patches pre-applied). brush is now a durable local fork like the other path=source recipes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
175 lines
5.8 KiB
Rust
175 lines
5.8 KiB
Rust
//! Benchmarks for the brush-shell crate.
|
|
|
|
#![allow(missing_docs)]
|
|
#![allow(clippy::unwrap_used)]
|
|
|
|
#[cfg(unix)]
|
|
mod unix {
|
|
use brush_builtins::ShellBuilderExt;
|
|
use brush_parser::SourceSpan;
|
|
use criterion::Criterion;
|
|
use std::hint::black_box;
|
|
|
|
async fn instantiate_shell() -> brush_core::Shell {
|
|
brush_core::Shell::builder()
|
|
.default_builtins(brush_builtins::BuiltinSet::BashMode)
|
|
.build()
|
|
.await
|
|
.unwrap()
|
|
}
|
|
|
|
async fn instantiate_shell_with_init_scripts() -> brush_core::Shell {
|
|
brush_core::Shell::builder()
|
|
.interactive(true)
|
|
.read_commands_from_stdin(true)
|
|
.default_builtins(brush_builtins::BuiltinSet::BashMode)
|
|
.build()
|
|
.await
|
|
.unwrap()
|
|
}
|
|
|
|
async fn run_one_command(shell: &mut brush_core::Shell, command: &str) {
|
|
let _ = shell
|
|
.run_string(
|
|
command.to_owned(),
|
|
&brush_core::SourceInfo::default(),
|
|
&shell.default_exec_params(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
async fn expand_string(shell: &mut brush_core::Shell, s: &str) {
|
|
let params = shell.default_exec_params();
|
|
let _ = shell.basic_expand_string(¶ms, s).await.unwrap();
|
|
}
|
|
|
|
fn eval_arithmetic_expr(shell: &mut brush_core::Shell, expr: &str) {
|
|
let parsed_expr = brush_parser::arithmetic::parse(expr).unwrap();
|
|
let _ = shell.eval_arithmetic(&parsed_expr).unwrap();
|
|
}
|
|
|
|
/// This function defines core shell benchmarks.
|
|
pub(crate) fn criterion_benchmark(c: &mut Criterion) {
|
|
// Construct a runtime for us to run async code on.
|
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap();
|
|
|
|
// Benchmark shell instantiation.
|
|
c.bench_function("instantiate_shell", |b| {
|
|
b.to_async(&rt).iter(|| black_box(instantiate_shell()));
|
|
});
|
|
c.bench_function("instantiate_shell_with_init_scripts", |b| {
|
|
b.to_async(&rt)
|
|
.iter(|| black_box(instantiate_shell_with_init_scripts()));
|
|
});
|
|
|
|
// Benchmark: cloning a shell object.
|
|
let shell = rt.block_on(instantiate_shell());
|
|
c.bench_function("clone_shell_object", |b| {
|
|
b.iter(|| black_box(shell.clone()));
|
|
});
|
|
|
|
// Benchmark: parsing and evaluating an arithmetic expression..
|
|
let shell = rt.block_on(instantiate_shell());
|
|
c.bench_function("eval_arithmetic", |b| {
|
|
b.iter_batched_ref(
|
|
|| shell.clone(),
|
|
|s| eval_arithmetic_expr(s, "3 + 10 * 2"),
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
|
|
// Benchmark: running the echo built-in command.
|
|
let shell = rt.block_on(instantiate_shell());
|
|
c.bench_function("run_echo_builtin_command", |b| {
|
|
b.iter_batched_ref(
|
|
|| shell.clone(),
|
|
|s| rt.block_on(run_one_command(s, "echo 'Hello, world!' >/dev/null")),
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
|
|
// Benchmark: running an external command.
|
|
// let shell = rt.block_on(instantiate_shell());
|
|
// c.bench_function("run_one_external_command", |b| {
|
|
// b.iter_batched_ref(
|
|
// || shell.clone(),
|
|
// |s| {
|
|
// rt.block_on(run_one_command(
|
|
// s,
|
|
// "/usr/bin/echo 'Hello, world!' >/dev/null",
|
|
// ));
|
|
// },
|
|
// criterion::BatchSize::SmallInput,
|
|
// );
|
|
// });
|
|
|
|
// Benchmark: word expansion.
|
|
let shell = rt.block_on(instantiate_shell());
|
|
c.bench_function("expand_one_string", |b| {
|
|
b.iter_batched_ref(
|
|
|| shell.clone(),
|
|
|s| rt.block_on(expand_string(s, "My version is ${BASH_VERSINFO[@]}")),
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
|
|
// Benchmark: function invocation.
|
|
let mut shell = rt.block_on(instantiate_shell());
|
|
shell.define_func(
|
|
String::from("testfunc"),
|
|
brush_parser::ast::FunctionDefinition {
|
|
fname: String::from("testfunc").into(),
|
|
body: brush_parser::ast::FunctionBody(
|
|
brush_parser::ast::CompoundCommand::BraceGroup(
|
|
brush_parser::ast::BraceGroupCommand {
|
|
list: brush_parser::ast::CompoundList(vec![]),
|
|
loc: SourceSpan::default(),
|
|
},
|
|
),
|
|
None,
|
|
),
|
|
},
|
|
&brush_core::SourceInfo::default(),
|
|
);
|
|
c.bench_function("function_call", |b| {
|
|
b.iter_batched_ref(
|
|
|| shell.clone(),
|
|
|s| {
|
|
rt.block_on(run_one_command(s, "testfunc"));
|
|
},
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
|
|
// Benchmark: for loop.
|
|
let shell = rt.block_on(instantiate_shell());
|
|
c.bench_function("for_loop", |b| {
|
|
b.iter_batched_ref(
|
|
|| shell.clone(),
|
|
|s| {
|
|
rt.block_on(run_one_command(s, "for ((i = 0; i < 10; i++)); do :; done"));
|
|
},
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
criterion::criterion_group! {
|
|
name = benches;
|
|
config = criterion::Criterion::default()
|
|
.measurement_time(std::time::Duration::from_secs(10));
|
|
targets = unix::criterion_benchmark
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
criterion::criterion_main!(benches);
|
|
|
|
#[cfg(not(unix))]
|
|
fn main() {}
|