Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Commit

Permalink
[benchmarks] add more benchmarks and some supporting functions
Browse files Browse the repository at this point in the history
  • Loading branch information
acfoltzer committed Apr 11, 2019
1 parent 3c3c38c commit 76fafb1
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 41 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
"lucet-wasi-sdk",
"lucetc",
"sightglass",
"benchmarks/lucet-microbenchmarks",
"benchmarks/lucet-benchmarks",
]
exclude = ["cranelift"]

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test: indent-check
-p lucet-idl \
-p lucet-wasi-sdk \
-p lucet-wasi \
-p lucet-microbenchmarks
-p lucet-benchmarks
cargo run -p lucet-wasi-fuzz -- --num-tests=3

.PHONY: fuzz
Expand All @@ -35,7 +35,7 @@ fuzz:

.PHONY: bench
bench:
cargo bench -p lucet-microbenchmarks
cargo bench -p lucet-benchmarks
make -C benchmarks/shootout clean
make -C benchmarks/shootout bench

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ Sightglass ships with a set of microbenchmarks called `shootout`. The scripts
to build the shootout tests with native and various versions of the Lucet
toolchain are in `/benchmarks/shootout`.

Furthermore, there is a suite of benchmarks of various Lucet runtime functions,
such as instance creation and teardown, in `/benchmarks/lucet-benchmarks`.

## Development Environment

### Operating System
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "lucet-microbenchmarks"
name = "lucet-benchmarks"
version = "0.1.0"
authors = ["Adam C. Foltzer <acfoltzer@fastly.com>"]
edition = "2018"
Expand All @@ -20,5 +20,5 @@ tempfile = "3.0"
bench = false

[[bench]]
name = "microbenchmarks"
name = "benchmarks"
harness = false
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use criterion::Criterion;
use lucet_microbenchmarks::{par_benches, seq_benches};
use lucet_benchmarks::{context_benches, par_benches, seq_benches};
use lucet_runtime::MmapRegion;

fn main() {
let mut c = Criterion::default().configure_from_args();

context_benches(&mut c);
seq_benches::<MmapRegion>(&mut c);
par_benches::<MmapRegion>(&mut c);

Expand Down
70 changes: 70 additions & 0 deletions benchmarks/lucet-benchmarks/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use criterion::Criterion;
use lucet_runtime_internals::context::{Context, ContextHandle};

/// Time the initialization of a context.
fn context_init(c: &mut Criterion) {
extern "C" fn f() {}

let mut stack = vec![0u64; 1024].into_boxed_slice();

c.bench_function("context_init", move |b| {
b.iter(|| {
let mut parent = ContextHandle::new();
ContextHandle::create_and_init(
&mut *stack,
&mut parent,
f as *const extern "C" fn(),
&[],
)
.unwrap();
})
});
}

/// Time the swap from an already-initialized context to a guest function and back.
fn context_swap_return(c: &mut Criterion) {
extern "C" fn f() {}

c.bench_function("context_swap_return", move |b| {
b.iter_batched(
|| {
let mut stack = vec![0u64; 1024].into_boxed_slice();
let mut parent = ContextHandle::new();
let child = ContextHandle::create_and_init(
&mut *stack,
&mut parent,
f as *const extern "C" fn(),
&[],
)
.unwrap();
(stack, parent, child)
},
|(stack, mut parent, child)| unsafe {
Context::swap(&mut parent, &child);
stack
},
criterion::BatchSize::PerIteration,
)
});
}

/// Time the call to sigprocmask as used in `Context::init()`.
fn context_sigprocmask(c: &mut Criterion) {
use nix::sys::signal;
c.bench_function("context_sigprocmask", |b| {
b.iter_batched(
|| signal::SigSet::empty(),
|mut sigset| {
signal::sigprocmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset))
.unwrap()
},
criterion::BatchSize::PerIteration,
)
});
}

