use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::OnceLock;
use super::axis_curve::AxisCurve;
use super::{SourceResolver, kernel_source_ok};
use crate::common::enums::MoeQuantMode;
use crate::common::error::AicError;
use crate::common::system_spec::SystemSpec;
use crate::config::{PerfDbSources, PerfSource};
use crate::perf_database::parquet_loader::PerfReader;
pub struct TrtllmAlltoallTable {
data_root: PathBuf,
alltoall_sources: Vec<PerfSource>,
trtllm_alltoall: OnceLock<Result<AlltoallGrids, AicError>>,
}
struct AlltoallGrids {
by_keys: BTreeMap<AlltoallKey, BTreeMap<u32, f64>>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct AlltoallKey {
kernel_source: String,
op_name: String,
quant: String,
num_nodes: u32,
hidden_size: u32,
topk: u32,
num_experts: u32,
moe_ep_size: u32,
}
impl TrtllmAlltoallTable {
pub fn new(data_root: PathBuf) -> Self {
Self::with_sources(data_root, &SourceResolver::fixed(PerfDbSources::default()))
.expect("fixed-map resolution is infallible")
}
pub fn with_sources(data_root: PathBuf, resolver: &SourceResolver) -> Result<Self, AicError> {
let alltoall_sources = resolver.sources_for("trtllm_alltoall_perf.parquet", &data_root)?;
Ok(Self {
data_root,
alltoall_sources,
trtllm_alltoall: OnceLock::new(),
})
}
#[allow(clippy::too_many_arguments)]
pub fn query_trtllm_alltoall(
&self,
spec: &SystemSpec,
op_name: &str,
num_tokens: u32,
hidden_size: u32,
topk: u32,
num_experts: u32,
moe_ep_size: u32,
quant: MoeQuantMode,
moe_backend: Option<&str>,
) -> Result<f64, AicError> {
const VALID_OP_NAMES: [&str; 4] = [
"alltoall_prepare",
"alltoall_dispatch",
"alltoall_combine",
"alltoall_combine_low_precision",
];
if !VALID_OP_NAMES.contains(&op_name) {
return Err(AicError::PerfDatabase(format!(
"Invalid op_name '{op_name}'. Must be one of {VALID_OP_NAMES:?}"
)));
}
let kernel_source = select_alltoall_kernel(spec, moe_ep_size, topk, moe_backend);
if kernel_source == "NotEnabled" {
return Ok(0.0);
}
let node_num = if moe_ep_size < 4 { 1 } else { moe_ep_size / 4 };
let table_quant = if quant == MoeQuantMode::Fp8Block {
MoeQuantMode::Fp8
} else {
quant
};
let grids = self.load_trtllm_alltoall()?;
let key = AlltoallKey {
kernel_source: kernel_source.to_string(),
op_name: op_name.to_string(),
quant: table_quant.name().to_string(),
num_nodes: node_num,
hidden_size,
topk,
num_experts,
moe_ep_size,
};
let by_tokens = grids.by_keys.get(&key).ok_or_else(|| {
AicError::PerfDatabase(format!(
"trtllm alltoall data missing for {key:?} at {}",
self.data_root.display()
))
})?;
token_axis_curve(by_tokens).query(num_tokens as f64, &|t| t)
}
#[allow(clippy::too_many_arguments)]
pub fn alltoall_slice_points(
&self,
kernel_source: &str,
op_name: &str,
table_quant: MoeQuantMode,
node_num: u32,
hidden_size: u32,
topk: u32,
num_experts: u32,
moe_ep_size: u32,
) -> Result<Vec<(u32, f64)>, AicError> {
let grids = self.load_trtllm_alltoall()?;
let key = AlltoallKey {
kernel_source: kernel_source.to_string(),
op_name: op_name.to_string(),
quant: table_quant.name().to_string(),
num_nodes: node_num,
hidden_size,
topk,
num_experts,
moe_ep_size,
};
let by_tokens = grids.by_keys.get(&key).ok_or_else(|| {
AicError::PerfDatabase(format!(
"trtllm alltoall data missing for {key:?} at {}",
self.data_root.display()
))
})?;
if by_tokens.is_empty() {
return Err(AicError::PerfDatabase(format!(
"trtllm alltoall data empty for {key:?} at {}",
self.data_root.display()
)));
}
Ok(by_tokens.iter().map(|(&t, &lat)| (t, lat)).collect())
}
fn load_trtllm_alltoall(&self) -> Result<&AlltoallGrids, AicError> {
let cell = self
.trtllm_alltoall
.get_or_init(|| load_alltoall_parquet(&self.alltoall_sources));
cell.as_ref().map_err(clone_err)
}
}
pub(crate) fn select_alltoall_kernel(
spec: &SystemSpec,
moe_ep_size: u32,
topk: u32,
moe_backend: Option<&str>,
) -> &'static str {
if let Some(backend) = moe_backend {
let upper = backend.to_uppercase();
if upper == "DEEPGEMM" || upper == "CUTE_DSL" {
return "NotEnabled";
}
}
let supports_mnnvl = spec.gpu.sm_version.unwrap_or(0) >= 100;
let is_wideep = moe_backend
.map(|b| b.to_uppercase() == "WIDEEP")
.unwrap_or(false);
if is_wideep {
if supports_mnnvl {
return "NVLinkTwoSided";
}
let deepep_feasible = moe_ep_size > 1 && topk <= 8;
let is_inter_node = moe_ep_size > spec.node.num_gpus_per_node;
if deepep_feasible && is_inter_node {
"DeepEP"
} else if deepep_feasible {
"DeepEPLowLatency"
} else {
"NotEnabled"
}
} else if supports_mnnvl {
"NVLinkOneSided"
} else {
"NotEnabled"
}
}
fn token_axis_curve(points: &std::collections::BTreeMap<u32, f64>) -> AxisCurve {
AxisCurve::from_sorted_iter(
"num_tokens",
points
.iter()
.map(|(&coordinate, &value)| (coordinate, value)),
)
}
pub(crate) fn legacy_num_nodes_fallback(moe_ep_size: u32) -> u32 {
(moe_ep_size / 4).max(1)
}
fn load_alltoall_parquet(sources: &[PerfSource]) -> Result<AlltoallGrids, AicError> {
let mut by_keys: BTreeMap<AlltoallKey, BTreeMap<u32, f64>> = BTreeMap::new();
let mut any_source = false;
for source in sources {
let path = source.path();
if !path.exists() {
continue;
}
any_source = true;
let reader = PerfReader::open(path)?;
let op_name_col = reader.col("op_name")?;
let moe_dtype_col = reader.col("moe_dtype")?;
let num_tokens_col = reader.col("num_tokens")?;
let hidden_size_col = reader.col("hidden_size")?;
let topk_col = reader.col("topk")?;
let num_experts_col = reader.col("num_experts")?;
let moe_ep_size_col = reader.col("moe_ep_size")?;
let latency_col = reader.col("latency")?;
let ks_col = reader.col_optional("kernel_source");
let num_nodes_col = reader.col_optional("num_nodes");
for row in reader.rows()? {
let row = row?;
if !kernel_source_ok(source.kernel_sources(), ks_col, &row)? {
continue;
}
let moe_ep_size = row.u32(moe_ep_size_col)?;
let key = AlltoallKey {
kernel_source: row
.str_optional(ks_col)?
.map(|s| s.to_string())
.unwrap_or_else(|| "NVLinkTwoSided".to_string()),
op_name: row.str_owned(op_name_col)?,
quant: row.str_owned(moe_dtype_col)?,
num_nodes: row
.u32_optional(num_nodes_col)?
.unwrap_or_else(|| legacy_num_nodes_fallback(moe_ep_size)),
hidden_size: row.u32(hidden_size_col)?,
topk: row.u32(topk_col)?,
num_experts: row.u32(num_experts_col)?,
moe_ep_size,
};
by_keys
.entry(key)
.or_default()
.entry(row.u32(num_tokens_col)?)
.or_insert(row.f64(latency_col)?);
}
}
if !any_source || by_keys.is_empty() {
return Err(AicError::PerfDatabase(format!(
"no TRT-LLM alltoall rows loaded from {} source(s) (first: {})",
sources.len(),
sources
.first()
.map(|s| s.path().display().to_string())
.unwrap_or_default()
)));
}
Ok(AlltoallGrids { by_keys })
}
fn clone_err(err: &AicError) -> AicError {
AicError::PerfDatabase(err.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
fn gb200_spec() -> SystemSpec {
let yaml = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../python/aisimulate/src/aiconfigurator_core/systems/gb200.yaml");
SystemSpec::load(&yaml).expect("gb200.yaml must parse")
}
fn gb200_trtllm_table() -> TrtllmAlltoallTable {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../python/aisimulate/src/aiconfigurator_core/systems/data/gb200/trtllm/1.3.0rc10",
);
TrtllmAlltoallTable::new(root)
}
#[test]
fn alltoall_kernel_selection_matches_python() {
let spec = gb200_spec();
assert_eq!(select_alltoall_kernel(&spec, 4, 8, None), "NVLinkOneSided");
assert_eq!(
select_alltoall_kernel(&spec, 4, 8, Some("WIDEEP")),
"NVLinkTwoSided"
);
assert_eq!(
select_alltoall_kernel(&spec, 4, 8, Some("DeepGemm")),
"NotEnabled"
);
assert_eq!(
select_alltoall_kernel(&spec, 4, 8, Some("cute_dsl")),
"NotEnabled"
);
let table = gb200_trtllm_table();
let zero = table
.query_trtllm_alltoall(
&spec,
"alltoall_dispatch",
1,
7168,
8,
256,
4,
MoeQuantMode::Fp8,
Some("DEEPGEMM"),
)
.expect("NotEnabled short-circuits");
assert_eq!(zero, 0.0);
}
#[test]
fn alltoall_keying_distinguishes_op_kernel_and_quant() {
let spec = gb200_spec();
let table = gb200_trtllm_table();
let dispatch = table
.query_trtllm_alltoall(
&spec,
"alltoall_dispatch",
1,
7168,
8,
256,
4,
MoeQuantMode::Fp8,
Some("WIDEEP"),
)
.expect("dispatch row");
assert!(dispatch.is_finite() && dispatch > 0.0, "got {dispatch}");
let combine = table
.query_trtllm_alltoall(
&spec,
"alltoall_combine",
1,
7168,
8,
256,
4,
MoeQuantMode::Fp8,
Some("WIDEEP"),
)
.expect("combine row");
assert!(combine.is_finite() && combine > 0.0, "got {combine}");
assert!(
(combine - dispatch).abs() > 1e-12,
"op_name must key the table: dispatch {dispatch} == combine {combine}"
);
let block = table
.query_trtllm_alltoall(
&spec,
"alltoall_dispatch",
1,
7168,
8,
256,
4,
MoeQuantMode::Fp8Block,
Some("WIDEEP"),
)
.expect("fp8_block reroutes to fp8");
assert_eq!(block, dispatch);
let one_sided = table
.query_trtllm_alltoall(
&spec,
"alltoall_dispatch",
1,
7168,
8,
256,
2,
MoeQuantMode::Nvfp4,
None,
)
.expect("one-sided row");
assert!(one_sided.is_finite() && one_sided > 0.0, "got {one_sided}");
assert!(
(one_sided - dispatch).abs() > 1e-12,
"kernel selection must key the table: one-sided {one_sided} == two-sided {dispatch}"
);
}
#[test]
fn alltoall_loader_smoke() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../python/aisimulate/src/aiconfigurator_core/systems/data/b200_sxm/vllm/0.19.0",
);
let spec = gb200_spec();
let table = TrtllmAlltoallTable::new(root);
let err = table
.query_trtllm_alltoall(
&spec,
"alltoall_dispatch",
64,
7168,
8,
256,
4,
MoeQuantMode::Fp8,
Some("WIDEEP"),
)
.unwrap_err();
match err {
AicError::Io { .. } | AicError::PerfDatabase(_) => {}
other => panic!("unexpected error: {other:?}"),
}
}
}