diff --git a/LongTest/README.base.md b/LongTest/README.base.md index 2e9c8ef..50fbd93 100644 --- a/LongTest/README.base.md +++ b/LongTest/README.base.md @@ -33,11 +33,36 @@ Which is the point of the script: a number obtained once, on one machine, in one chain, is an anecdote. ``` -./LongTest/deep_proxmox.py --depth 10 --dry-run # the plan, nothing created -./LongTest/deep_proxmox.py --depth 10 # hours +./LongTest/deep_proxmox.py # three levels, ~30 minutes +./LongTest/deep_proxmox.py --dry-run # the plan, nothing created +./LongTest/deep_proxmox.py --depth 5 # ask for more, knowingly ./LongTest/deep_proxmox.py --detruire # undo it ``` +### How deep is worth asking for + +The depth is the only setting, and **three** is the default because three +works. Measured on a 28-core machine, one full descent per row: + +| level | boot (ssh) | install | total | +|------:|-----------:|--------:|------:| +| 1 | 0 s | 200 s | 280 s | +| 2 | 37 s | 344 s | 495 s | +| 3 | 93 s | 777 s | 1 064 s | +| 4 | **15 608 s** | **26 306 s** | did not finish | + +Three levels cost half an hour. The **fourth** cost 4 h 20 of boot and 7 h 18 +of install on the same machine — everything there is 15 to 30 times slower, not +just one step. And it lands exactly where the hardware vendors stop: level 4 is +the *third* nested hypervisor, and AMD documents two. + +A wider guest makes it worse, sharply: at level 4, one extra vCPU multiplied +the boot by 9.4 (1 664 s at two vCPU, 15 608 s at three), and at eight vCPU the +guest read 32 MiB in 106 minutes with a static instruction pointer. At levels 2 +and 3 that same vCPU costs nothing. + +So: three by default, five if you want to know, ten only to watch the wall. + The descent is **uniform**. Every level, the first included, goes through the same six steps: create, wait for ssh, install Proxmox, reboot and check the kernel, bring pmxcfs back up, check the storage. Only creation differs — @@ -141,11 +166,37 @@ D'où le script : un chiffre obtenu une fois, sur une machine, dans une chaîne, est une anecdote. ``` -./LongTest/deep_proxmox.py --depth 10 --dry-run # le plan, rien de créé -./LongTest/deep_proxmox.py --depth 10 # des heures +./LongTest/deep_proxmox.py # trois étages, ~30 minutes +./LongTest/deep_proxmox.py --dry-run # le plan, rien de créé +./LongTest/deep_proxmox.py --depth 5 # en demander plus, sciemment ./LongTest/deep_proxmox.py --detruire # défaire ``` +### Quelle profondeur vaut la peine d'être demandée + +La profondeur est le seul réglage, et **trois** est le défaut parce que trois +marche. Mesuré sur une machine à 28 cœurs, une descente complète par ligne : + +| étage | amorçage (ssh) | installation | total | +|------:|---------------:|-------------:|------:| +| 1 | 0 s | 200 s | 280 s | +| 2 | 37 s | 344 s | 495 s | +| 3 | 93 s | 777 s | 1 064 s | +| 4 | **15 608 s** | **26 306 s** | n'a pas abouti | + +Trois étages coûtent une demi-heure. Le **quatrième** a coûté 4 h 20 +d'amorçage et 7 h 18 d'installation sur la même machine — tout y est 15 à 30 +fois plus lent, pas une seule étape. Et cela tombe précisément là où les +fabricants s'arrêtent : le quatrième étage est le *troisième* hyperviseur +imbriqué, et AMD en documente deux. + +Un invité plus large aggrave brutalement : au quatrième étage, un vCPU de plus +a multiplié l'amorçage par 9,4 (1 664 s à deux vCPU, 15 608 s à trois), et à +huit vCPU l'invité a lu 32 Mio en 106 minutes, pointeur d'instruction +immobile. Aux étages 2 et 3, ce même vCPU ne coûte rien. + +Donc : trois par défaut, cinq pour savoir, dix seulement pour voir le mur. + La descente est **uniforme**. Chaque étage, le premier compris, passe par les mêmes six étapes : créer, attendre le ssh, installer Proxmox, redémarrer et vérifier le noyau, remettre pmxcfs debout, contrôler le stockage. Seule la diff --git a/LongTest/README.fr.md b/LongTest/README.fr.md index 67e05c2..55137c3 100644 --- a/LongTest/README.fr.md +++ b/LongTest/README.fr.md @@ -32,11 +32,37 @@ D'où le script : un chiffre obtenu une fois, sur une machine, dans une chaîne, est une anecdote. ``` -./LongTest/deep_proxmox.py --depth 10 --dry-run # le plan, rien de créé -./LongTest/deep_proxmox.py --depth 10 # des heures +./LongTest/deep_proxmox.py # trois étages, ~30 minutes +./LongTest/deep_proxmox.py --dry-run # le plan, rien de créé +./LongTest/deep_proxmox.py --depth 5 # en demander plus, sciemment ./LongTest/deep_proxmox.py --detruire # défaire ``` +### Quelle profondeur vaut la peine d'être demandée + +La profondeur est le seul réglage, et **trois** est le défaut parce que trois +marche. Mesuré sur une machine à 28 cœurs, une descente complète par ligne : + +| étage | amorçage (ssh) | installation | total | +|------:|---------------:|-------------:|------:| +| 1 | 0 s | 200 s | 280 s | +| 2 | 37 s | 344 s | 495 s | +| 3 | 93 s | 777 s | 1 064 s | +| 4 | **15 608 s** | **26 306 s** | n'a pas abouti | + +Trois étages coûtent une demi-heure. Le **quatrième** a coûté 4 h 20 +d'amorçage et 7 h 18 d'installation sur la même machine — tout y est 15 à 30 +fois plus lent, pas une seule étape. Et cela tombe précisément là où les +fabricants s'arrêtent : le quatrième étage est le *troisième* hyperviseur +imbriqué, et AMD en documente deux. + +Un invité plus large aggrave brutalement : au quatrième étage, un vCPU de plus +a multiplié l'amorçage par 9,4 (1 664 s à deux vCPU, 15 608 s à trois), et à +huit vCPU l'invité a lu 32 Mio en 106 minutes, pointeur d'instruction +immobile. Aux étages 2 et 3, ce même vCPU ne coûte rien. + +Donc : trois par défaut, cinq pour savoir, dix seulement pour voir le mur. + La descente est **uniforme**. Chaque étage, le premier compris, passe par les mêmes six étapes : créer, attendre le ssh, installer Proxmox, redémarrer et vérifier le noyau, remettre pmxcfs debout, contrôler le stockage. Seule la diff --git a/LongTest/README.md b/LongTest/README.md index 41cc307..6158c24 100644 --- a/LongTest/README.md +++ b/LongTest/README.md @@ -28,11 +28,36 @@ Which is the point of the script: a number obtained once, on one machine, in one chain, is an anecdote. ``` -./LongTest/deep_proxmox.py --depth 10 --dry-run # the plan, nothing created -./LongTest/deep_proxmox.py --depth 10 # hours +./LongTest/deep_proxmox.py # three levels, ~30 minutes +./LongTest/deep_proxmox.py --dry-run # the plan, nothing created +./LongTest/deep_proxmox.py --depth 5 # ask for more, knowingly ./LongTest/deep_proxmox.py --detruire # undo it ``` +### How deep is worth asking for + +The depth is the only setting, and **three** is the default because three +works. Measured on a 28-core machine, one full descent per row: + +| level | boot (ssh) | install | total | +|------:|-----------:|--------:|------:| +| 1 | 0 s | 200 s | 280 s | +| 2 | 37 s | 344 s | 495 s | +| 3 | 93 s | 777 s | 1 064 s | +| 4 | **15 608 s** | **26 306 s** | did not finish | + +Three levels cost half an hour. The **fourth** cost 4 h 20 of boot and 7 h 18 +of install on the same machine — everything there is 15 to 30 times slower, not +just one step. And it lands exactly where the hardware vendors stop: level 4 is +the *third* nested hypervisor, and AMD documents two. + +A wider guest makes it worse, sharply: at level 4, one extra vCPU multiplied +the boot by 9.4 (1 664 s at two vCPU, 15 608 s at three), and at eight vCPU the +guest read 32 MiB in 106 minutes with a static instruction pointer. At levels 2 +and 3 that same vCPU costs nothing. + +So: three by default, five if you want to know, ten only to watch the wall. + The descent is **uniform**. Every level, the first included, goes through the same six steps: create, wait for ssh, install Proxmox, reboot and check the kernel, bring pmxcfs back up, check the storage. Only creation differs — diff --git a/LongTest/deep_proxmox.py b/LongTest/deep_proxmox.py index ec2869b..bd2be2f 100755 --- a/LongTest/deep_proxmox.py +++ b/LongTest/deep_proxmox.py @@ -1174,7 +1174,13 @@ def principal(argv=None): parseur = argparse.ArgumentParser( description="Jusqu'à quel étage un Proxmox dans un Proxmox tient-il ?" ) - parseur.add_argument("--depth", type=int, default=10) + # Trois par défaut, et c'est une MESURE, pas une prudence : les trois + # premiers étages coûtent 280, 495 et 1 064 secondes — une demi-heure en + # tout. Le quatrième en a coûté 7 h 18 d'installation et 4 h 20 d'amorçage + # sur la même machine. Un défaut à dix promettait ce qu'aucune machine ne + # peut tenir ; la profondeur reste un paramètre, et c'est à qui la demande + # de savoir ce qu'il demande. + parseur.add_argument("--depth", type=int, default=3) parseur.add_argument("--dry-run", action="store_true") parseur.add_argument("--detruire", action="store_true") args = parseur.parse_args(argv) diff --git a/script/todo/longtest_menu.py b/script/todo/longtest_menu.py index 4fe7b04..918da38 100644 --- a/script/todo/longtest_menu.py +++ b/script/todo/longtest_menu.py @@ -87,6 +87,12 @@ class LongTestMenuMixin: print(t("Command not found !")) def _longtest_depth(self): - """Profondeur demandée. Dix par défaut : c'est ce qu'on veut mesurer.""" - brut = input(f"{t('Depth (default 10): ')}").strip() - return int(brut) if brut.isdigit() and int(brut) > 0 else 10 + """Profondeur demandée. Trois par défaut, parce que trois marche. + + Mesuré sur cette machine : les trois premiers étages prennent 280, 495 + et 1 064 secondes — une demi-heure. Le quatrième a demandé 7 h 18 + d'installation et 4 h 20 d'amorçage, et les suivants se comptent en + jours. Dix par défaut promettait ce qu'aucune machine ne tient. + """ + brut = input(f"{t('Depth (default 3): ')}").strip() + return int(brut) if brut.isdigit() and int(brut) > 0 else 3 diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index d94bf33..d0df4f4 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -3454,9 +3454,9 @@ TRANSLATIONS = { "fr": "Script introuvable :", "en": "Script not found:", }, - "Depth (default 10): ": { - "fr": "Profondeur (défaut 10) : ", - "en": "Depth (default 10): ", + "Depth (default 3): ": { + "fr": "Profondeur (défaut 3) : ", + "en": "Depth (default 3): ", }, "Nesting level": { "fr": "Étage d'imbrication", diff --git a/test/test_todo_longtest.py b/test/test_todo_longtest.py index 5a05e7d..c72c71a 100644 --- a/test/test_todo_longtest.py +++ b/test/test_todo_longtest.py @@ -208,15 +208,72 @@ class TestLEssaiABlanc(unittest.TestCase): (int(n), int(v), int(r), int(d)) for n, v, r, d in plan ) for parent, enfant in zip(etages, etages[1:]): - for i, quoi in ((1, "vCPU"), (2, "RAM"), (3, "disque")): + # Mémoire et disque : STRICTEMENT décroissants, chaque parent + # portant son enfant en plus de lui-même. + for i, quoi in ((2, "RAM"), (3, "disque")): self.assertGreater( parent[i], enfant[i], f"étage {parent[0]} : {quoi}" ) + # Le processeur : jamais plus étroit, mais pas toujours plus + # large. Deux étages imbriqués peu profonds ont la même largeur — + # au quatrième étage, un vCPU de plus multiplie l'amorçage par + # 9,4, alors qu'aux étages 2 et 3 il ne coûte rien. + self.assertGreaterEqual( + parent[1], enfant[1], f"étage {parent[0]} : vCPU" + ) # Et le plus profond reçoit ce qu'un Proxmox de test demande, pas ce # qui reste. self.assertEqual(etages[-1][1], 2, "vCPU du plus profond") +class TestLaProfondeurParDefaut(unittest.TestCase): + """Trois, et c'est une MESURE, pas une prudence. + + Sur la machine où ce test a été écrit, les trois premiers étages coûtent + 280, 495 et 1 064 secondes — une demi-heure en tout. Le quatrième a demandé + 7 h 18 d'installation et 4 h 20 d'amorçage, et les suivants se comptent en + jours. Un défaut à dix promettait ce qu'aucune machine ne peut tenir : la + profondeur reste un paramètre, mais le défaut doit marcher.""" + + def test_the_script_defaults_to_three(self): + import inspect + import sys as _sys + + _sys.path.insert(0, os.path.join(RACINE, "LongTest")) + import deep_proxmox + + src = inspect.getsource(deep_proxmox.principal) + self.assertIn('"--depth", type=int, default=3', src) + + def test_the_menu_defaults_to_three(self): + import inspect + + from script.todo.todo import TODO + + src = inspect.getsource(TODO._longtest_depth) + self.assertIn("else 3", src) + # Et l'invite le DIT : un défaut caché se subit, il ne se choisit pas. + self.assertIn("Depth (default 3): ", src) + + def test_the_prompt_is_translated(self): + from script.todo.todo_i18n import TRANSLATIONS + + entree = TRANSLATIONS.get("Depth (default 3): ") + self.assertIsNotNone(entree, "invite non traduite") + self.assertIn("3", entree["fr"]) + + def test_the_default_depth_fits_a_modest_machine(self): + """Le défaut doit tenir là où le test sera lancé, pas seulement sur la + machine de celui qui l'a écrit.""" + from script.proxmox import nesting + + plan = nesting.nesting_plan( + 3, cpu_hote=8, ram_dispo_mo=24000, disque_libre_go=120 + ) + self.assertEqual(plan["atteignable"], 3) + self.assertEqual(plan["arret"], "") + + class TestDefaireSansEffacerAutreChose(unittest.TestCase): """« --detruire » effaçait par SOUS-CHAÎNE de nom, dans le mauvais ordre, sans confirmation et sans honorer --dry-run.