use crate::core::resources::ResourceSpec;
use crate::providers::common::InstanceSelection;
pub struct LambdaLabsInstanceMapper;
impl LambdaLabsInstanceMapper {
pub fn map(spec: &ResourceSpec) -> InstanceSelection {
let gpu_count = spec.gpu_count.unwrap_or(1).max(1);
let instance_type = match gpu_count {
1 => select_single_gpu(spec),
2 => "gpu_2x_a100_pcie",
4 => "gpu_4x_a100",
8 if spec.memory_gb > 512.0 => "gpu_8x_h100_sxm",
8 => "gpu_8x_a100",
_ => "gpu_8x_h100_sxm",
};
InstanceSelection {
instance_type: instance_type.to_string(),
spot_capable: false,
estimated_hourly_cost: Some(Self::estimate_hourly_cost(instance_type)),
}
}
pub fn estimate_hourly_cost(instance_type: &str) -> f64 {
match instance_type {
"gpu_1x_a10" => 0.75,
"gpu_1x_a100_pcie" => 1.29,
"gpu_1x_a100" => 1.29,
"gpu_1x_a6000" => 0.80,
"gpu_1x_h100_pcie" => 2.49,
"gpu_2x_a100_pcie" => 2.58,
"gpu_4x_a100" => 5.16,
"gpu_8x_a100" => 10.32,
"gpu_8x_h100_sxm" => 23.92,
_ => 2.00,
}
}
}
fn select_single_gpu(spec: &ResourceSpec) -> &'static str {
if spec.memory_gb >= 200.0 {
"gpu_1x_h100_pcie"
} else if spec.memory_gb >= 100.0 {
"gpu_1x_a100"
} else if spec.memory_gb >= 48.0 {
"gpu_1x_a6000"
} else {
"gpu_1x_a10"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn selects_single_a10_for_small_spec() {
let spec = ResourceSpec {
cpu: 4.0,
memory_gb: 16.0,
storage_gb: 100.0,
gpu_count: Some(1),
allow_spot: false,
qos: Default::default(),
};
let selection = LambdaLabsInstanceMapper::map(&spec);
assert_eq!(selection.instance_type, "gpu_1x_a10");
assert!(!selection.spot_capable);
}
#[test]
fn selects_h100_for_heavy_memory() {
let spec = ResourceSpec {
cpu: 16.0,
memory_gb: 256.0,
storage_gb: 1000.0,
gpu_count: Some(1),
allow_spot: false,
qos: Default::default(),
};
let selection = LambdaLabsInstanceMapper::map(&spec);
assert_eq!(selection.instance_type, "gpu_1x_h100_pcie");
}
#[test]
fn selects_8x_h100_for_sxm_class() {
let spec = ResourceSpec {
cpu: 64.0,
memory_gb: 1024.0,
storage_gb: 8000.0,
gpu_count: Some(8),
allow_spot: false,
qos: Default::default(),
};
let selection = LambdaLabsInstanceMapper::map(&spec);
assert_eq!(selection.instance_type, "gpu_8x_h100_sxm");
}
#[test]
fn never_spot_capable() {
let spec = ResourceSpec {
cpu: 4.0,
memory_gb: 16.0,
storage_gb: 100.0,
gpu_count: Some(2),
allow_spot: true,
qos: Default::default(),
};
let selection = LambdaLabsInstanceMapper::map(&spec);
assert!(!selection.spot_capable);
}
#[test]
fn cost_estimate_scales_with_gpu_count() {
let single = LambdaLabsInstanceMapper::estimate_hourly_cost("gpu_1x_a100");
let eight = LambdaLabsInstanceMapper::estimate_hourly_cost("gpu_8x_a100");
assert!(eight > single * 4.0, "8x should be more than 4x single");
}
#[test]
fn unknown_instance_falls_back_to_default_cost() {
let cost = LambdaLabsInstanceMapper::estimate_hourly_cost("gpu_42x_unobtainium");
assert!(
(cost - 2.0).abs() < f64::EPSILON,
"expected 2.0, got {cost}"
);
}
}