Coverage Report

Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/realizar/src/memory.rs
Line
Count
Source
1
//! Memory management for hot expert pinning
2
//!
3
//! Per Dean & Barroso (2013) "The Tail at Scale", page faults cause
4
//! tail latency. This module provides mlock support for hot experts.
5
6
/// Configuration for memory pinning
7
#[derive(Debug, Clone, Default)]
8
pub struct MlockConfig {
9
    /// Whether to attempt memory locking
10
    pub enabled: bool,
11
    /// Maximum bytes to lock (0 = unlimited)
12
    pub max_locked_bytes: usize,
13
}
14
15
/// Result of mlock operation
16
#[derive(Debug, Clone, PartialEq, Eq)]
17
pub enum MlockResult {
18
    /// Successfully locked memory
19
    Locked,
20
    /// Mlock disabled in config
21
    Disabled,
22
    /// Failed to lock (insufficient privileges)
23
    InsufficientPrivileges,
24
    /// Failed to lock (resource limit)
25
    ResourceLimit,
26
    /// Platform not supported
27
    Unsupported,
28
}
29
30
/// Memory region that can be pinned
31
pub struct PinnedRegion {
32
    /// Pointer to locked memory (for tracking)
33
    ptr: *const u8,
34
    /// Size of locked region
35
    len: usize,
36
    /// Whether actually locked
37
    locked: bool,
38
}
39
40
// Safety: PinnedRegion only holds a pointer for tracking, doesn't access it
41
unsafe impl Send for PinnedRegion {}
42
unsafe impl Sync for PinnedRegion {}
43
44
impl PinnedRegion {
45
    /// Create a pinned region (attempts mlock)
46
    ///
47
    /// # Safety
48
    ///
49
    /// Caller must ensure ptr points to valid memory for len bytes.
50
    #[must_use]
51
5
    pub unsafe fn new(ptr: *const u8, len: usize, config: &MlockConfig) -> (Self, MlockResult) {
52
5
        if !config.enabled {
53
3
            return (
54
3
                Self {
55
3
                    ptr,
56
3
                    len,
57
3
                    locked: false,
58
3
                },
59
3
                MlockResult::Disabled,
60
3
            );
61
2
        }
62
63
2
        if config.max_locked_bytes > 0 && 
len > config.max_locked_bytes1
{
64
1
            return (
65
1
                Self {
66
1
                    ptr,
67
1
                    len,
68
1
                    locked: false,
69
1
                },
70
1
                MlockResult::ResourceLimit,
71
1
            );
72
1
        }
73
74
1
        let result = Self::mlock_impl(ptr, len);
75
1
        let locked = result == MlockResult::Locked;
76
1
        (Self { ptr, len, locked }, result)
77
5
    }
78
79
    /// Check if memory is locked
80
    #[must_use]
81
2
    pub fn is_locked(&self) -> bool {
82
2
        self.locked
83
2
    }
84
85
    /// Get size of region
86
    #[must_use]
87
3
    pub fn len(&self) -> usize {
88
3
        self.len
89
3
    }
90
91
    /// Check if region is empty
92
    #[must_use]
93
2
    pub fn is_empty(&self) -> bool {
94
2
        self.len == 0
95
2
    }
96
97
    #[cfg(target_family = "unix")]
98
1
    fn mlock_impl(ptr: *const u8, len: usize) -> MlockResult {
99
        // Safety: ptr and len validated by caller
100
        // SAFETY: Memory safety ensured by bounds checking and alignment
101
1
        let result = unsafe { libc::mlock(ptr.cast(), len) };
102
1
        if result == 0 {
103
1
            MlockResult::Locked
104
        } else {
105
            // Check errno for specific error
106
0
            let errno = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
107
0
            if errno == libc::EPERM {
108
0
                MlockResult::InsufficientPrivileges
109
            } else {
110
0
                MlockResult::ResourceLimit
111
            }
112
        }
113
1
    }
114
115
    #[cfg(not(target_family = "unix"))]
116
    fn mlock_impl(_ptr: *const u8, _len: usize) -> MlockResult {
117
        MlockResult::Unsupported
118
    }
119
}
120
121
impl Drop for PinnedRegion {
122
5
    fn drop(&mut self) {
123
5
        if self.locked {
124
            #[cfg(target_family = "unix")]
125
            // SAFETY: Memory safety ensured by bounds checking and alignment
126
1
            unsafe {
127
1
                libc::munlock(self.ptr.cast(), self.len);
128
1
            }
129
4
        }
130
5
    }
131
}
132
133
/// Expert tier classification for memory management
134
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135
pub enum ExpertTier {
136
    /// Hot tier - pinned in memory, never swapped
137
    Hot,
138
    /// Warm tier - in memory but may be swapped
139
    Warm,
140
    /// Cold tier - on disk, loaded on demand
141
    Cold,
142
}
143
144
impl ExpertTier {
145
    /// Determine tier based on access frequency
146
    #[must_use]
147
7
    pub fn from_access_count(count: usize, hot_threshold: usize, warm_threshold: usize) -> Self {
148
7
        if count >= hot_threshold {
149
2
            Self::Hot
150
5
        } else if count >= warm_threshold {
151
3
            Self::Warm
152
        } else {
153
2
            Self::Cold
154
        }
155
7
    }
156
}
157
158
#[cfg(test)]
159
mod tests {
160
    use super::*;
161
162
    #[test]
163
1
    fn test_mlock_disabled() {
164
1
        let config = MlockConfig {
165
1
            enabled: false,
166
1
            max_locked_bytes: 0,
167
1
        };
168
1
        let data = vec![0u8; 1024];
169
        // SAFETY: Memory safety ensured by bounds checking and alignment
170
1
        let (region, result) = unsafe { PinnedRegion::new(data.as_ptr(), data.len(), &config) };
171
1
        assert_eq!(result, MlockResult::Disabled);
172
1
        assert!(!region.is_locked());
173
1
    }
174
175
    #[test]
176
1
    fn test_mlock_resource_limit() {
177
1
        let config = MlockConfig {
178
1
            enabled: true,
179
1
            max_locked_bytes: 100,
180
1
        };
181
1
        let data = vec![0u8; 1024]; // Exceeds limit
182
                                    // SAFETY: Memory safety ensured by bounds checking and alignment
183
1
        let (region, result) = unsafe { PinnedRegion::new(data.as_ptr(), data.len(), &config) };
184
1
        assert_eq!(result, MlockResult::ResourceLimit);
185
1
        assert!(!region.is_locked());
186
1
    }
187
188
    #[test]
189
1
    fn test_expert_tier_hot() {
190
1
        let tier = ExpertTier::from_access_count(1000, 100, 10);
191
1
        assert_eq!(tier, ExpertTier::Hot);
192
1
    }
193
194
    #[test]
195
1
    fn test_expert_tier_warm() {
196
1
        let tier = ExpertTier::from_access_count(50, 100, 10);
197
1
        assert_eq!(tier, ExpertTier::Warm);
198
1
    }
199
200
    #[test]
201
1
    fn test_expert_tier_cold() {
202
1
        let tier = ExpertTier::from_access_count(5, 100, 10);
203
1
        assert_eq!(tier, ExpertTier::Cold);
204
1
    }
205
206
    #[test]
207
1
    fn test_pinned_region_len() {
208
1
        let config = MlockConfig::default();
209
1
        let data = vec![0u8; 1024];
210
        // SAFETY: Memory safety ensured by bounds checking and alignment
211
1
        let (region, _) = unsafe { PinnedRegion::new(data.as_ptr(), data.len(), &config) };
212
1
        assert_eq!(region.len(), 1024);
213
1
        assert!(!region.is_empty());
214
1
    }
215
216
    #[test]
217
1
    fn test_pinned_region_empty() {
218
1
        let config = MlockConfig::default();
219
1
        let data: Vec<u8> = vec![];
220
        // SAFETY: Memory safety ensured by bounds checking and alignment
221
1
        let (region, _) = unsafe { PinnedRegion::new(data.as_ptr(), data.len(), &config) };
222
1
        assert_eq!(region.len(), 0);
223
1
        assert!(region.is_empty());
224
1
    }
225
226
    #[test]
227
1
    fn test_mlock_config_default() {
228
1
        let config = MlockConfig::default();
229
1
        assert!(!config.enabled);
230
1
        assert_eq!(config.max_locked_bytes, 0);
231
1
    }
232
233
    #[test]
234
1
    fn test_mlock_result_equality() {
235
1
        assert_eq!(MlockResult::Locked, MlockResult::Locked);
236
1
        assert_eq!(MlockResult::Disabled, MlockResult::Disabled);
237
1
        assert_ne!(MlockResult::Locked, MlockResult::Disabled);
238
1
    }
239
240
    #[test]
241
1
    fn test_expert_tier_boundary() {
242
        // Test exact boundary conditions
243
1
        assert_eq!(ExpertTier::from_access_count(100, 100, 10), ExpertTier::Hot);
244
1
        assert_eq!(ExpertTier::from_access_count(99, 100, 10), ExpertTier::Warm);
245
1
        assert_eq!(ExpertTier::from_access_count(10, 100, 10), ExpertTier::Warm);
246
1
        assert_eq!(ExpertTier::from_access_count(9, 100, 10), ExpertTier::Cold);
247
1
    }
248
249
    #[test]
250
1
    fn test_mlock_enabled_within_limit() {
251
        // Test when enabled and within limit - will try actual mlock
252
1
        let config = MlockConfig {
253
1
            enabled: true,
254
1
            max_locked_bytes: 0, // 0 = unlimited
255
1
        };
256
1
        let data: [u8; 64] = [0u8; 64];
257
        // SAFETY: Memory safety ensured by bounds checking and alignment
258
1
        let (region, result) = unsafe { PinnedRegion::new(data.as_ptr(), data.len(), &config) };
259
        // Result depends on system permissions, but API should work
260
1
        assert!(
261
1
            result == MlockResult::Locked
262
0
                || result == MlockResult::InsufficientPrivileges
263
0
                || result == MlockResult::ResourceLimit
264
0
                || result == MlockResult::Unsupported
265
        );
266
1
        assert_eq!(region.len(), 64);
267
1
    }
268
269
    // ========================================================================
270
    // Coverage Tests
271
    // ========================================================================
272
273
    #[test]
274
1
    fn test_mlock_config_debug() {
275
1
        let config = MlockConfig {
276
1
            enabled: true,
277
1
            max_locked_bytes: 1024,
278
1
        };
279
1
        let debug = format!("{:?}", config);
280
1
        assert!(debug.contains("MlockConfig"));
281
1
        assert!(debug.contains("1024"));
282
1
    }
283
284
    #[test]
285
1
    fn test_mlock_config_clone() {
286
1
        let config = MlockConfig {
287
1
            enabled: true,
288
1
            max_locked_bytes: 2048,
289
1
        };
290
1
        let cloned = config.clone();
291
1
        assert_eq!(config.enabled, cloned.enabled);
292
1
        assert_eq!(config.max_locked_bytes, cloned.max_locked_bytes);
293
1
    }
294
295
    #[test]
296
1
    fn test_mlock_result_debug() {
297
1
        let result = MlockResult::Locked;
298
1
        let debug = format!("{:?}", result);
299
1
        assert!(debug.contains("Locked"));
300
301
1
        let result2 = MlockResult::InsufficientPrivileges;
302
1
        let debug2 = format!("{:?}", result2);
303
1
        assert!(debug2.contains("InsufficientPrivileges"));
304
1
    }
305
306
    #[test]
307
1
    fn test_mlock_result_clone() {
308
1
        let result = MlockResult::Locked;
309
1
        let cloned = result.clone();
310
1
        assert_eq!(result, cloned);
311
1
    }
312
313
    #[test]
314
1
    fn test_expert_tier_debug() {
315
1
        let tier = ExpertTier::Hot;
316
1
        let debug = format!("{:?}", tier);
317
1
        assert!(debug.contains("Hot"));
318
1
    }
319
320
    #[test]
321
1
    fn test_expert_tier_clone() {
322
1
        let tier = ExpertTier::Warm;
323
1
        let cloned = tier;
324
1
        assert_eq!(tier, cloned);
325
1
    }
326
}