use crate::core::resources::ResourceSpec;
use crate::providers::common::InstanceSelection;
pub struct BittensorLiumInstanceMapper;
impl BittensorLiumInstanceMapper {
pub fn map(spec: &ResourceSpec) -> InstanceSelection {
let gpu_count = spec.gpu_count.unwrap_or(1).max(1);
let gpu_type = match gpu_count {
1 => select_single_gpu(spec),
_ => "H100-80GB",
};
InstanceSelection {
instance_type: gpu_type.to_string(),
spot_capable: false,
estimated_hourly_cost: Some(Self::estimate_hourly_cost(gpu_type) * gpu_count as f64),
}
}
pub fn estimate_hourly_cost(gpu_type: &str) -> f64 {
match gpu_type {
"H100-80GB" => 2.20,
"A100-80GB" => 1.40,
"A100-40GB" => 0.95,
"RTX_4090" => 0.42,
"RTX_3090" => 0.19,
_ => 1.50,
}
}
}
fn select_single_gpu(spec: &ResourceSpec) -> &'static str {
if spec.memory_gb >= 200.0 {
"H100-80GB"
} else if spec.memory_gb >= 100.0 {
"A100-80GB"
} else if spec.memory_gb >= 60.0 {
"A100-40GB"
} else if spec.memory_gb >= 16.0 {
"RTX_4090"
} else {
"RTX_3090"
}
}
#[cfg(test)]
mod tests {
use super::*;
fn spec(memory_gb: f32, gpu_count: u32) -> ResourceSpec {
ResourceSpec {
cpu: 8.0,
memory_gb,
storage_gb: 100.0,
gpu_count: Some(gpu_count),
allow_spot: false,
qos: Default::default(),
}
}
#[test]
fn small_workload_picks_rtx_3090() {
let selection = BittensorLiumInstanceMapper::map(&spec(8.0, 1));
assert_eq!(selection.instance_type, "RTX_3090");
}
#[test]
fn mid_workload_picks_a100_80gb() {
let selection = BittensorLiumInstanceMapper::map(&spec(128.0, 1));
assert_eq!(selection.instance_type, "A100-80GB");
}
#[test]
fn heavy_single_gpu_picks_h100() {
let selection = BittensorLiumInstanceMapper::map(&spec(256.0, 1));
assert_eq!(selection.instance_type, "H100-80GB");
}
#[test]
fn multi_gpu_always_h100() {
let selection = BittensorLiumInstanceMapper::map(&spec(64.0, 4));
assert_eq!(selection.instance_type, "H100-80GB");
}
#[test]
fn cost_scales_with_gpu_count() {
let single = BittensorLiumInstanceMapper::map(&spec(256.0, 1))
.estimated_hourly_cost
.unwrap();
let octa = BittensorLiumInstanceMapper::map(&spec(256.0, 8))
.estimated_hourly_cost
.unwrap();
assert!(octa > single * 7.0);
}
#[test]
fn unknown_gpu_falls_back() {
let cost = BittensorLiumInstanceMapper::estimate_hourly_cost("MI300X");
assert!(
(cost - 1.50).abs() < f64::EPSILON,
"expected 1.50, got {cost}"
);
}
}