pub fn context_benches(c: &mut Criterion) {
context_init(c);
context_swap_return(c);
context_sigprocmask(c);
}
14 changes: 14 additions & 0 deletions benchmarks/lucet-benchmarks/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mod context;
mod modules;
mod par;
mod seq;

pub use context::context_benches;
pub use par::par_benches;
pub use seq::seq_benches;

#[no_mangle]
extern "C" fn lucet_benchmarks_ensure_linked() {
lucet_runtime::lucet_internal_ensure_linked();
lucet_wasi::hostcalls::ensure_linked();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use lucet_runtime::vmctx::lucet_vmctx;
use lucet_runtime::Module;
use lucet_runtime_internals::module::MockModuleBuilder;
use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module};
use lucet_wasi_sdk::{CompileOpts, Lucetc};
use lucetc::{Bindings, LucetcOpts};
use std::path::Path;
Expand Down Expand Up @@ -28,6 +27,59 @@ pub fn null_mock() -> Arc<dyn Module> {
.build()
}

pub fn large_dense_heap_mock() -> Arc<dyn Module> {
extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

const HEAP_LEN: usize = 4 * 1024 * 1024;
const HEAP_SPEC: HeapSpec = HeapSpec {
reserved_size: HEAP_LEN as u64,
guard_size: 4 * 1024 * 1024,
initial_size: HEAP_LEN as u64,
max_size: None,
};

let mut heap = vec![0x00; HEAP_LEN];
(0..HEAP_LEN).into_iter().for_each(|i| {
heap[i] = (i % 256) as u8;
});

MockModuleBuilder::new()
.with_export_func(b"f", f as *const extern "C" fn())
.with_initial_heap(heap.as_slice())
.with_heap_spec(HEAP_SPEC)
.build()
}

pub fn large_sparse_heap_mock() -> Arc<dyn Module> {
extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

const HEAP_LEN: usize = 4 * 1024 * 1024;
const HEAP_SPEC: HeapSpec = HeapSpec {
reserved_size: HEAP_LEN as u64,
guard_size: 4 * 1024 * 1024,
initial_size: HEAP_LEN as u64,
max_size: None,
};

let mut heap = vec![0x00; HEAP_LEN];

// fill every eighth page with data
(0..HEAP_LEN)
.into_iter()
.step_by(4096 * 8)
.for_each(|base| {
for i in base..base + 4096 {
heap[i] = (i % 256) as u8;
}
});

MockModuleBuilder::new()
.with_export_func(b"f", f as *const extern "C" fn())
.with_initial_heap(heap.as_slice())
.with_heap_spec(HEAP_SPEC)
.build()
}

pub fn fib_mock() -> Arc<dyn Module> {
extern "C" fn f(_vmctx: *mut lucet_vmctx) {
fn fib(n: u32) -> u32 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn par_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
let module = DlModule::load(&so_file).unwrap();

let bench = criterion::ParameterizedBenchmark::new(
"par_instantiate hello",
format!("par_instantiate ({})", R::type_name()),
move |b, &num_threads| {
b.iter_batched(
setup,
Expand Down Expand Up @@ -116,15 +116,25 @@ fn par_run<R: RegionCreate + 'static>(
/// sure that the locks for signal handling don't unduly slow the program down with multiple
/// threads.
fn par_run_null<R: RegionCreate + 'static>(c: &mut Criterion) {
par_run::<R>("par_run_null", 1000, null_mock(), c);
par_run::<R>(
&format!("par_run_null ({})", R::type_name()),
1000,
null_mock(),
c,
);
}

/// Run a computation-heavy function in parallel.
///
/// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close
/// to linearly.
fn par_run_fib<R: RegionCreate + 'static>(c: &mut Criterion) {
par_run::<R>("par_run_fib", 1000, fib_mock(), c);
par_run::<R>(
&format!("par_run_fib ({})", R::type_name()),
1000,
fib_mock(),
c,
);
}

pub fn par_benches<R: RegionCreate + 'static>(c: &mut Criterion) {
Expand Down
Loading

0 comments on commit 76fafb1

Please sign in to comment.