> Les seuils et outils ci-dessous sont ceux du crate eBin (repo 1000-dev-evo ; app canonique 2000-miniTools/130-ebin). Pour le
> benchmark des apps MiddleDAO (Hermes, Livia, OpenFang), voir `app-bench`
> (tableau KPI agents + protocole gradué).
Les benchmarks sur Mac M3 (ARM64 UMA) sont extrêmement sensibles à l'état thermique du CPU. Exécuter tous les benchmarks d'une branche puis tous ceux d'une autre introduit un **biais thermique** : la première branche bénéficie d'un CPU froid, la seconde subit un CPU chaud.
**Conséquence** : des écarts de -50% à +200% qui sont entièrement du bruit thermique, pas des vraies régressions.
### Principe
Alterner les branches : `dev → cnt → dev → cnt → dev`. Jamais exécuter 2 runs consécutifs de la même branche.
### Template d'exécution
# execute_code — A/B alterné, 5 mesures
def run_bench(branch, bench_name):
r = terminal(
f"cd ~/MIDDLEDAO/1000-dev-evo && git checkout {branch} 2>&1 >/dev/null && "
f"COLD_FORGE_BOOTSTRAP=1 cargo test -p evoBin --release --lib '{bench_name}' -- --nocapture 2>&1 "
f"| grep 'ops/sec'",
timeout=120
)
m = re.search(r'(\d+)\s+ops/sec', r["output"])
return int(m.group(1)) if m else 0
results = {"dev": [], "dev-cnt": []}
for i in range(5):
branch = "dev" if i % 2 == 0 else "dev-cnt"
v = run_bench(branch, "stress_10_multithread_ring")
results[branch].append(v)
dev_mean = sum(results["dev"]) / len(results["dev"])
cnt_mean = sum(results["dev-cnt"]) / len(results["dev-cnt"])
delta = (cnt_mean - dev_mean) / dev_mean * 100
### Interprétation
| Delta (A/B alterné) | Verdict |
| ±5% | Bruit statistique — pas de régression |
| ±5-10% | Marge acceptable — surveiller |
| ±10-20% | Régression possible — investiguer |
| >±20% | Régression probable — cause structurelle |
Pour un benchmark isolé (pas de comparaison), lancer **10 runs consécutifs** et calculer le coefficient de variation :
CV = (std_dev / mean) × 100%
| CV | Verdict |
| <10% | Mesure fiable |
| 10-20% | Variance modérée — moyenne fiable |
| 20-40% | Bruit thermique — résultats non-interprétables |
| >40% | Benchmark flaky — ne pas tirer de conclusions |
**Choisir le protocole AVANT d'exécuter** : comparaison de branches/conditions → A/B alterné ; bench mono-branche (baseline, signature métrologique) → protocole CV. Un run ×2 « bit-exact » prouve le DÉTERMINISME, pas la variance : c'est un critère R01, jamais un substitut au CV — deux runs ne donnent aucun coefficient. Toute baseline chiffrée livrée sans CV est une claim non qualifiée. CV calculé en entiers purs (sd via somme des carrés, zéro float).
### Cas réel : AtomicU64 store
Session 2026-08-07, 10 runs consécutifs :
- Mean: 12.9M, StdDev: 5.3M, **CV: 41.0%**
- Min: 6.2M, Max: 21.1M (variation de 3×)
- **Verdict** : bruit thermique pur, aucune conclusion structurelle possible
`05-addins/8-bench/src/hotpath_bench.rs` : bench get/set du hot-path RÉEL (garde
RateLimiter incluse, n=32). Verdicts mesurés (Mac M3, release — les seuils ebin-bench
sont des seuils RELEASE ; dev opt-level=0 = 7,1 M seulement) :
| Mesure | Valeur | Verdict |
| get (zéro-copie mmap) | 173,5 M ops/s release (seuil >50M ✅) | 120,9 M en A/B alterné ×3 (CV ~3 %) |
| set (écriture en place + flush) | 24,7 k ops/s | flush-bound ~40 µs = durabilité, honnête |
| ancien evoBin bench_memcpy_128 | 89,3 M ops/s (CV ~1 %) | bench COPIE — protocole différent du get zéro-copie |
Leçon : comparer ancien (bench copie) vs nouveau (bench zéro-copie) = +36 % apparent,
cause STRUCTURELLE (le get ne copie pas) — déclarer le protocole, ne jamais vendre le
chiffre comme un A/B strict. Absent chez l'ancien : bench get-strate comparable (CRUD
= opcodes MOE).
- Tout tableau comparatif (ancien vs nouveau, variantes) : **sujets comparés en COLONNES, métriques en LIGNES** — un sujet par ligne = non conforme, refaire.
- Ex : `| Métrique | ancien eBin | nouveau eBin (SEGx) | nouveau (TauView) |` — le nouveau grandit à droite.
- get arène ancien (index direct) ≈ 5,6 G ops/s · get-par-id ancien (ColdSeg bit-math)
≈ 1,28 G ops/s (médiane — variance brute 0,88–3,95 G, turbo Mac) · get nouveau = 121,7 M
- **Verdict honnête : l'ANCIEN gagne le get ×10 (H2 falsifiée)** — id=adresse (R13) sans
index vs BTreeMap+mmap. Le nouveau achète pour ce coût : persistence conteneur disque,
seal/crypto ChaCha, layouts déclaratifs, format 08-ebin composite.
- V1 doctrinal 319 M (CV ~6 %) · **V2 tau-guard = TauView 3 228 M (CV <0,3 % — le plus
déterministe)** · V3 arène ancienne 1 208 M (CV ~7 %). TauView = ×10,1 vs V1, ×2,7
vs arène ancienne. Machine chaude : les 3 bras baissent ensemble (turbo), l'ÉCART s'élargit.
- Soluce get-perf CLOSE : tout l'outillage coldCompute applicable est appliqué ; le coût
restant (mmap file vs arène RAM) = choix d'architecture (durabilité), pas un outil manquant.
- Déclarer TOUJOURS le chemin exact (arène RAM vs mmap file ; index implicite vs lookup).
- **set = FLUSH-BOUND à variance élevée** : 24,7 k vs 12,8 k ops/s observés (spread ~48 %
> 40 % = non-interprétable en absolu, protocole CV). La métrique FIABLE du hot-path
eBin = **get**. Seuil set = sanité seulement (>5k). Cause : le flush mmap = I/O disque,
sensible à l'état du cache FS.
- **Seuils profil-aware** : les seuils du skill (get >50M) sont RELEASE ; en dev
(opt-level=0) le get tourne ~7-8M — jamais évaluer un bench dev avec des seuils release
(bench hotpath_bench.rs fait cfg!(debug_assertions)).
| Erreur | Conséquence | Correction |
| Exécuter tous les benchmarks d'une branche puis l'autre | Biais thermique -50% à +200% | A/B alterné |
| Tirer des conclusions d'un seul run | Données non fiables | Minimum 3 runs, idéalement 5 A/B |
| Comparer branches avec toolchains différentes | Layout change avec Rust version | Même toolchain obligatoire |
| Attribuer régression au code alors qu'elle vient de la layout | Mauvaise correction | Vérifier taille binaire (nm, ls -la) |
| Ignorer CV >20% et présenter résultat comme factuel | Décision basée sur bruit | Calculer CV, rejeter si >20% |
Quand une régression apparaît après l'ajout de code :
ls -la target/release/evoBin
nm target/release/evoBin | wc -l
Si la différence est <0.1%, la régression vient de la **layout** (repositionnement des fonctions dans `.text`), pas du code ajouté. Solution : `#[cfg(feature = "...")]` pour exclure le code non-utilisé.
Quand un module ajouté au binaire déplace les hot-loops et cause des régressions multi-thread :
# Cargo.toml
[features]
default = []
midos = ["regex-lite"]
// lib.rs
#[cfg(feature = "midos")]
pub mod midos;
# Containerfile (production uniquement)
RUN cargo build --release --features midos
**Effet** : le binaire par défaut (bench/dev) n'inclut pas le module → layout intact. Le binaire container inclut le module → fonctionnalité complète.
**Résultat mesuré** : CV du ring P+E-Core passe de 20.3% (midos inclus) à 6.4% (sans midos). Binaire : 80B de différence (0.008%).
| Métrique | Seuil | Source |
| AtomicU64 load | >40M ops/s | benchMacro |
| AtomicU64 store | >25M ops/s (CV <15%) | benchMacro |
| XOR resonance | >50M ops/s | benchMacro |
| memcpy 128B | >50M ops/s | benchMacro |
| TETRA_ADD 8 threads | >150M ops/s | benchStress |
| Ring P+E-Core | >30M ops/s | benchStress |
| NOP stability 10M | >20M ops/s | benchStress |
| Métrique | Seuil | Notes |
| AtomicU64 load | >50M ops/s | RDTSC haute résolution |
| TETRA_ADD 8 threads | >100M ops/s | |
| Ring P+E-Core | >25M ops/s |
### MdaoMetrics — métriques d'observabilité hot-path
Commit `3d6b9ad` : `MdaoMetrics` câble des compteurs d'observabilité **directement dans le hot-path** du runtime eBin. Contrairement aux benchmarks ponctuels (benchMacro, benchStress), MdaoMetrics collecte des métriques en continu pendant l'exécution normale.
**Usage** : détecter des dégradations progressives (memory leaks, contention croissante) que les benchmarks A/B alternés ne capturent pas forcément.
### KPIs coldCompute dans le hot-path
Commit `154c147` : les indicateurs clés de performance (KPIs) de coldCompute sont câblés dans le hot-path via MdaoMetrics. Cela permet de surveiller en continu les métriques spécifiques à coldCompute (densité, calibration, supraconductivité) sans interrompre le flux d'exécution.
### Bench coldcompute_effect — indice d'effet A/B
Commit `b8af03f` : le bench `coldcompute_effect` mesure l'**indice d'effet** de coldCompute via une comparaison A/B. Il quantifie l'impact réel de coldCompute sur les performances en alternant états activé/désactivé, appliquant la même méthodologie anti-biais thermique que les benchmarks classiques.
**Format de sortie réel** (`coldcompute_effect.rs`, report) :
[ EFFECT ] nom_primitive : cold=NNNNN classic=NNNNN gain=X.X× ✅/⚠️
Le gain est un ratio `classic/cold` en cycles (≥1.0 = ✅ coldCompute gagne). Primitives comparées : equator (AND vs branch), tetra (SHR vs DIV), fast_modulo (AND vs %), etc. — 1000 itérations via QuartzTuner::rdtsc, `#![deny(clippy::float_arithmetic)]` dans le bench.
Ces trois outils complètent la méthodologie de benchmark A/B alterné :
- **Bench A/B alterné** : mesure ponctuelle, comparaison de branches, anti-biais thermique.
- **MdaoMetrics + KPIs coldCompute** : observabilité continue du hot-path en production/développement.
- **coldcompute_effect** : mesure A/B de l'effet spécifique de coldCompute, pas de branches entières.
Ensemble, ils forment un système complet : bench pour les régressions ponctuelles, metrics pour la surveillance continue, effect pour quantifier l'impact d'un sous-système.