Skip to main content

moirai_core/executor/
config.rs

1//! Configuration settings for executor behavior.
2
3use crate::platform::String;
4
5// Memory pool size constants
6const KILOBYTE: usize = 1024;
7const MEGABYTE: usize = 1024 * KILOBYTE;
8/// Default capacity for the small object allocation pool.
9pub const SMALL_POOL_SIZE: usize = 64 * KILOBYTE;
10/// Default capacity for the medium object allocation pool.
11pub const MEDIUM_POOL_SIZE: usize = MEGABYTE;
12/// Default capacity for the large object allocation pool.
13pub const LARGE_POOL_SIZE: usize = 16 * MEGABYTE;
14
15/// Default bound for the global task queue (tasks, not bytes). Sized for
16/// burst absorption across all workers before producers observe backpressure.
17pub const DEFAULT_GLOBAL_QUEUE_CAPACITY: usize = 8192;
18/// Default bound for each worker's local queue (tasks, not bytes). Small so
19/// idle workers can steal instead of one worker hoarding a deep queue.
20pub const DEFAULT_LOCAL_QUEUE_CAPACITY: usize = 256;
21
22/// Configuration settings for executor behavior and performance characteristics.
23///
24/// This struct encapsulates all tunable parameters that affect executor operation,
25/// including thread pool sizes, queue capacities, and various performance optimizations.
26#[allow(clippy::module_name_repetitions)]
27pub struct ExecutorConfig {
28    /// Number of worker threads for parallel tasks
29    pub worker_threads: usize,
30    /// Number of threads dedicated to async tasks
31    pub async_threads: usize,
32    /// Maximum size of the global task queue
33    pub max_global_queue_size: usize,
34    /// Maximum size of per-thread local queues
35    pub max_local_queue_size: usize,
36    /// Thread name prefix for worker threads
37    pub thread_name_prefix: String,
38    /// Whether to enable NUMA-aware thread placement
39    #[cfg(feature = "numa")]
40    pub numa_aware: bool,
41    /// Whether to enable metrics collection
42    #[cfg(feature = "metrics")]
43    pub enable_metrics: bool,
44    /// Task preemption configuration
45    pub preemption: PreemptionConfig,
46    /// Memory management configuration
47    pub memory: MemoryConfig,
48    /// Task cleanup configuration
49    pub cleanup: CleanupConfig,
50}
51
52impl Default for ExecutorConfig {
53    fn default() -> Self {
54        Self {
55            worker_threads: super::num_cpus(),
56            async_threads: (super::num_cpus() / 4).max(1),
57            max_global_queue_size: DEFAULT_GLOBAL_QUEUE_CAPACITY,
58            max_local_queue_size: DEFAULT_LOCAL_QUEUE_CAPACITY,
59            thread_name_prefix: "moirai-worker".into(),
60            #[cfg(feature = "numa")]
61            numa_aware: true,
62            #[cfg(feature = "metrics")]
63            enable_metrics: true,
64            preemption: PreemptionConfig::default(),
65            memory: MemoryConfig::default(),
66            cleanup: CleanupConfig::default(),
67        }
68    }
69}
70
71/// Configuration for task preemption.
72#[derive(Debug, Clone)]
73pub struct PreemptionConfig {
74    /// Whether to enable cooperative preemption
75    pub enabled: bool,
76    /// Time slice for each task before preemption (microseconds)
77    pub time_slice_us: u64,
78    /// Whether to preempt based on priority
79    pub priority_based: bool,
80    /// Minimum execution time before preemption (microseconds)
81    pub min_execution_time_us: u64,
82}
83
84impl Default for PreemptionConfig {
85    fn default() -> Self {
86        Self {
87            enabled: true,
88            time_slice_us: 10_000, // 10ms
89            priority_based: true,
90            min_execution_time_us: 1_000, // 1ms
91        }
92    }
93}
94
95/// Configuration for memory management.
96#[derive(Debug, Clone)]
97pub struct MemoryConfig {
98    /// Whether to use memory pools
99    pub use_memory_pools: bool,
100    /// Size of small object pool (bytes)
101    pub small_pool_size: usize,
102    /// Size of medium object pool (bytes)
103    pub medium_pool_size: usize,
104    /// Size of large object pool (bytes)
105    pub large_pool_size: usize,
106    /// Whether to track memory usage per task
107    pub track_per_task_memory: bool,
108}
109
110impl Default for MemoryConfig {
111    fn default() -> Self {
112        Self {
113            use_memory_pools: true,
114            small_pool_size: SMALL_POOL_SIZE,
115            medium_pool_size: MEDIUM_POOL_SIZE,
116            large_pool_size: LARGE_POOL_SIZE,
117            track_per_task_memory: cfg!(feature = "metrics"),
118        }
119    }
120}
121
122/// Configuration for task metadata cleanup.
123///
124/// Controls how and when completed task metadata is removed from memory
125/// to prevent memory leaks in long-running executors.
126#[derive(Debug, Clone)]
127pub struct CleanupConfig {
128    /// How long to keep completed task metadata before cleanup
129    ///
130    /// # Default: 5 minutes
131    /// # Range: 1 second to `task_retention_duration`
132    pub task_retention_duration: core::time::Duration,
133
134    /// How often to run the cleanup process
135    ///
136    /// # Default: 30 seconds  
137    /// # Range: 1 second to `task_retention_duration`
138    pub cleanup_interval: core::time::Duration,
139
140    /// Whether to enable automatic cleanup
141    ///
142    /// If disabled, cleanup must be triggered manually via `cleanup_completed_tasks()`
143    /// # Default: true
144    pub enable_automatic_cleanup: bool,
145
146    /// Maximum number of completed tasks to retain regardless of age
147    ///
148    /// This provides a hard limit to prevent unbounded memory growth
149    /// # Default: 10,000 tasks
150    pub max_retained_tasks: usize,
151}
152
153impl Default for CleanupConfig {
154    fn default() -> Self {
155        Self {
156            task_retention_duration: core::time::Duration::from_mins(5),
157            cleanup_interval: core::time::Duration::from_secs(30), // 30 seconds
158            enable_automatic_cleanup: true,
159            max_retained_tasks: 10_000,
160        }
161    }
162}