use super::{
FullyContiguousLayout, LayerSeparateLayout, Layout, MemoryDescriptor,
builder::{PhysicalLayoutBuilder, PhysicalLayoutBuilderDefault},
serialize::{LayoutDescriptor, LayoutTypeDetails},
};
use crate::block_manager::v2::memory::{MemoryRegion, StorageKind};
use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::sync::Arc;
use crate::block_manager::v2::physical::transfer::nixl_agent::NixlAgent;
#[derive(Debug, Clone)]
pub struct PhysicalLayout {
layout: Arc<dyn Layout>,
location: StorageKind,
nixl_metadata: NixlMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NixlMetadata {
agent_name: String,
mem_type: nixl_sys::MemType,
device_id: u64,
}
impl NixlMetadata {
pub fn new(agent_name: String, mem_type: nixl_sys::MemType, device_id: u64) -> Self {
Self {
agent_name,
mem_type,
device_id,
}
}
pub fn agent_name(&self) -> &str {
&self.agent_name
}
pub fn mem_type(&self) -> nixl_sys::MemType {
self.mem_type
}
pub fn device_id(&self) -> u64 {
self.device_id
}
}
impl PhysicalLayout {
pub fn builder(agent: NixlAgent) -> PhysicalLayoutBuilderDefault {
PhysicalLayoutBuilder::new(agent)
}
pub(crate) fn new_local(
layout: Arc<dyn Layout>,
location: StorageKind,
nixl_metadata: NixlMetadata,
) -> Self {
Self {
layout,
location,
nixl_metadata,
}
}
pub fn layout(&self) -> &Arc<dyn Layout> {
&self.layout
}
pub fn location(&self) -> StorageKind {
self.location
}
pub fn nixl_metadata(&self) -> &NixlMetadata {
&self.nixl_metadata
}
pub fn memory_region(
&self,
block_id: usize,
layer_id: usize,
outer_id: usize,
) -> Result<MemoryDescriptor> {
self.layout.memory_region(block_id, layer_id, outer_id)
}
pub fn to_descriptor(&self) -> Result<LayoutDescriptor> {
let memory_descriptors = self
.layout
.memory_regions()
.iter()
.map(|region| MemoryDescriptor {
addr: region.addr(),
size: region.size(),
})
.collect();
let layout_type_details = self.layout.serialization_details();
Ok(LayoutDescriptor {
version: LayoutDescriptor::CURRENT_VERSION,
layout_config: self.layout.config().clone(),
location: self.location,
nixl_metadata: self.nixl_metadata.clone(),
memory_descriptors,
layout_type_details,
})
}
pub fn from_descriptor(serialized: LayoutDescriptor) -> Result<Self> {
if serialized.version > LayoutDescriptor::CURRENT_VERSION {
return Err(anyhow!(
"Unsupported serialization version: {}. Maximum supported: {}",
serialized.version,
LayoutDescriptor::CURRENT_VERSION
));
}
let remote_regions: Vec<Arc<dyn MemoryRegion>> = serialized
.memory_descriptors
.iter()
.map(|desc| {
Arc::new(RemoteMemoryDescriptor {
addr: desc.addr,
size: desc.size,
storage_kind: serialized.location,
}) as Arc<dyn MemoryRegion>
})
.collect();
let layout: Arc<dyn Layout> = match serialized.layout_type_details {
LayoutTypeDetails::FullyContiguous(details) => {
if remote_regions.len() != 1 {
return Err(anyhow!(
"FullyContiguous layout requires exactly 1 memory region, got {}",
remote_regions.len()
));
}
let layout = FullyContiguousLayout::new_with_format(
serialized.layout_config.clone(),
remote_regions[0].clone(),
details.block_format,
)?;
Arc::new(layout)
}
LayoutTypeDetails::LayerSeparate(details) => {
if remote_regions.len() != serialized.layout_config.num_layers {
return Err(anyhow!(
"LayerSeparate layout requires {} memory regions (one per layer), got {}",
serialized.layout_config.num_layers,
remote_regions.len()
));
}
let layout = LayerSeparateLayout::new(
serialized.layout_config.clone(),
remote_regions,
details.block_dim,
)?;
Arc::new(layout)
}
};
Ok(Self {
layout,
location: serialized.location,
nixl_metadata: serialized.nixl_metadata,
})
}
}
#[derive(Debug)]
struct RemoteMemoryDescriptor {
addr: usize,
size: usize,
storage_kind: StorageKind,
}
impl MemoryRegion for RemoteMemoryDescriptor {
fn addr(&self) -> usize {
self.addr
}
fn size(&self) -> usize {
self.size
}
fn storage_kind(&self) -> StorageKind {
self.storage_kind
}
fn as_any(&self) -> &dyn Any {
self
}
fn nixl_descriptor(&self) -> Option<crate::block_manager::v2::memory::NixlDescriptor> {
None
}
}