Skip to content

Commit 4e2fb7e

Browse files
perfomance tuning grates: cache dispatcher + better grate_inflight handling. (#992)
* init * fix * fix2 * fix3 * Add comments for new code. Removed unused commented out code. * Fix typos
1 parent 0e8c9fd commit 4e2fb7e

File tree

4 files changed

+81
-36
lines changed

4 files changed

+81
-36
lines changed

src/cage/src/cage.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,25 @@ pub fn get_cage_or_debug_panic(cageid: u64, caller: &str) -> Option<Arc<Cage>> {
322322
result
323323
}
324324

325+
/// Borrows the `cageid` cage and applies a function `f` to it, return `Some(R)` or `None`
326+
/// depending on whether tha cage is out of range or does not exist.
327+
///
328+
/// Preferred over `get_cage` for synchronous operations where cloning the cage through an `Arc` is
329+
/// unnecessary.
330+
///
331+
/// SAFETY: Assumes that the cage cannot be removed while `f` is running (e.g. by ensuring
332+
/// `grate_inflight > 0`).
333+
pub fn with_cage<F, R>(cageid: u64, f: F) -> Option<R>
334+
where
335+
F: FnOnce(&Cage) -> R,
336+
{
337+
if cageid >= MAX_CAGEID as u64 {
338+
return None;
339+
}
340+
341+
unsafe { CAGE_MAP[cageid as usize].as_deref().map(f) }
342+
}
343+
325344
#[allow(static_mut_refs)]
326345
// SAFETY: This code is single-threaded during teardown, and no other
327346
// mutable or immutable references to `CAGE_MAP` exist while this call executes.

src/lind-boot/src/lind_wasmtime/host.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,43 @@
11
use crate::cli::CliOptions;
22
use std::sync::Arc;
3+
use wasmtime::TypedFunc;
34
use wasmtime_lind_common::LindEnviron;
45
use wasmtime_lind_multi_process::{LindCtx, LindHost};
56
use wasmtime_wasi_threads::WasiThreadsCtx;
67

8+
/// Function type for the `pass_fptr_to_wt` function used as an entry point for grate-run syscalls.
9+
pub type PassFptrTyped = TypedFunc<
10+
(
11+
u64,
12+
u64,
13+
u64,
14+
u64,
15+
u64,
16+
u64,
17+
u64,
18+
u64,
19+
u64,
20+
u64,
21+
u64,
22+
u64,
23+
u64,
24+
u64,
25+
),
26+
i32,
27+
>;
28+
729
/// The HostCtx host structure stores all relevant execution context objects:
830
/// `lind_environ`: argv/environ data served by the 4 host functions in lind-common;
931
/// `lind_fork_ctx`: the multi-process management structure, encapsulating fork/exec state;
1032
/// `wasi_threads`: which manages WASI thread-related capabilities.
33+
/// `pass_fptr_func`: the dispatcher function defined in the grate's WASM module. Cached after the
34+
/// first invocation.
1135
#[derive(Default, Clone)]
1236
pub struct HostCtx {
1337
pub lind_environ: Option<LindEnviron>,
1438
pub wasi_threads: Option<Arc<WasiThreadsCtx<HostCtx>>>,
1539
pub lind_fork_ctx: Option<LindCtx<HostCtx, CliOptions>>,
40+
pub pass_fptr_func: Option<PassFptrTyped>,
1641
}
1742

1843
impl HostCtx {
@@ -29,6 +54,7 @@ impl HostCtx {
2954
lind_environ: forked_lind_environ,
3055
lind_fork_ctx: forked_lind_fork_ctx,
3156
wasi_threads: self.wasi_threads.clone(),
57+
pass_fptr_func: None,
3258
}
3359
}
3460
}

src/lind-boot/src/lind_wasmtime/trampoline.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::lind_wasmtime::host::PassFptrTyped;
12
use crate::{cli::CliOptions, lind_wasmtime::host::HostCtx};
23
use anyhow::anyhow;
34
use threei::threei_const;
@@ -68,31 +69,27 @@ pub extern "C" fn grate_callback_trampoline(
6869
caller: instance,
6970
} = caller;
7071

