Files
extism/runtime/benches/bench.rs
zach a5edf58747 fix(kernel): improve performance after large allocations, add extism_plugin_reset to give users more control when dealing with large allocations (#627)
See https://github.com/extism/cpp-sdk/issues/15

- Limits a call to memset in the kernel to the size of the current
memory offset instead of the total size of memory.
- Adds `extism_plugin_reset` to the C API and `extism::Plugin::reset` to
Rust

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: zshipko <zshipko@users.noreply.github.com>
2023-12-12 13:56:34 -08:00

257 lines
7.5 KiB
Rust

use criterion::{criterion_group, criterion_main, Criterion};
use extism::*;
use extism_convert::Json;
const COUNT_VOWELS: &[u8] = include_bytes!("../../wasm/code.wasm");
const REFLECT: &[u8] = include_bytes!("../../wasm/reflect.wasm");
const ECHO: &[u8] = include_bytes!("../../wasm/echo.wasm");
const CONSUME: &[u8] = include_bytes!("../../wasm/consume.wasm");
host_fn!(hello_world (a: String) -> String { Ok(a) });
pub fn basic(c: &mut Criterion) {
let mut g = c.benchmark_group("basic");
g.measurement_time(std::time::Duration::from_secs(6));
g.bench_function("basic", |b| {
let data = "a".repeat(4096);
b.iter(|| {
let mut plugin = Plugin::new(COUNT_VOWELS, [], true).unwrap();
let _: serde_json::Value = plugin.call("count_vowels", &data).unwrap();
})
});
}
pub fn create_plugin(c: &mut Criterion) {
let mut g = c.benchmark_group("create");
g.noise_threshold(1.0);
g.significance_level(0.2);
g.bench_function("create_plugin", |b| {
b.iter(|| {
let _plugin = PluginBuilder::new(COUNT_VOWELS)
.with_wasi(true)
.build()
.unwrap();
})
});
}
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Count {
count: u32,
}
pub fn count_vowels(c: &mut Criterion) {
let mut g = c.benchmark_group("count_vowels");
g.sample_size(500);
let mut plugin = PluginBuilder::new(COUNT_VOWELS)
.with_wasi(true)
.build()
.unwrap();
let data = "a".repeat(4096);
g.bench_function("count_vowels(4096)", |b| {
b.iter(|| {
assert_eq!(
Count { count: 4096 },
plugin
.call::<_, Json<Count>>("count_vowels", &data)
.unwrap()
.0
);
})
});
}
pub fn consume(c: &mut Criterion) {
let mut g = c.benchmark_group("consume");
g.sample_size(500);
g.noise_threshold(1.0);
g.significance_level(0.2);
let mut plugin = PluginBuilder::new(CONSUME).build().unwrap();
for (i, elements) in [
b"a".repeat(65536),
b"a".repeat(65536 * 10),
b"a".repeat(65536 * 100),
]
.iter()
.enumerate()
{
g.throughput(criterion::Throughput::Bytes(elements.len() as u64));
g.bench_with_input(
format!("consume {} bytes", 10u32.pow(i as u32) * 65536),
elements,
|b, elems| {
b.iter(|| {
assert_eq!(b"", plugin.call::<_, &[u8]>("consume", &elems).unwrap());
});
},
);
}
}
pub fn echo(c: &mut Criterion) {
let mut g = c.benchmark_group("echo");
g.sample_size(500);
g.noise_threshold(1.0);
g.significance_level(0.2);
let mut plugin = PluginBuilder::new(ECHO).build().unwrap();
for (i, elements) in [
b"a".repeat(65536),
b"a".repeat(65536 * 10),
b"a".repeat(65536 * 100),
]
.iter()
.enumerate()
{
g.throughput(criterion::Throughput::Bytes(elements.len() as u64));
g.bench_with_input(
format!("echo {} bytes", 10u32.pow(i as u32) * 65536),
elements,
|b, elems| {
b.iter(|| {
plugin.call::<_, &[u8]>("echo", &elems).unwrap();
});
},
);
}
}
pub fn reflect(c: &mut Criterion) {
let mut g = c.benchmark_group("reflect");
let mut plugin = PluginBuilder::new(REFLECT)
.with_wasi(true)
.with_function(
"host_reflect",
[PTR],
[PTR],
UserData::default(),
hello_world,
)
.build()
.unwrap();
for (i, elements) in [
b"a".repeat(65536),
b"a".repeat(65536 * 10),
b"a".repeat(65536 * 100),
b"a".repeat(65536),
]
.iter()
.enumerate()
{
g.throughput(criterion::Throughput::Bytes(elements.len() as u64));
g.bench_with_input(
format!("{i}: reflect {} bytes", elements.len()),
elements,
|b, elems| {
b.iter(|| {
assert_eq!(elems, plugin.call::<_, &[u8]>("reflect", &elems).unwrap());
// plugin.reset().unwrap();
});
},
);
}
}
// This is an apples-to-apples comparison of a linked wasm "reflect" function to our host "reflect"
// function.
pub fn reflect_linked(c: &mut Criterion) {
let mut g = c.benchmark_group("reflect");
g.sample_size(500);
g.noise_threshold(1.0);
g.significance_level(0.2);
let manifest = Manifest::new([
Wasm::Data {
data: br#"(module
(import "extism:host/env" "length" (func $length (param i64) (result i64)))
(import "extism:host/env" "load_u64" (func $load_u64 (param i64) (result i64)))
(import "extism:host/env" "load_u8" (func $load_u8 (param i64) (result i32)))
(import "extism:host/env" "store_u64" (func $store_u64 (param i64 i64)))
(import "extism:host/env" "store_u8" (func $store_u8 (param i64 i32)))
(func (export "host_reflect") (param $extism_offset i64) (result i64)
(local $len i64)
(local $offset i64)
(local $len64 i64)
(local.set $offset (i64.const 0))
(local.set $len (call $length (local.get $extism_offset)))
(local.set $len64 (i64.shl (i64.shr_u (local.get $len) (i64.const 16)) (i64.const 16)))
(loop $to_upper
(call $store_u64
(i64.add (local.get $extism_offset) (local.get $offset))
(call $load_u64 (i64.add (local.get $extism_offset) (local.get $offset)))
)
(local.set $offset (i64.add (local.get $offset) (i64.const 8)))
(br_if $to_upper (i64.lt_u (local.get $offset) (local.get $len64)))
)
(if (i64.ne (local.get $len64) (local.get $len)) (then
(loop $to_upper
(call $store_u8
(i64.add (local.get $extism_offset) (local.get $offset))
(call $load_u8 (i64.add (local.get $extism_offset) (local.get $offset)))
)
(local.set $offset (i64.add (i64.const 1) (local.get $offset)))
(br_if $to_upper (i64.lt_u (local.get $offset) (local.get $len)))
)
))
local.get $extism_offset
)
)"#
.to_vec(),
meta: WasmMetadata {
name: Some("extism:host/user".to_string()),
hash: None,
},
},
Wasm::Data {
data: REFLECT.to_vec(),
meta: WasmMetadata {
name: Some("main".to_string()),
hash: None,
},
},
]);
let mut plugin = PluginBuilder::new(manifest)
.with_wasi(true)
.build()
.unwrap();
for (i, elements) in [
b"a".repeat(65536),
b"a".repeat(65536 * 10),
b"a".repeat(65536 * 100),
]
.iter()
.enumerate()
{
g.throughput(criterion::Throughput::Bytes(elements.len() as u64));
g.bench_with_input(
format!("reflect_linked {} bytes", 10u32.pow(i as u32) * 65536),
elements,
|b, elems| {
b.iter(|| {
assert_eq!(elems, plugin.call::<_, &[u8]>("reflect", &elems).unwrap());
});
},
);
}
}
criterion_group!(
benches,
consume,
echo,
reflect,
reflect_linked,
basic,
create_plugin,
count_vowels
);
criterion_main!(benches);