#![allow(clippy::expect_used)]
use core::hint::black_box;
use criterion::BenchmarkId;
use criterion::Criterion;
use criterion::Throughput;
use criterion::criterion_group;
use criterion::criterion_main;
use polyplug_abi::AbiError;
use polyplug_abi::Array;
use polyplug_abi::CallArena;
use polyplug_abi::DependencyInfo;
use polyplug_abi::GuestContractHandle;
use polyplug_abi::GuestContractInterface;
use polyplug_abi::HostApi;
use polyplug_abi::HostContractInstance;
use polyplug_abi::HostContractInterface;
use polyplug_abi::PluginDescriptor;
use polyplug_abi::ffi::polyplug_host_alloc;
use polyplug_abi::ffi::polyplug_host_free;
use polyplug_utils::BundleId;
unsafe extern "C" fn stub_register_guest(
_this: *const HostApi,
_descriptor: *const PluginDescriptor,
_interface: *const GuestContractInterface,
out_err: *mut AbiError,
) {
if !out_err.is_null() {
unsafe { out_err.write(AbiError::ok()) };
}
}
unsafe extern "C" fn stub_find(_this: *const HostApi, _id: u64, _ver: u32) -> GuestContractHandle {
GuestContractHandle::null()
}
unsafe extern "C" fn stub_find_all(
_this: *const HostApi,
_id: u64,
_ver: u32,
) -> Array<GuestContractHandle> {
Array::empty()
}
unsafe extern "C" fn stub_resolve_guest(
_this: *const HostApi,
_handle: GuestContractHandle,
) -> *const GuestContractInterface {
core::ptr::null()
}
unsafe extern "C" fn stub_get_host_contract(
_this: *const HostApi,
_id: u64,
_ver: u32,
) -> HostContractInstance {
HostContractInstance::null()
}
unsafe extern "C" fn stub_resolve_host_interface(
_this: *const HostApi,
_id: u64,
_ver: u32,
) -> *const HostContractInterface {
core::ptr::null()
}
unsafe extern "C" fn stub_list_bundles(_this: *const HostApi) -> Array<BundleId> {
Array::empty()
}
unsafe extern "C" fn stub_get_deps(_this: *const HostApi) -> Array<DependencyInfo> {
Array::empty()
}
unsafe extern "C" fn stub_load(
_this: *const HostApi,
_p: *const u8,
_l: usize,
out_err: *mut AbiError,
) {
if !out_err.is_null() {
unsafe { out_err.write(AbiError::ok()) };
}
}
unsafe extern "C" fn stub_register_host(
_this: *const HostApi,
_interface: *const HostContractInterface,
out_err: *mut AbiError,
) {
if !out_err.is_null() {
unsafe { out_err.write(AbiError::ok()) };
}
}
unsafe extern "C" fn stub_register_loader(
_this: *const HostApi,
_loader: *mut core::ffi::c_void,
out_err: *mut AbiError,
) {
if !out_err.is_null() {
unsafe { out_err.write(AbiError::ok()) };
}
}
unsafe extern "C" fn stub_get_last_error(
_this: *const HostApi,
_buf: *mut u8,
_len: usize,
) -> usize {
0
}
unsafe extern "C" fn stub_get_len(_this: *const HostApi) -> usize {
0
}
unsafe extern "C" fn stub_unload(
_this: *const HostApi,
_bundle_id: BundleId,
out_err: *mut AbiError,
) {
if !out_err.is_null() {
unsafe { out_err.write(AbiError::ok()) };
}
}
unsafe extern "C" fn arena_alloc(_this: *const HostApi, size: usize, align: usize) -> *mut u8 {
polyplug_host_alloc(size, align)
}
unsafe extern "C" fn arena_free(_this: *const HostApi, ptr: *mut u8, size: usize, align: usize) {
unsafe { polyplug_host_free(ptr, size, align) };
}
fn arena_host_api() -> HostApi {
HostApi {
runtime: core::ptr::null_mut(),
register_guest_contract: stub_register_guest,
alloc: arena_alloc,
free: arena_free,
find_guest_contract: stub_find,
find_all_guest_contracts: stub_find_all,
resolve_guest_contract: stub_resolve_guest,
get_host_contract: stub_get_host_contract,
resolve_host_contract_interface: stub_resolve_host_interface,
list_bundles: stub_list_bundles,
get_dependencies: stub_get_deps,
load_bundle: stub_load,
reload_bundle: stub_load,
register_host_contract: stub_register_host,
register_loader: stub_register_loader,
get_last_error: stub_get_last_error,
get_error_len: stub_get_len,
unload_bundle: stub_unload,
log: stub_host_log,
create_guest_instance: stub_create_guest_instance,
destroy_guest_instance: stub_destroy_guest_instance,
revision_counter: stub_revision_counter,
reserved: core::ptr::null(),
}
}
const PRIMARY_BYTES: usize = 4096;
fn bench_primary_alloc(c: &mut Criterion) {
let host: HostApi = arena_host_api();
let mut buf: Vec<u8> = vec![0_u8; PRIMARY_BYTES];
let mut arena: CallArena = CallArena::new(&mut buf, &host as *const HostApi);
let mut group: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> =
c.benchmark_group("call_arena");
group.throughput(Throughput::Elements(1));
group.bench_function(BenchmarkId::new("primary", "alloc_64"), |b| {
b.iter(|| {
arena.reset();
let p: *mut u8 = black_box(arena.alloc(black_box(64), black_box(8)));
black_box(p);
});
});
group.finish();
}
fn bench_reset_primary_only(c: &mut Criterion) {
let host: HostApi = arena_host_api();
let mut buf: Vec<u8> = vec![0_u8; PRIMARY_BYTES];
let mut arena: CallArena = CallArena::new(&mut buf, &host as *const HostApi);
let _ = arena.alloc(64, 8);
let mut group: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> =
c.benchmark_group("call_arena");
group.throughput(Throughput::Elements(1));
group.bench_function(BenchmarkId::new("reset", "primary_only"), |b| {
b.iter(|| {
arena.reset();
black_box(&arena.cur);
});
});
group.finish();
}
fn bench_overflow_reuse(c: &mut Criterion) {
let host: HostApi = arena_host_api();
let host_ptr: *const HostApi = &host as *const HostApi;
const OVERFLOW_ALLOC: usize = PRIMARY_BYTES + 1024;
let mut group: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> =
c.benchmark_group("call_arena");
group.throughput(Throughput::Elements(1));
group.bench_function(BenchmarkId::new("overflow", "cold_first_block"), |b| {
b.iter(|| {
let mut buf: [u8; 16] = [0_u8; 16];
let mut arena: CallArena = CallArena::new(&mut buf, host_ptr);
let p: *mut u8 = black_box(arena.alloc(black_box(OVERFLOW_ALLOC), black_box(8)));
black_box(p);
});
});
{
let mut buf: [u8; 16] = [0_u8; 16];
let mut arena: CallArena = CallArena::new(&mut buf, host_ptr);
let _ = arena.alloc(OVERFLOW_ALLOC, 8);
group.bench_function(BenchmarkId::new("overflow", "warm_reuse"), |b| {
b.iter(|| {
arena.reset();
let p: *mut u8 = black_box(arena.alloc(black_box(OVERFLOW_ALLOC), black_box(8)));
black_box(p);
});
});
}
group.finish();
}
fn bench_per_call(c: &mut Criterion) {
let host: HostApi = arena_host_api();
let host_ptr: *const HostApi = &host as *const HostApi;
let mut buf: Vec<u8> = vec![0_u8; PRIMARY_BYTES];
let mut arena: CallArena = CallArena::new(&mut buf, host_ptr);
let payload_sizes: [usize; 2] = [64, 65536];
let mut group: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> =
c.benchmark_group("call_arena");
group.throughput(Throughput::Elements(1));
for &payload in &payload_sizes {
arena.reset();
let _ = arena.alloc(16, 8);
let _ = arena.alloc(payload, 8);
let _ = arena.alloc(32, 8);
group.bench_with_input(BenchmarkId::new("per_call", payload), &payload, |b, &p| {
b.iter(|| {
arena.reset();
let h: *mut u8 = black_box(arena.alloc(black_box(16), black_box(8)));
let body: *mut u8 = black_box(arena.alloc(black_box(p), black_box(8)));
let t: *mut u8 = black_box(arena.alloc(black_box(32), black_box(8)));
black_box((h, body, t));
});
});
}
group.finish();
}
criterion_group!(
benches,
bench_primary_alloc,
bench_reset_primary_only,
bench_overflow_reuse,
bench_per_call,
);
criterion_main!(benches);
unsafe extern "C" fn stub_host_log(
_this: *const polyplug_abi::HostApi,
_level: u32,
_scope: polyplug_abi::StringView,
_message: polyplug_abi::StringView,
) {
}
unsafe extern "C" fn stub_create_guest_instance(
_this: *const polyplug_abi::HostApi,
_interface: *const polyplug_abi::GuestContractInterface,
_args: *const core::ffi::c_void,
out_instance: *mut polyplug_abi::GuestContractInstance,
) {
if !out_instance.is_null() {
unsafe { out_instance.write(polyplug_abi::GuestContractInstance::null()) };
}
}
unsafe extern "C" fn stub_destroy_guest_instance(
_this: *const polyplug_abi::HostApi,
_interface: *const polyplug_abi::GuestContractInterface,
_instance: polyplug_abi::GuestContractInstance,
) {
}
unsafe extern "C" fn stub_revision_counter(_this: *const polyplug_abi::HostApi) -> *const u64 {
core::ptr::null()
}