use std::ffi::OsStr;
use std::path::PathBuf;
use cubecl::config::cache::CacheConfig;
use cubecl::config::{CubeClRuntimeConfig, RuntimeConfig};
pub const COMPILATION_CACHE_ENV: &str = "AV_DENOISE_COMPILATION_CACHE";
const CACHE_DIR_NAME: &str = "av-denoise";
const DISABLE_WORDS: [&str; 4] = ["off", "0", "false", "none"];
#[derive(Debug, thiserror::Error)]
#[error(
"CubeCL global config already initialized. Call install_compilation_cache() before any Denoiser::create"
)]
pub struct CacheAlreadyInitialisedError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum CacheLocation {
Disabled,
Dir(PathBuf),
}
pub(crate) fn resolve_cache_location(
env: Option<&OsStr>,
xdg_cache_home: Option<&OsStr>,
home: Option<&OsStr>,
is_macos: bool,
) -> CacheLocation {
if let Some(raw) = env {
let text = raw.to_string_lossy();
let trimmed = text.trim();
if !trimmed.is_empty() {
if DISABLE_WORDS.iter().any(|w| trimmed.eq_ignore_ascii_case(w)) {
return CacheLocation::Disabled;
}
return CacheLocation::Dir(PathBuf::from(raw));
}
}
if let Some(xdg) = xdg_cache_home.filter(|x| !x.is_empty()) {
return CacheLocation::Dir(PathBuf::from(xdg).join(CACHE_DIR_NAME));
}
let Some(home) = home.filter(|h| !h.is_empty()) else {
return CacheLocation::Disabled;
};
let base = if is_macos {
PathBuf::from(home).join("Library").join("Caches")
} else {
PathBuf::from(home).join(".cache")
};
CacheLocation::Dir(base.join(CACHE_DIR_NAME))
}
pub fn install_compilation_cache() -> Result<Option<PathBuf>, CacheAlreadyInitialisedError> {
let location = resolve_cache_location(
std::env::var_os(COMPILATION_CACHE_ENV).as_deref(),
std::env::var_os("XDG_CACHE_HOME").as_deref(),
std::env::var_os("HOME").as_deref(),
cfg!(target_os = "macos"),
);
let CacheLocation::Dir(path) = location else {
return Ok(None);
};
if let Err(err) = std::fs::create_dir_all(&path) {
tracing::warn!(
?path,
%err,
"cannot create the kernel cache directory, continuing without a cache"
);
return Ok(None);
}
let mut cfg = CubeClRuntimeConfig::from_current_dir().override_from_env();
cfg.compilation.cache = Some(CacheConfig::File(path.clone()));
cfg.autotune.cache = CacheConfig::File(path.clone());
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
CubeClRuntimeConfig::set(cfg);
}))
.map_err(|_| CacheAlreadyInitialisedError)?;
Ok(Some(path))
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;
use super::*;
fn os(text: &str) -> OsString {
OsString::from(text)
}
fn resolve(env: Option<&str>, xdg: Option<&str>, home: Option<&str>) -> CacheLocation {
let env = env.map(os);
let xdg = xdg.map(os);
let home = home.map(os);
resolve_cache_location(env.as_deref(), xdg.as_deref(), home.as_deref(), false)
}
#[test]
fn the_default_is_the_xdg_cache_directory() {
assert_eq!(
resolve(None, Some("/home/u/.cache"), Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/home/u/.cache/av-denoise")),
);
}
#[test]
fn without_xdg_the_default_sits_under_the_home_directory() {
assert_eq!(
resolve(None, None, Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/home/u/.cache/av-denoise")),
);
}
#[test]
fn macos_uses_its_own_cache_directory() {
let home = os("/Users/u");
assert_eq!(
resolve_cache_location(None, None, Some(home.as_os_str()), true),
CacheLocation::Dir(PathBuf::from("/Users/u/Library/Caches/av-denoise")),
);
}
#[test]
fn an_explicit_path_overrides_every_default() {
assert_eq!(
resolve(Some("/mnt/cache"), Some("/home/u/.cache"), Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/mnt/cache")),
);
}
#[test]
fn the_disable_words_turn_caching_off() {
for word in ["off", "OFF", "Off", "0", "false", "FALSE", "none", " off "] {
assert_eq!(
resolve(Some(word), Some("/home/u/.cache"), Some("/home/u")),
CacheLocation::Disabled,
"{word} should disable caching",
);
}
}
#[test]
fn a_path_containing_a_disable_word_is_still_a_path() {
assert_eq!(
resolve(Some("/tmp/offsite"), None, Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/tmp/offsite")),
);
}
#[test]
fn an_empty_variable_takes_the_default() {
assert_eq!(
resolve(Some(""), Some("/home/u/.cache"), Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/home/u/.cache/av-denoise")),
);
assert_eq!(
resolve(Some(" "), Some("/home/u/.cache"), Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/home/u/.cache/av-denoise")),
);
}
#[test]
fn an_empty_xdg_falls_through_to_the_home_directory() {
assert_eq!(
resolve(None, Some(""), Some("/home/u")),
CacheLocation::Dir(PathBuf::from("/home/u/.cache/av-denoise")),
);
}
#[test]
fn no_home_directory_means_no_cache() {
assert_eq!(resolve(None, None, None), CacheLocation::Disabled);
assert_eq!(resolve(None, None, Some("")), CacheLocation::Disabled);
}
}