[FIX] imbrication : le coût d'un vCPU dépend de la profondeur de l'étage

Amorçage du quatrième étage, mesuré sur deux descentes complètes : 1 664 s à
2 vCPU, 15 608 s à 3. Un seul vCPU de plus, ×9,4. Aux étages 2 et 3 le même
vCPU ne coûte RIEN — ssh en 37 s et 93 s, comme à deux.

Le « gel » observé à 8 et 12 vCPU n'est probablement pas autre chose que cette
courbe poussée assez loin : 1 664 × 9,4 par vCPU dépasse vite toute patience,
et un RIP immobile à cinq minutes d'intervalle ne s'en distingue pas.

D'où un SEUIL de profondeur au lieu d'une largeur uniforme. Le troisième vCPU
reste aux étages 2 et 3, où il est gratuit et où il enlève le surengagement
qui affamait l'installation de l'étage 4 — celle-ci ne finissait pas avec un
parent à 2 vCPU, elle progresse avec un parent à 3. À partir du quatrième
étage, le strict minimum.

La combinaison ainsi obtenue — parent 3, enfant 2 — n'a jamais été mesurée :
les deux essais étaient (2, 2) et (3, 3).

--- EN ---

Fourth-level boot, measured on two full descents: 1,664 s at 2 vCPU, 15,608 s
at 3. One more vCPU, ×9.4. At levels 2 and 3 that same vCPU costs NOTHING —
ssh in 37 s and 93 s, same as at two.

The "freeze" seen at 8 and 12 vCPU is most likely nothing but this curve taken
far enough: 1,664 × 9.4 per vCPU quickly exceeds any patience, and a static
RIP five minutes apart is indistinguishable from it.

Hence a depth THRESHOLD instead of a uniform width. The third vCPU stays at
levels 2 and 3, where it is free and where it removes the overcommit that
starved level 4's install — which never finished with a 2-vCPU parent and does
progress with a 3-vCPU one. From the fourth level down, the strict minimum.

The resulting combination — parent 3, child 2 — has never been measured: the
two attempts were (2, 2) and (3, 3).

Assisted-by: claude-opus-5
(cherry picked from commit 9a5583a4b9461a087d161775764c560c82e0609e)
This commit is contained in:
Mathieu Benoit 2026-08-27 15:39:24 -04:00
parent b2b3f36026
commit 30399b4559
2 changed files with 60 additions and 15 deletions

View file

