Skip to main content

cubecl_runtime/config/
memory.rs

1use super::logger::{LogLevel, LoggerConfig};
2
3/// Configuration for memory settings in `CubeCL`.
4///
5/// Unknown fields are rejected so a leftover `pools` entry — the pools are the
6/// memory management's to lay out, not a setting — or a misspelled option is a
7/// load error rather than a silently dropped setting.
8#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
9#[serde(deny_unknown_fields)]
10pub struct MemoryConfig {
11    /// Logger configuration for memory-related logs, using specific log levels.
12    #[serde(default)]
13    pub logger: LoggerConfig<MemoryLogLevel>,
14    /// Configuration for persistent memory pools.
15    #[serde(default)]
16    pub persistent_memory: PersistentMemory,
17    /// CUDA-specific memory settings. Ignored by other backends.
18    #[serde(default)]
19    pub cuda: CudaMemoryConfig,
20}
21
22/// Memory settings for the CUDA runtime (`[memory.cuda]` in `cubecl.toml`).
23#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
24#[serde(deny_unknown_fields)]
25pub struct CudaMemoryConfig {
26    /// Allocator backing `CubeCL`'s pools, selected when the runtime initializes.
27    #[serde(default)]
28    pub allocator: CudaAllocator,
29}
30
31/// CUDA allocator used to obtain backing memory for `CubeCL`'s pools.
32#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum CudaAllocator {
35    /// Allocate and free synchronously, avoiding an additional CUDA memory pool.
36    /// Pool growth and cleanup may synchronize GPU work.
37    #[default]
38    Sync,
39    /// Use CUDA's stream-ordered allocator, which may reserve extra backing memory
40    /// but can preserve concurrency during pool growth and cleanup. Falls back to
41    /// synchronous allocation if an asynchronous allocation fails.
42    Async,
43}
44
45/// Configuration options for persistent memory pools in `CubeCL` runtimes.
46#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
47pub enum PersistentMemory {
48    /// Persistent memory is enabled but used only when explicitly specified.
49    #[default]
50    #[serde(rename = "enabled")]
51    Enabled,
52    /// Like `enabled`, and automatic allocations whose size matches an
53    /// existing persistent bucket are also served from the persistent pool.
54    ///
55    /// A good heuristic for training, where the recurring allocations are
56    /// weight-shaped and updated within the same pool. Less suited to
57    /// inference: activations that happen to match a weight size get pulled
58    /// into exact-sized persistent slices.
59    #[serde(rename = "size-match")]
60    SizeMatch,
61    /// Persistent memory is disabled, allowing dynamic allocations.
62    #[serde(rename = "disabled")]
63    Disabled,
64    /// Persistent memory is enforced, preventing dynamic allocations.
65    ///
66    /// # Warning
67    ///
68    /// Enforcing persistent memory may cause out-of-memory errors if tensors of varying sizes are used.
69    #[serde(rename = "enforced")]
70    Enforced,
71}
72
73/// Log levels for memory-related events in `CubeCL`.
74#[derive(Default, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
75pub enum MemoryLogLevel {
76    /// No memory-related logging.
77    #[default]
78    #[serde(rename = "disabled")]
79    Disabled,
80    /// Logs basic memory events, such as creating memory pages and manually cleaning memory.
81    #[serde(rename = "basic")]
82    Basic,
83    /// Logs detailed memory information.
84    #[serde(rename = "full")]
85    Full,
86}
87
88impl LogLevel for MemoryLogLevel {}
89
90#[cfg(all(test, feature = "std"))]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn cuda_allocator_config() {
96        use crate::config::CubeClRuntimeConfig;
97
98        let config: CubeClRuntimeConfig = toml::from_str("").unwrap();
99        assert_eq!(config.memory.cuda.allocator, CudaAllocator::Sync);
100
101        let config: CubeClRuntimeConfig =
102            toml::from_str("[memory.cuda]\nallocator = \"async\"").unwrap();
103        assert_eq!(config.memory.cuda.allocator, CudaAllocator::Async);
104    }
105
106    #[test]
107    fn pools_rejected_in_config_files() {
108        // Pool layouts are a programmatic setting; a leftover `pools` entry in
109        // a config file must be a load error, not a silently ignored setting.
110        assert!(toml::from_str::<MemoryConfig>("pools = \"sub-slices\"").is_err());
111        assert!(
112            toml::from_str::<MemoryConfig>("[[pools]]\ntype = \"sliced\"\npage_size = \"1MiB\"\n")
113                .is_err()
114        );
115    }
116}