use crate::{WgpuResource, WgpuStorage};
use cubecl_core::{MemoryConfiguration, server::IoError};
use cubecl_environment::sync::Arc;
use cubecl_ir::MemoryDeviceProperties;
use cubecl_server::{
logging::ServerLogger,
memory_management::{
AuxiliaryMemoryReport, Cleanup, ErrorGraph, ManagedMemoryBinding, ManagedMemoryHandle,
MemoryAllocationMode, MemoryHandle, MemoryManagement, MemoryManagementOptions, PageUpdate,
},
storage::ComputeStorage,
};
use wgpu::BufferUsages;
const STAGING: &str = "Staging CPU Memory";
const UNIFORMS: &str = "Uniform GPU Memory";
pub(crate) fn main_memory(
device: &wgpu::Device,
properties: &MemoryDeviceProperties,
config: MemoryConfiguration,
logger: Arc<ServerLogger>,
use_vulkan_compiler: bool,
) -> MemoryManagement<WgpuStorage> {
MemoryManagement::from_configuration(
WgpuStorage::new(
properties.alignment as usize,
device.clone(),
BufferUsages::STORAGE
| BufferUsages::COPY_SRC
| BufferUsages::COPY_DST
| BufferUsages::INDIRECT,
use_vulkan_compiler,
),
properties,
config,
logger,
MemoryManagementOptions::new("Main GPU Memory"),
)
}
#[derive(Debug)]
pub struct AuxiliaryMemory {
staging: MemoryManagement<WgpuStorage>,
uniforms: MemoryManagement<WgpuStorage>,
queued_uniforms: Vec<ManagedMemoryHandle>,
failures: ErrorGraph,
}
impl AuxiliaryMemory {
pub(crate) fn new(
device: &wgpu::Device,
properties: &MemoryDeviceProperties,
logger: Arc<ServerLogger>,
use_vulkan_compiler: bool,
) -> Self {
let staging = MemoryManagement::from_configuration(
WgpuStorage::new(
wgpu::COPY_BUFFER_ALIGNMENT as usize,
device.clone(),
BufferUsages::MAP_READ | BufferUsages::COPY_DST,
false,
),
properties,
MemoryConfiguration::ExclusivePages,
logger.clone(),
MemoryManagementOptions::new(STAGING).mode(MemoryAllocationMode::Auto),
);
let uniforms = MemoryManagement::from_configuration(
WgpuStorage::new(
properties.alignment as usize,
device.clone(),
BufferUsages::UNIFORM | BufferUsages::STORAGE | BufferUsages::COPY_DST,
use_vulkan_compiler,
),
properties,
MemoryConfiguration::ExclusivePages,
logger,
MemoryManagementOptions::new(UNIFORMS).mode(MemoryAllocationMode::Auto),
);
Self {
staging,
uniforms,
queued_uniforms: Vec::new(),
failures: ErrorGraph::default(),
}
}
pub(crate) fn bytes_allocated(&self) -> u64 {
self.staging.bytes_allocated() + self.uniforms.bytes_allocated()
}
pub(crate) fn report(&self) -> Vec<AuxiliaryMemoryReport> {
[(STAGING, &self.staging), (UNIFORMS, &self.uniforms)]
.into_iter()
.map(|(name, memory)| AuxiliaryMemoryReport {
name: name.to_string(),
pools: memory.memory_report(),
})
.collect()
}
pub(crate) fn reserve_staging(
&mut self,
size: u64,
) -> Result<(WgpuResource, ManagedMemoryBinding), IoError> {
let handle = self
.staging
.reserve(size, PageUpdate::Allow, &mut self.failures)?;
let binding = MemoryHandle::binding(handle);
let resource = self
.staging
.get_resource(binding.clone(), None, None)
.unwrap();
Ok((resource, binding))
}
pub(crate) fn reserve_uniform(&mut self, size: u64) -> (ManagedMemoryHandle, WgpuResource) {
let slice = self
.uniforms
.reserve(size, PageUpdate::Allow, &mut self.failures)
.expect("Must have enough memory for a uniform");
self.queued_uniforms.push(slice.clone());
let retained = slice.clone();
let handle = self
.uniforms
.get_storage(slice.binding())
.expect("Failed to find storage!");
let resource = self
.uniforms
.storage()
.get(&handle)
.expect("Failed to get the uniform's storage!");
(retained, resource)
}
pub(crate) fn cleanup_uniforms(&mut self) {
self.uniforms.cleanup(Cleanup::Explicit, &mut self.failures);
}
pub(crate) fn release_uniforms(&mut self) {
self.queued_uniforms.clear();
}
}