mod batch;
pub mod bootstrap;
mod control;
mod decode;
pub mod epd;
mod http;
pub mod layout;
mod net;
mod prefill;
mod status;
mod wire;
use std::{
path::PathBuf,
sync::{Arc, RwLock},
time::Duration,
};
pub use batch::BatchRows;
pub use bootstrap::{BootstrapServer, Registry};
pub use control::{
BootstrapInfo, EmbeddingChunk, EmbeddingItem, EmbeddingReceiver, EmbeddingSender, LandedItem,
LandedRequest, PdError, PdEvent, RemotePrefill, TransferPeer,
};
pub use decode::{DecodeConfig, DecodeOutbox, DecodePeer};
pub use layout::{
registration::{PrefillLayout, PrefillRoute},
LayoutError,
};
pub use net::NetError;
pub use prefill::{Layerwise, PrefillConfig, PrefillOutbox, PrefillPeer};
pub use status::TransferPoll;
use ts_mooncake::{Engine, PageGrid};
pub use wire::StatusMessage;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Copy {
Pages(PageGrid),
Spans {
sources: Vec<u64>,
destinations: Vec<u64>,
lengths: Vec<u64>,
},
}
const DESCRIPTOR_BATCH: usize = 4096;
#[derive(Debug, thiserror::Error)]
pub enum StartError {
#[error(transparent)]
Engine(#[from] ts_mooncake::Error),
#[error(transparent)]
Net(#[from] NetError),
#[error("starting a PD thread: {0}")]
Thread(#[from] std::io::Error),
#[error(transparent)]
Layout(#[from] LayoutError),
}
#[derive(Debug, Clone)]
pub struct PeerConfig {
pub library: PathBuf,
pub local_ip: String,
pub ib_device: String,
pub regions: Vec<(usize, usize)>,
pub engine_rank: i64,
pub metrics: Option<Arc<ts_metrics::KvTransferMetrics>>,
}
struct Transport {
library: Arc<ts_mooncake::Library>,
local_ip: String,
ib_device: String,
regions: Vec<(usize, usize)>,
engine: RwLock<Arc<Engine>>,
sockets: net::Sockets,
}
impl Transport {
fn start(
config: &PeerConfig,
incoming: std::sync::mpsc::Sender<Vec<bytes::Bytes>>,
) -> Result<Arc<Self>, StartError> {
let library = ts_mooncake::Library::load(&config.library)?;
let engine = Engine::start(library.clone(), &config.local_ip, &config.ib_device)?;
for &(addr, length) in &config.regions {
engine.register(addr, length)?;
}
tracing::info!(
session = engine.session_id(),
ib_device = config.ib_device,
"Mooncake transfer engine ready"
);
let sockets = net::Sockets::start(&config.local_ip, incoming)?;
Ok(Arc::new(Self {
library,
local_ip: config.local_ip.clone(),
ib_device: config.ib_device.clone(),
regions: config.regions.clone(),
engine: RwLock::new(Arc::new(engine)),
sockets,
}))
}
fn engine(&self) -> Arc<Engine> {
self.engine
.read()
.expect("the engine lock is poisoned")
.clone()
}
fn session_id(&self) -> String {
self.engine().session_id().to_owned()
}
fn release_regions(&self) -> Result<(), String> {
let engine = self.engine();
let failed = self
.regions
.iter()
.filter(|&&(addr, _)| engine.unregister(addr).is_err())
.count();
if failed > 0 {
return Err(format!(
"Mooncake failed to deregister {failed} cache region(s) before the memory release"
));
}
Ok(())
}
fn restore_regions(&self, fresh_session: bool) -> Result<(), String> {
let engine = if fresh_session {
Arc::new(
Engine::start(self.library.clone(), &self.local_ip, &self.ib_device)
.map_err(|error| error.to_string())?,
)
} else {
self.engine()
};
let failed = self
.regions
.iter()
.filter(|&&(addr, length)| engine.register(addr, length).is_err())
.count();
if failed > 0 {
return Err(format!(
"Mooncake failed to register {failed} cache region(s) after the memory resume"
));
}
if fresh_session {
tracing::info!(session = engine.session_id(), "a fresh transfer session");
*self.engine.write().expect("the engine lock is poisoned") = engine;
}
Ok(())
}
fn write(&self, session: &str, copies: &[Copy]) -> Result<(), ts_mooncake::Error> {
let engine = self.engine();
for copy in copies {
match copy {
Copy::Pages(grid) => engine.write_pages(session, grid, DESCRIPTOR_BATCH)?,
Copy::Spans {
sources,
destinations,
lengths,
} => {
for start in (0..sources.len()).step_by(DESCRIPTOR_BATCH) {
let end = (start + DESCRIPTOR_BATCH).min(sources.len());
engine.write(
session,
&sources[start..end],
&destinations[start..end],
&lengths[start..end],
)?;
}
}
}
}
Ok(())
}
}
fn sleep_or_stop(stop: &std::sync::mpsc::Receiver<()>, duration: Duration) -> bool {
!matches!(
stop.recv_timeout(duration),
Err(std::sync::mpsc::RecvTimeoutError::Timeout)
)
}