use serde::{Deserialize, Serialize};
use crate::hnep::{Confidence, HnepProfile, SizeClassEntry, WorkloadEntry};
use crate::Result;
pub const SCF_FORMAT: &str = "silicera-compiler-feedback";
pub const SCF_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScfWorkload {
pub name: String,
pub winner: String,
pub confidence: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub baseline: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub winner_median_ns: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub baseline_median_ns: Option<f64>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub rationale: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScfSizeClass {
pub class: String,
pub threshold_bytes: u64,
pub working_set_bytes: u64,
pub winner: String,
pub confidence: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompilerFeedback {
pub format: String,
pub version: u32,
pub silicera_version: String,
pub fingerprint: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub host_brand: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub microarchitecture: Option<String>,
pub workloads: Vec<ScfWorkload>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub size_classes: Vec<ScfSizeClass>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fallback_variant: Option<String>,
pub caveats: Vec<String>,
}
impl CompilerFeedback {
pub fn from_hnep(profile: &HnepProfile) -> Result<Self> {
profile.verify_integrity()?;
let fp = profile.header.fingerprint.clone();
let microarchitecture = fp
.split(':')
.nth(2)
.map(|s| s.to_ascii_lowercase());
let workloads = profile
.workloads
.iter()
.map(workload_to_scf)
.collect::<Vec<_>>();
let size_classes = profile
.size_classes
.iter()
.map(size_class_to_scf)
.collect::<Vec<_>>();
let fallback_variant = profile
.decision_tree
.as_ref()
.map(|t| t.fallback_variant.clone());
Ok(Self {
format: SCF_FORMAT.into(),
version: SCF_VERSION,
silicera_version: crate::VERSION.into(),
fingerprint: fp,
host_brand: None,
microarchitecture,
workloads,
size_classes,
fallback_variant,
caveats: vec![
"SCF is experimental; not an LLVM ABI.".into(),
"Winners are machine-local measurements; re-verify on the target host.".into(),
"Fingerprint identifies the specialization environment — not authentication."
.into(),
"Community or cross-machine recommendations must be treated as candidates only."
.into(),
],
})
}
pub fn to_json_pretty(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(self)?)
}
pub fn write_to(&self, path: &std::path::Path) -> Result<()> {
std::fs::write(path, self.to_json_pretty()?)?;
Ok(())
}
}
fn workload_to_scf(w: &WorkloadEntry) -> ScfWorkload {
ScfWorkload {
name: w.name.clone(),
winner: w.winner.clone(),
confidence: conf_label(w.confidence),
baseline: None,
winner_median_ns: w.winner_median_ns,
baseline_median_ns: w.baseline_median_ns,
rationale: w.rationale.clone(),
}
}
fn size_class_to_scf(c: &SizeClassEntry) -> ScfSizeClass {
ScfSizeClass {
class: c.class.clone(),
threshold_bytes: c.threshold_bytes,
working_set_bytes: c.working_set_bytes,
winner: c.winner.clone(),
confidence: conf_label(c.confidence),
}
}
fn conf_label(c: Confidence) -> String {
c.label().into()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hardware::EnvironmentSnapshot;
use crate::hnep::{HnepHeader, IntegrityDigest};
#[test]
fn scf_roundtrip_empty_workloads() {
let mut profile = HnepProfile {
header: HnepHeader {
format: crate::hnep::HNEP_FORMAT.into(),
version: crate::hnep::HNEP_VERSION,
silicera_version: crate::VERSION.into(),
created_at: "1970-01-01T00:00:00Z".into(),
fingerprint: "SLC:AMD:ZEN5:00:00:00:deadbeefdeadbeef:cafebabecafebabe".into(),
label: "test".into(),
},
environment: EnvironmentSnapshot::capture(),
workloads: vec![],
size_classes: vec![],
decision_tree: None,
digest: IntegrityDigest {
alg: "sha256".into(),
hex: String::new(),
},
};
profile.recompute_digest().unwrap();
let scf = CompilerFeedback::from_hnep(&profile).unwrap();
assert_eq!(scf.format, SCF_FORMAT);
assert_eq!(scf.version, SCF_VERSION);
assert_eq!(scf.microarchitecture.as_deref(), Some("zen5"));
let json = scf.to_json_pretty().unwrap();
assert!(json.contains("silicera-compiler-feedback"));
}
}