use std::sync::Arc;
pub trait HeapTrim: Send + Sync {
fn trim(&self);
}
#[cfg(all(target_os = "linux", target_env = "gnu"))]
struct GlibcTrim;
#[cfg(all(target_os = "linux", target_env = "gnu"))]
impl HeapTrim for GlibcTrim {
fn trim(&self) {
unsafe {
libc::malloc_trim(0);
}
}
}
#[derive(Clone)]
pub struct HeapTrimPolicy {
min_tokens: usize,
trimmer: Option<Arc<dyn HeapTrim>>,
}
impl HeapTrimPolicy {
pub fn off() -> Self {
Self {
min_tokens: 0,
trimmer: None,
}
}
pub fn process_heap(min_tokens: usize) -> Result<Self, String> {
if min_tokens == 0 {
return Ok(Self::off());
}
Self::glibc_trimmer().map(|trimmer| Self::with_trimmer(min_tokens, trimmer))
}
#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn glibc_trimmer() -> Result<Arc<dyn HeapTrim>, String> {
Ok(Arc::new(GlibcTrim))
}
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
fn glibc_trimmer() -> Result<Arc<dyn HeapTrim>, String> {
Err("this build's allocator is not glibc's, so there is no malloc_trim to run".into())
}
pub fn with_trimmer(min_tokens: usize, trimmer: Arc<dyn HeapTrim>) -> Self {
Self {
min_tokens,
trimmer: Some(trimmer),
}
}
pub fn min_tokens(&self) -> usize {
self.min_tokens
}
pub(super) fn after_encode(&self, tokens: usize) {
match &self.trimmer {
Some(trimmer) if self.min_tokens > 0 && tokens >= self.min_tokens => {
let started = std::time::Instant::now();
trimmer.trim();
tracing::debug!(
tokens,
trim_ms = started.elapsed().as_secs_f64() * 1e3,
"tokenizer heap trimmed"
);
}
_ => {}
}
}
}