71-
// Resolve the unified entry function once per call
72-
let entry_func = instance
73-
.host_state()
74-
.downcast_ref::<Instance>()
75-
.ok_or_else(|| anyhow!("bad host_state Instance"))?
76-
.get_export(&mut store, "pass_fptr_to_wt")
77-
.and_then(|f| f.into_func())
78-
.ok_or_else(|| anyhow!("missing export `pass_fptr_to_wt`"))?;
72+
let typed_func: PassFptrTyped = match store.data().pass_fptr_func.clone() {
73+
// Check if the dispatcher function is already cached.
74+
Some(f) => f,
75+
// Retrieve and store the dispatcher function. Done on the first syscall
76+
// invocation.
77+
None => {
78+
let entry_func = instance
79+
.host_state()
80+
.downcast_ref::<Instance>()
81+
.ok_or_else(|| anyhow!("bad host_state Instance"))?
82+
.get_export(&mut store, "pass_fptr_to_wt")
83+
.and_then(|f| f.into_func())
84+
.ok_or_else(|| anyhow!("missing export `pass_fptr_to_wt`"))?;
7985

80-
let typed_func = entry_func.typed::<(
81-
u64,
82-
u64,
83-
u64,
84-
u64,
85-
u64,
86-
u64,
87-
u64,
88-
u64,
89-
u64,
90-
u64,
91-
u64,
92-
u64,
93-
u64,
94-
u64,
95-
), i32>(&mut store)?;
86+
let typed = entry_func.typed(&mut store)?;
87+
88+
store.data_mut().pass_fptr_func = Some(typed.clone());
89+
90+
typed
91+
}
92+
};
9693

9794
// Call the entry function with all arguments and in grate function pointer
9895
typed_func.call(

src/threei/src/threei.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Threei (Three Interposition) module
22
use cage::memory::{check_addr_read, check_addr_rw};
3+
use cage::with_cage;
34
use core::panic;
45
use dashmap::DashMap;
56
use dashmap::DashSet;
@@ -495,21 +496,23 @@ pub fn make_syscall(
495496

496497
// Track this in-flight grate dispatch so cage_finalize() waits
497498
// for it to complete before removing the cage.
498-
if let Some(grate_cage) = cage::get_cage(grateid) {
499-
grate_cage
499+
//
500+
// If the cage is already dead, return early.
501+
let cage_dead = with_cage(grateid, |grate| {
502+
grate
500503
.grate_inflight
501504
.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
502-
// After incrementing, recheck is_dead: if the cage started
503-
// exiting between our earlier check and now, bail out.
504-
if grate_cage
505-
.is_dead
506-
.load(std::sync::atomic::Ordering::Acquire)
507-
{
508-
grate_cage
505+
if grate.is_dead.load(std::sync::atomic::Ordering::Acquire) {
506+
grate
509507
.grate_inflight
510508
.fetch_sub(1, std::sync::atomic::Ordering::AcqRel);
511509
return -(Errno::ESRCH as i32);
512510
}
511+
0
512+
});
513+
514+
if cage_dead != Some(0) {
515+
return -(Errno::ESRCH as i32);
513516
}
514517

515518
let grate_result = _call_grate_func(
@@ -530,11 +533,11 @@ pub fn make_syscall(
530533
);
531534

532535
// Decrement the in-flight counter now that the dispatch returned.
533-
if let Some(grate_cage) = cage::get_cage(grateid) {
534-
grate_cage
536+
with_cage(grateid, |grate| {
537+
grate
535538
.grate_inflight
536539
.fetch_sub(1, std::sync::atomic::Ordering::AcqRel);
537-
}
540+
});
538541

539542
if let Some(ret) = grate_result {
540543
return ret;

0 commit comments

Comments
 (0)