2026-02-06 11:25:37 +00:00
|
|
|
/// Backoff policy for worker threads when idle.
|
|
|
|
|
///
|
|
|
|
|
/// Workers spin → yield → sleep with increasing delay when no work is available.
|
|
|
|
|
pub struct BackoffPolicy {
|
|
|
|
|
/// Number of idle ticks before switching from spin to yield.
|
|
|
|
|
pub spin_threshold: u32,
|
|
|
|
|
/// Number of idle ticks before switching from yield to sleep.
|
|
|
|
|
pub yield_threshold: u32,
|
|
|
|
|
/// Microseconds added per tick beyond the yield threshold.
|
|
|
|
|
pub sleep_increment_us: u64,
|
|
|
|
|
/// Maximum sleep duration in microseconds.
|
|
|
|
|
pub sleep_max_us: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for BackoffPolicy {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
spin_threshold: 64,
|
|
|
|
|
yield_threshold: 256,
|
|
|
|
|
sleep_increment_us: 50,
|
|
|
|
|
sleep_max_us: 1000,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-13 07:11:24 +00:00
|
|
|
/// What to do when a bounded mailbox is full.
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
pub enum MailboxOverflow {
|
|
|
|
|
/// Drop the incoming message (newest). The message is silently discarded.
|
|
|
|
|
DropNewest,
|
|
|
|
|
/// Drop the oldest message in the queue to make room for the new one.
|
|
|
|
|
DropOldest,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-06 11:25:37 +00:00
|
|
|
/// The tunable settings for the runtime.
|
|
|
|
|
pub struct RuntimeConfig {
|
|
|
|
|
pub max_actors: usize,
|
2026-02-10 07:35:58 +00:00
|
|
|
pub channel_buffer_size: usize,
|
2026-02-06 11:25:37 +00:00
|
|
|
pub num_threads: usize,
|
|
|
|
|
pub backoff_policy: BackoffPolicy,
|
2026-02-13 07:11:24 +00:00
|
|
|
/// Maximum messages processed per actor per tick.
|
|
|
|
|
/// Prevents a single actor with a large mailbox from starving others.
|
|
|
|
|
/// `0` means unlimited (drain entire mailbox).
|
|
|
|
|
pub actor_message_budget: usize,
|
|
|
|
|
/// Default per-actor mailbox capacity. `0` means unbounded (no limit).
|
|
|
|
|
/// When non-zero, `mailbox_overflow` controls what happens when the mailbox is full.
|
|
|
|
|
pub default_mailbox_capacity: usize,
|
|
|
|
|
/// Overflow policy for bounded mailboxes. Ignored when `default_mailbox_capacity` is 0.
|
|
|
|
|
pub mailbox_overflow: MailboxOverflow,
|
2026-02-06 11:25:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 8kB for the `Box<..>` before counting the rest of the memory
|
|
|
|
|
const DEFAULT_MAX_ACTORS: usize = 1_000;
|
|
|
|
|
|
2026-02-10 07:35:58 +00:00
|
|
|
/// Pre-allocated ring buffer capacity for each channel (transfer, spawn, inbox).
|
|
|
|
|
/// When the ring is full, messages overflow into an unbounded backup queue.
|
|
|
|
|
const DEFAULT_CHANNEL_BUFFER_SIZE: usize = 1_000;
|
2026-02-06 11:25:37 +00:00
|
|
|
|
2026-02-13 07:11:24 +00:00
|
|
|
/// Default per-actor message budget per tick.
|
|
|
|
|
/// Inspired by BEAM's reduction budget (4000) and tokio's cooperative budget (128).
|
|
|
|
|
/// 64 is a good default: high enough for throughput, low enough for fairness.
|
|
|
|
|
const DEFAULT_ACTOR_MESSAGE_BUDGET: usize = 64;
|
|
|
|
|
|
2026-02-06 11:25:37 +00:00
|
|
|
impl Default for RuntimeConfig {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
max_actors: DEFAULT_MAX_ACTORS,
|
2026-02-10 07:35:58 +00:00
|
|
|
channel_buffer_size: DEFAULT_CHANNEL_BUFFER_SIZE,
|
2026-02-06 11:25:37 +00:00
|
|
|
num_threads: 1,
|
|
|
|
|
backoff_policy: BackoffPolicy::default(),
|
2026-02-13 07:11:24 +00:00
|
|
|
actor_message_budget: DEFAULT_ACTOR_MESSAGE_BUDGET,
|
|
|
|
|
default_mailbox_capacity: 0,
|
|
|
|
|
mailbox_overflow: MailboxOverflow::DropNewest,
|
2026-02-06 11:25:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|