@ -101,14 +101,25 @@ DISQUE_MIN_GO = 15
# Le plus profond : deux, le seul chiffre dont on ait la preuve qu'il démarre
# au quatrième étage.
VCPU_IMBRIQUE = 2
# Les étages imbriqués intermédiaires : un de plus, pour héberger leur enfant
# Les étages imbriqués PEU PROFONDS : un de plus, pour héberger leur enfant
# sans être aussi étroits que lui. Deux hébergeant deux, c'est cent pour cent
# de surengagement — et l'installation de l'étage 4 dépassait alors 2 h 50
# contre 793 s pour l'étage 3.
#
# Trois est une HYPOTHÈSE : on a la preuve que deux démarre au quatrième étage
# et que huit gèle, rien entre les deux. C'est la descente qui tranchera.
# « Peu profonds », et c'est la mesure qui l'impose. Ce troisième vCPU ne coûte
# RIEN aux étages 2 et 3 — leur ssh répond en 37 s et 93 s, comme à deux vCPU —
# et il coûte tout au quatrième : 15 608 s, soit 4 h 20, contre 1 664 s à deux
# vCPU. Un seul vCPU de plus, l'amorçage multiplié par 9,4.
VCPU_INTERMEDIAIRE = 3
# Le premier étage qui doit rester au strict minimum.
#
# Amorçage du quatrième étage, mesuré : 1 664 s à 2 vCPU, 15 608 s à 3, jamais
# à 8 ni à 12 — même RIP à cinq minutes d'intervalle. Le « gel » observé à 8 et
# 12 n'est probablement pas autre chose que cette courbe poussée assez loin :
# 1 664 × 9,4 par vCPU supplémentaire dépasse vite toute patience.
#
# Aux étages 2 et 3, la même largeur ne coûte rien. Le seuil est donc là.
SEUIL_ETROIT = 4
# Le premier étage tourne sur le MÉTAL : aucun risque de gel, et son amorçage
# est rapide — onze vCPU y ont démarré en 42 s. Il n'a pourtant qu'un enfant à
# trois vCPU à servir ; quatre suffisent, et laissent la machine physique aux
@ -178,8 +189,9 @@ def nesting_plan(
étages tienne : la cible du bas, plus un surcoût par étage au-dessus.
Le processeur n'en fait PAS partie de la même façon : il ne croît
pas avec la profondeur, puisque tout étage imbriqué reste étroit. Le
premier étage demande VCPU_METAL, quelle que soit la profondeur.
pas avec la profondeur — il DÉCROÎT, et se stabilise à
VCPU_IMBRIQUE dès SEUIL_ETROIT. Le premier étage demande VCPU_METAL,
quelle que soit la profondeur.
"""
return (
PVE_RAM_CIBLE_MO + (d - 1) * PVE_RAM_MO,
@ -212,15 +224,21 @@ def nesting_plan(
niveaux = [
{
"niveau": niveau,
# Trois largeurs, et aucune ne dépend de la profondeur : le
# métal en premier, le fond au plus étroit, les intermédiaires
# juste assez larges pour héberger leur enfant.
# Le métal peut être large ; un étage imbriqué peu profond
# gagne son troisième vCPU pour héberger son enfant sans
# surengagement ; à partir de SEUIL_ETROIT, le strict minimum,
# parce que là ce troisième vCPU multiplie l'amorçage par 9,4.
#
# L'étage juste AU-DESSUS du seuil garde donc trois quand son
# enfant en a deux : c'est le seul endroit de la descente où le
# surengagement disparaît, et c'est celui qui compte, puisque
# l'étage 4 est le premier dont l'installation s'effondrait.
"vcpu": (
VCPU_METAL
if niveau == 1
else (
VCPU_IMBRIQUE
if niveau == atteignable
if niveau >= SEUIL_ETROIT
else VCPU_INTERMEDIAIRE
)
),

View file

@ -83,14 +83,41 @@ class TestLePlanDesEtages(unittest.TestCase):
)
def test_the_three_widths_are_where_they_belong(self):
"""Le coût d'un vCPU dépend de la PROFONDEUR de l'étage, pas d'une
largeur absolue.
Mesuré : le troisième vCPU ne coûte rien aux étages 2 et 3 — ssh en
37 s et 93 s, comme à deux vCPU — et coûte 4 h 20 au quatrième, contre
1 664 s à deux. Un seul vCPU de plus, l'amorçage ×9,4."""
niveaux = nesting.nesting_plan(6, **self.HOTE)["niveaux"]
largeurs = {n["niveau"]: n["vcpu"] for n in niveaux}
# Le métal : aucun risque de gel, onze vCPU y ont démarré en 42 s.
self.assertEqual(niveaux[0]["vcpu"], nesting.VCPU_METAL)
# Le fond : le seul chiffre dont on ait la preuve qu'il démarre au
# quatrième étage.
self.assertEqual(niveaux[-1]["vcpu"], nesting.VCPU_IMBRIQUE)
for n in niveaux[1:-1]:
self.assertEqual(n["vcpu"], nesting.VCPU_INTERMEDIAIRE)
self.assertEqual(largeurs[1], nesting.VCPU_METAL)
# Peu profonds : le troisième vCPU est gratuit, et il enlève le
# surengagement là où l'installation s'effondrait.
for niveau in range(2, nesting.SEUIL_ETROIT):
self.assertEqual(
largeurs[niveau], nesting.VCPU_INTERMEDIAIRE, f"étage {niveau}"
)
# À partir du seuil : le strict minimum, sans exception.
for niveau in range(nesting.SEUIL_ETROIT, 7):
self.assertEqual(
largeurs[niveau], nesting.VCPU_IMBRIQUE, f"étage {niveau}"
)
def test_the_level_above_the_threshold_keeps_its_headroom(self):
"""C'est le seul endroit de la descente où le surengagement disparaît,
et c'est celui qui compte : l'étage 4 est le premier dont
l'installation s'effondrait, faute d'un parent plus large que lui.
Les deux combinaisons mesurées étaient (parent 2, enfant 2) — démarre
en 1 664 s puis l'installation ne finit pas — et (parent 3, enfant 3) —
démarre en 15 608 s. Celle-ci est (parent 3, enfant 2)."""
niveaux = nesting.nesting_plan(6, **self.HOTE)["niveaux"]
largeurs = {n["niveau"]: n["vcpu"] for n in niveaux}
parent = largeurs[nesting.SEUIL_ETROIT - 1]
enfant = largeurs[nesting.SEUIL_ETROIT]
self.assertGreater(parent, enfant)
def test_a_single_level_descent_runs_on_metal(self):
niveaux = nesting.nesting_plan(1, **self.HOTE)["niveaux"]