use std::cmp::Ordering;
use std::collections::BTreeMap;
use super::carbon::{
self, CO2_MODEL, CO2_MODEL_CLOUD_SPECPOWER, CO2_MODEL_EMAPS, CO2_MODEL_KEPLER,
CO2_MODEL_REDFISH, CO2_MODEL_SCAPHANDRE, CO2_MODEL_V2, CO2_MODEL_V3, CarbonEstimate,
CarbonReport, GENERIC_PUE, IntensitySource, REGION_STATUS_KNOWN, REGION_STATUS_OUT_OF_TABLE,
REGION_STATUS_UNRESOLVED, RegionBreakdown, UNKNOWN_REGION, lookup_region_lower,
};
#[derive(Default)]
#[allow(clippy::struct_excessive_bools)]
pub(super) struct RegionAccumulator {
pub(super) co2_gco2: f64,
pub(super) total_ops: usize,
pub(super) intensity_sum_per_op: f64,
pub(super) max_intensity_source: IntensitySource,
pub(super) any_scaphandre: bool,
pub(super) any_kepler_ebpf: bool,
pub(super) any_redfish_bmc: bool,
pub(super) any_cloud_specpower: bool,
pub(super) any_calibrated: bool,
pub(super) realtime_estimated: Option<bool>,
pub(super) realtime_estimation_method: Option<String>,
}
#[derive(Default, Clone, Copy)]
#[allow(clippy::struct_excessive_bools)]
pub(super) struct ReportFlags {
any_hourly: bool,
any_monthly_hourly: bool,
any_scaphandre: bool,
any_kepler_ebpf: bool,
any_redfish_bmc: bool,
any_cloud_specpower: bool,
any_calibrated: bool,
any_realtime: bool,
}
pub(super) fn build_region_breakdowns(
per_region: BTreeMap<String, RegionAccumulator>,
unknown_ops: usize,
) -> (Vec<RegionBreakdown>, ReportFlags, f64) {
let mut regions: Vec<RegionBreakdown> = Vec::with_capacity(per_region.len() + 1);
let mut flags = ReportFlags::default();
let mut operational_gco2: f64 = 0.0;
for (region, acc) in per_region {
operational_gco2 += acc.co2_gco2;
update_flags_from_accumulator(&mut flags, &acc);
regions.push(build_single_region_row(region, acc));
}
if unknown_ops > 0 {
tracing::debug!(
"{unknown_ops} I/O ops had no resolvable region and were excluded \
from operational CO₂ estimates. Set [green] default_region or \
[green.service_regions] to attribute them."
);
regions.push(RegionBreakdown {
status: REGION_STATUS_UNRESOLVED.to_string(),
region: UNKNOWN_REGION.to_string(),
grid_intensity_gco2_kwh: 0.0,
pue: 0.0,
io_ops: unknown_ops,
co2_gco2: 0.0,
intensity_source: IntensitySource::Annual,
intensity_estimated: None,
intensity_estimation_method: None,
});
}
(regions, flags, operational_gco2)
}
fn update_flags_from_accumulator(flags: &mut ReportFlags, acc: &RegionAccumulator) {
match acc.max_intensity_source {
IntensitySource::RealTime => {
flags.any_realtime = true;
}
IntensitySource::MonthlyHourly => {
flags.any_monthly_hourly = true;
flags.any_hourly = true;
}
IntensitySource::Hourly => {
flags.any_hourly = true;
}
IntensitySource::Annual => {}
}
flags.any_scaphandre |= acc.any_scaphandre;
flags.any_kepler_ebpf |= acc.any_kepler_ebpf;
flags.any_redfish_bmc |= acc.any_redfish_bmc;
flags.any_cloud_specpower |= acc.any_cloud_specpower;
flags.any_calibrated |= acc.any_calibrated;
}
fn build_single_region_row(region: String, acc: RegionAccumulator) -> RegionBreakdown {
if let Some((_, pue)) = lookup_region_lower(®ion) {
let mean_intensity = acc.intensity_sum_per_op / acc.total_ops as f64;
let intensity_source = acc.max_intensity_source;
let total_ops = acc.total_ops;
let co2_gco2 = acc.co2_gco2;
let (intensity_estimated, intensity_estimation_method) =
realtime_metadata_for_row(intensity_source, acc);
return RegionBreakdown {
status: REGION_STATUS_KNOWN.to_string(),
region,
grid_intensity_gco2_kwh: mean_intensity,
pue,
io_ops: total_ops,
co2_gco2,
intensity_source,
intensity_estimated,
intensity_estimation_method,
};
}
let has_co2 = acc.co2_gco2 > 0.0;
if !has_co2 {
tracing::debug!(
"Region '{region}' is not in the embedded carbon table; \
{ops} I/O ops contribute 0 to operational CO₂. \
See docs/CONFIGURATION.md for the list of supported regions.",
ops = acc.total_ops
);
}
let mean_intensity = if acc.total_ops > 0 && has_co2 {
acc.intensity_sum_per_op / acc.total_ops as f64
} else {
0.0
};
let pue_display = if has_co2 { GENERIC_PUE } else { 0.0 };
let intensity_source = if has_co2 {
acc.max_intensity_source
} else {
IntensitySource::Annual
};
let total_ops = acc.total_ops;
let co2_gco2 = acc.co2_gco2;
let (intensity_estimated, intensity_estimation_method) =
realtime_metadata_for_row(intensity_source, acc);
RegionBreakdown {
status: REGION_STATUS_OUT_OF_TABLE.to_string(),
region,
grid_intensity_gco2_kwh: mean_intensity,
pue: pue_display,
io_ops: total_ops,
co2_gco2,
intensity_source,
intensity_estimated,
intensity_estimation_method,
}
}
fn realtime_metadata_for_row(
source: IntensitySource,
acc: RegionAccumulator,
) -> (Option<bool>, Option<String>) {
if source == IntensitySource::RealTime {
(acc.realtime_estimated, acc.realtime_estimation_method)
} else {
(None, None)
}
}
pub(super) fn select_co2_model_tag(flags: ReportFlags) -> &'static str {
if flags.any_realtime {
CO2_MODEL_EMAPS
} else if flags.any_scaphandre {
CO2_MODEL_SCAPHANDRE
} else if flags.any_kepler_ebpf {
CO2_MODEL_KEPLER
} else if flags.any_redfish_bmc {
CO2_MODEL_REDFISH
} else if flags.any_cloud_specpower {
CO2_MODEL_CLOUD_SPECPOWER
} else {
select_proxy_co2_model_tag(
flags.any_monthly_hourly,
flags.any_hourly,
flags.any_calibrated,
)
}
}
fn select_proxy_co2_model_tag(
monthly_hourly: bool,
hourly: bool,
calibrated: bool,
) -> &'static str {
if monthly_hourly {
if calibrated {
carbon::CO2_MODEL_V3_CAL
} else {
CO2_MODEL_V3
}
} else if hourly {
if calibrated {
carbon::CO2_MODEL_V2_CAL
} else {
CO2_MODEL_V2
}
} else if calibrated {
carbon::CO2_MODEL_V1_CAL
} else {
CO2_MODEL
}
}
#[must_use]
pub(super) fn avoidable_share(
window_total: f64,
avoidable_io_ops: usize,
accounted_io_ops: usize,
) -> f64 {
if accounted_io_ops > 0 {
let ratio = (avoidable_io_ops as f64 / accounted_io_ops as f64).min(1.0);
window_total * ratio
} else {
0.0
}
}
#[allow(clippy::too_many_arguments)]
pub(super) fn finalize_carbon_report(
traces_len: usize,
operational_gco2: f64,
total_transport_gco2: f64,
total_io_ops: usize,
avoidable_io_ops: usize,
unknown_ops: usize,
embodied_per_request_gco2: f64,
model: &'static str,
) -> CarbonReport {
let embodied_gco2 = traces_len as f64 * embodied_per_request_gco2;
let total_mid = operational_gco2 + embodied_gco2 + total_transport_gco2;
let accounted_io_ops = total_io_ops.saturating_sub(unknown_ops);
let avoidable_mid = avoidable_share(operational_gco2, avoidable_io_ops, accounted_io_ops);
let transport_gco2 = if total_transport_gco2 > 0.0 {
Some(total_transport_gco2)
} else {
None
};
let total_methodology = if transport_gco2.is_some() {
carbon::METHODOLOGY_SCI_NUMERATOR_TRANSPORT
} else {
carbon::METHODOLOGY_SCI_NUMERATOR
};
let sci_per_trace = (traces_len > 0).then(|| {
CarbonEstimate::new_with_model(
total_mid / traces_len as f64,
model,
carbon::METHODOLOGY_SCI_INTENSITY,
)
});
CarbonReport {
total: CarbonEstimate::new_with_model(total_mid, model, total_methodology),
avoidable: CarbonEstimate::operational_ratio_with_model(avoidable_mid, model),
operational_gco2,
embodied_gco2,
transport_gco2,
sci_per_trace,
functional_unit: "trace".to_string(),
}
}
pub(super) fn sort_regions_by_co2_desc(regions: &mut [RegionBreakdown]) {
regions.sort_by(|a, b| {
b.co2_gco2
.partial_cmp(&a.co2_gco2)
.unwrap_or(Ordering::Equal)
.then_with(|| a.region.cmp(&b.region))
});
}