use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnergyMetrics {
pub total_joules: f64,
pub average_power_watts: f64,
pub peak_power_watts: f64,
pub duration_seconds: f64,
pub co2_grams: Option<f64>,
pub pue: f64,
}
impl EnergyMetrics {
pub fn new(
total_joules: f64,
average_power_watts: f64,
peak_power_watts: f64,
duration_seconds: f64,
) -> Self {
Self {
total_joules,
average_power_watts,
peak_power_watts,
duration_seconds,
co2_grams: None,
pue: 1.0,
}
}
pub fn with_carbon_intensity(mut self, carbon_intensity_g_per_kwh: f64) -> Self {
let kwh = self.total_joules / 3_600_000.0;
self.co2_grams = Some(kwh * carbon_intensity_g_per_kwh * self.pue);
self
}
pub fn with_pue(mut self, pue: f64) -> Self {
let old_pue = self.pue;
self.pue = pue;
if let Some(co2) = self.co2_grams {
self.co2_grams = Some(co2 / old_pue * pue);
}
self
}
pub fn flops_per_watt(&self, total_flops: f64) -> f64 {
if self.average_power_watts > 0.0 {
total_flops / self.average_power_watts
} else {
0.0
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CostMetrics {
pub compute_cost_usd: f64,
pub storage_cost_usd: f64,
pub network_cost_usd: f64,
pub total_cost_usd: f64,
pub cost_per_flop: Option<f64>,
pub cost_per_sample: Option<f64>,
pub currency: String,
}
impl CostMetrics {
pub fn new(compute_cost: f64, storage_cost: f64, network_cost: f64) -> Self {
Self {
compute_cost_usd: compute_cost,
storage_cost_usd: storage_cost,
network_cost_usd: network_cost,
total_cost_usd: compute_cost + storage_cost + network_cost,
cost_per_flop: None,
cost_per_sample: None,
currency: "USD".to_string(),
}
}
pub fn with_flops(mut self, total_flops: f64) -> Self {
if total_flops > 0.0 {
self.cost_per_flop = Some(self.total_cost_usd / total_flops);
}
self
}
pub fn with_samples(mut self, total_samples: u64) -> Self {
if total_samples > 0 {
self.cost_per_sample = Some(self.total_cost_usd / total_samples as f64);
}
self
}
}