use std::sync::OnceLock;
pub use config::{GpuConfig, GpuInfo, GpuPoolStats};
use crate::{Error, Precision, Result, kernel::Method, prepare::Knots, time::Grid, value::Value};
mod config;
#[cfg(feature = "gpu")]
mod context;
#[cfg(feature = "gpu")]
pub mod run;
#[cfg(feature = "gpu")]
mod shader;
static CONFIG: OnceLock<GpuConfig> = OnceLock::new();
fn config() -> GpuConfig {
CONFIG.get().cloned().unwrap_or_default()
}
#[cfg(feature = "gpu")]
fn fix_config() -> GpuConfig {
CONFIG.get_or_init(GpuConfig::default).clone()
}
pub fn configure_gpu(config: GpuConfig) -> Result<()> {
CONFIG.set(config).map_err(|_| {
#[cfg(feature = "gpu")]
if context::started() {
return Error::GpuAlreadyConfigured("the GPU has already started; configure it before its first use");
}
Error::GpuAlreadyConfigured("a configuration was already set")
})
}
#[must_use]
pub fn gpu_config() -> GpuConfig {
config()
}
pub fn prewarm_gpu() -> Result<GpuInfo> {
#[cfg(feature = "gpu")]
return context::get().map(|ctx| ctx.info.clone());
#[cfg(not(feature = "gpu"))]
Err(no_gpu_feature())
}
pub fn prewarm_gpu_with_config(config: GpuConfig) -> Result<GpuInfo> {
configure_gpu(config)?;
prewarm_gpu()
}
#[must_use]
#[cfg_attr(not(feature = "gpu"), allow(clippy::missing_const_for_fn))]
pub fn gpu_info() -> Option<GpuInfo> {
#[cfg(feature = "gpu")]
return context::try_get().map(|ctx| ctx.info.clone());
#[cfg(not(feature = "gpu"))]
None
}
#[must_use]
#[cfg_attr(not(feature = "gpu"), allow(clippy::missing_const_for_fn))]
pub fn gpu_pool_stats() -> Option<GpuPoolStats> {
#[cfg(feature = "gpu")]
return context::try_get().map(context::Context::pool_stats);
#[cfg(not(feature = "gpu"))]
None
}
#[cfg_attr(not(feature = "gpu"), allow(clippy::missing_const_for_fn))]
pub fn started() -> bool {
#[cfg(feature = "gpu")]
return context::started();
#[cfg(not(feature = "gpu"))]
false
}
#[cfg_attr(not(feature = "gpu"), allow(unused_variables, clippy::needless_pass_by_ref_mut))]
pub fn eval<V: Value>(knots: &Knots<'_, V>, grid: &Grid, method: &Method, precision: Precision, out: &mut [f64]) -> Result<()> {
#[cfg(feature = "gpu")]
return run::eval(context::get()?, knots, grid, method, precision, out);
#[cfg(not(feature = "gpu"))]
Err(no_gpu_feature())
}
#[cfg_attr(not(feature = "gpu"), allow(unused_variables, clippy::missing_const_for_fn))]
pub fn ready(precision: Precision) -> bool {
#[cfg(feature = "gpu")]
return context::ready(precision);
#[cfg(not(feature = "gpu"))]
false
}
#[cfg(not(feature = "gpu"))]
fn no_gpu_feature() -> Error {
Error::GpuUnavailable("splimes was built without the `gpu` feature".to_owned())
}
#[cfg(all(test, feature = "gpu"))]
mod tests {
#[test]
fn opening_the_device_fixes_the_configuration() {
let _ = super::context::get();
assert!(super::CONFIG.get().is_some());
assert!(super::configure_gpu(super::GpuConfig::minimal()).is_err());
}
}