feat(memory): scale L1 audio cache cap to host memory profile (#331)
Add audio_cache_l1_max_bytes to MemoryProfile and wire it into AppState's AudioCache constructor. Normal hosts keep the historical 400 MB cap; LowMemory hosts drop to 50 MB. Without this, a Pi 3B (1 GB total) starts with the L1 cache cap set at ~40 % of physical RAM. Even with the Feature #3 prefetch caps already in place, the runtime watchdog from the previous commit ends up firing more often than necessary because nothing prevents a single L1 fill cycle from claiming 400 MB. Capping at 50 MB caps how much the cache can grow before either: (a) eviction picks up naturally, or (b) the watchdog steps in if the rest of the system is also under pressure. Pure refactor in lib.rs — replaces a hard-coded 400 * 1024 * 1024 with a profile field read. The default-constructed AudioCache fallback (when disk-spillover init fails) keeps its own crate default; no need to thread the profile there since the failure path is rare. Two tests added: a presence-bound assertion in the existing Pi 3B case, and an explicit comparison that LowMemory's cap is strictly smaller than Normal's. cc
This commit is contained in:
2 files changed
+24
-2
No files matched your search
@@ -43,6 +43,11 @@ pub struct MemoryProfile {
|
||||
/// (44.1 kHz / 16-bit FLAC) so each cached track stays under ~15 MB
|
||||
/// instead of ~60 MB.
|
||||
pub allow_hires_prefetch: bool,
|
||||
/// Upper bound for the L1 (in-memory) audio cache. The default
|
||||
/// 400 MB cap is sized for Normal-class desktops; on a Pi 3B (1 GB
|
||||
/// total) that single subsystem could consume 40 % of RAM, which
|
||||
/// guarantees swap thrash before the watchdog can react.
|
||||
pub audio_cache_l1_max_bytes: usize,
|
||||
}
|
||||
|
||||
impl MemoryProfile {
|
||||
@@ -61,6 +66,7 @@ impl MemoryProfile {
|
||||
max_initial_buffer_bytes: 2 * 1024 * 1024,
|
||||
max_concurrent_prefetch: 2,
|
||||
allow_hires_prefetch: true,
|
||||
audio_cache_l1_max_bytes: 400 * 1024 * 1024,
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
@@ -70,6 +76,7 @@ impl MemoryProfile {
|
||||
max_initial_buffer_bytes: 256 * 1024,
|
||||
max_concurrent_prefetch: 1,
|
||||
allow_hires_prefetch: false,
|
||||
audio_cache_l1_max_bytes: 50 * 1024 * 1024,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +245,17 @@ SwapTotal: 2097152 kB
|
||||
assert_eq!(profile.max_concurrent_prefetch, 1);
|
||||
assert!(!profile.allow_hires_prefetch);
|
||||
assert!(profile.max_initial_buffer_bytes <= 256 * 1024);
|
||||
// L1 cap must be a small fraction of total RAM — at most ~10 %
|
||||
// of a Pi 3B, so we don't reserve four-tenths of memory for one
|
||||
// subsystem on a 1 GB host.
|
||||
assert!(profile.audio_cache_l1_max_bytes <= 100 * 1024 * 1024);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_cache_cap_is_significantly_smaller_on_low_memory() {
|
||||
let normal = MemoryProfile::from_total_kb(8 * 1024 * 1024);
|
||||
let low = MemoryProfile::from_total_kb(938196);
|
||||
assert!(low.audio_cache_l1_max_bytes < normal.audio_cache_l1_max_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user