Skip to content

Fix(ci,#24696): epingler les pools de threads BLAS/OpenMP du job Scripts Tests (CPU) - #24697

Merged
myia-ai-01 merged 2 commits into
mainfrom
fix/24696-openblas-threads
Nov 4, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
fix/24696-openblas-threads

Conversation

@jsboige

@jsboige jsboige commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: DEEP/guard #24635

Le défaut

Le job Scripts Tests (CPU) tombe sur deux tests hashlife quand le runner Linux est saturé :

scripts/hashlife/tests/test_wolfram_ksf.py::TestWolframKSFJsonRoundtrip
scripts/hashlife/tests/test_wolfram_mode.py::TestWolframJsonRoundtrip
OpenBLAS blas_thread_init: pthread_create failed for thread 14 of 32: Resource temporarily unavailable
OpenBLAS blas_thread_init: ensure that your address space and process count limits are big enough (ulimit -a)
OpenBLAS blas_thread_init: or set a smaller OPENBLAS_NUM_THREADS to fit into what you have available

Mesure de référence : job 126652731468 (run 41852640940, tentative 1, 2026-11-04T15:09Z) → 2 failed, 24345 passed, 379 skipped, 9 xfailed en 622,84 s.

Ce n'est pas un défaut de contenu des tests : les deux passent sur cette machine, avec et sans épinglage. Le runner est un pool auto-hébergé partagé : quand plusieurs jobs se partagent la machine, la création de threads échoue, le sous-processus qui importe numpy meurt avant de rendre sa sortie, et le test lit proc.returncode != 0.

La cause

OpenBLAS dimensionne son pool de threads sur le nombre de cœurs vus par le runner — 32 dans le message ci-dessus. Ce job lance déjà jusqu'à 4 workers xdist, chacun susceptible d'ouvrir un sous-processus qui importe numpy. Le déficit n'est donc pas le CPU, c'est le nombre de threads créées simultanément : d'où une valeur de 1, et non le quota CPU.

Le correctif

Un pas de plus dans le job Scripts Tests (CPU), avant le run pytest, exporte les quatre variables de pool de threads à 1 :

OPENBLAS_NUM_THREADS=1
OMP_NUM_THREADS=1
MKL_NUM_THREADS=1
NUMEXPR_NUM_THREADS=1

La valeur est affichée dans le log : une contrainte non affichée n'est pas prouvée. Même famille de variables que le job ML (Borner les threads au quota CPU du conteneur) et que les exécuteurs de carnets (scripts/notebook_tools/notebook_helpers.py, #11111) — ici la valeur est 1 parce que la panne est un échec de création de thread, pas une contention CPU.

La mesure avant/après (poste ai-01, 2026-11-04)

Processus enfant scripts/hashlife/k_trajectory.py --mode wolfram-ksf --n-cells 64 --n-steps 64, threads OS du processus enfant observés pendant l'exécution (pic) :

configuration threads OS au pic durée
sans épinglage (défaut OpenBLAS) 53 1,90 s
OPENBLAS_NUM_THREADS=1 + OMP_NUM_THREADS=1 8 1,46 s

Suite hashlife complète (175 tests) : 18,70 s sans épinglage, 17,25 s avec. L'épinglage ne coûte donc rien de mesure — la création du pool de threads dominait le coût, pas le calcul.

Les deux tests rouges du CI, joués sur cette machine : 2 passed dans les deux configurations (la panne est un phénomène de saturation du runner, pas reproductible hors saturation).

Périmètre

  • Un seul fichier : .github/workflows/scripts-tests.yml.
  • Aucune suite n'est sautée : le correctif ne touche ni la collecte pytest ni les pytest.ini ; il ne fait qu'ajouter une variable d'environnement au job. Les compteurs de tests collectés restent ceux d'avant.
  • Le job qc-mcp-lite suite (58) est un job distinct : il n'est pas dans le périmètre de ce correctif.

Ce qui reste à observer

Le troisième critère de l'issue #24696 — « la suite hashlife passe sur le runner saturé » — ne se prouve que sous saturation ; il s'observe sur les runs de la flotte une fois ce correctif mergé. L'issue reste donc ouverte jusqu'à cette observation, et ce PR la suit sans la fermer.

See #24696

🤖 Generated with Claude Code

…pts Tests (CPU)

Le runner est un pool auto-heberge partage : sous saturation, la creation de
threads echoue et les sous-processus qui importent numpy meurent avant de
rendre leur sortie. Mesure (job 126652731468, run 41852640940, tentative 1,
2026-11-04T15:09Z) : 2 failed, 24345 passed, sur
test_wolfram_ksf.py::TestWolframKSFJsonRoundtrip et
test_wolfram_mode.py::TestWolframJsonRoundtrip, avec
`OpenBLAS blas_thread_init: pthread_create failed for thread 14 of 32`.

Le defaut d'OpenBLAS dimensionne son pool sur le nombre de coeurs vus par le
runner (32) -- ce job lance deja jusqu'a 4 workers xdist, chacun susceptible
d'ouvrir un sous-processus numpy. Le deficit est le NOMBRE de threads
creees simultanement, pas le CPU : d'ou la valeur 1, non le quota CPU.

Cout mesure (poste ai-01, 2026-11-04, processus enfant
scripts/hashlife/k_trajectory.py --mode wolfram-ksf --n-cells 64
--n-steps 64) : 53 threads OS au pic sans epinglage, 8 avec epinglage ;
duree 1,90 s -> 1,46 s. Suite hashlife complete (175 tests) : 18,70 s ->
17,25 s. L'epinglage ne coute donc rien de mesure.

Les quatre variables (OPENBLAS_NUM_THREADS, OMP_NUM_THREADS, MKL_NUM_THREADS,
NUMEXPR_NUM_THREADS) sont exportees a 1 et AFFICHEES dans le log : une
contrainte non affichee n'est pas prouvee.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

[ACTION] Le correctif est valide sur CI ; le seul job rouge est un rouge hérité de main — correctif en PR #24681, cette PR sera rebasée dessus.

Preuve que l'épinglage fait effet. Dans le log du job Scripts Tests (CPU) (job 126711644691, run 41869294690), le pas ajouté s'exécute et affiche les quatre variables à 1 :

OPENBLAS_NUM_THREADS=1
OMP_NUM_THREADS=1
MKL_NUM_THREADS=1
NUMEXPR_NUM_THREADS=1
pools de threads epingles a 1 (#24696)

Preuve que le défaut visé a disparu. Le rouge de référence (job 126652731468, run 41852640940, tentative 1) portait sur TestWolframKSFJsonRoundtrip et TestWolframJsonRoundtrip — OpenBLAS blas_thread_init: pthread_create failed for thread 14 of 32, 2 failed / 24345 passed. Sur ce run, aucun échec hashlife : la suite se termine par 1 failed, 24347 passed, 381 skipped, 9 xfailed et l'unique échec est sans rapport avec les pools de threads (voir ci-dessous). Les deux tests roundtrip passent.

Ce qui reste rouge, et pourquoi ce n'est pas cette PR. L'unique échec est :

FAILED scripts/notebook_tools/tests/test_check_prose_quantitative_claims.py::test_artifact_exemptions_are_motivated_and_point_at_real_files
AssertionError: chemin d'exemption introuvable : 'MyIA.AI.Notebooks/SymbolicAI/Lean/conway_lean/scripts/README.md'

Le chemin fautif est absent de origin/main au même titre que de cette branche (git cat-file -e origin/main:MyIA.AI.Notebooks/SymbolicAI/Lean/conway_lean/scripts/README.md → does not exist) : le lake a été descendu vers GOL/conway_lean (#24166) et l'exemption d'artifact est restée sur l'ancien chemin. Le job Scripts Tests (CPU) exécute toute la suite de scripts/, quel que soit le périmètre de la PR — ce rouge fait donc échouer le PR gate de toute PR du dépôt.

PR #24681 : trois lignes (le chemin de l'exemption et les deux chemins du test). Sur cette PR, le job Scripts Tests (CPU) est vert, et le PR gate est repassé vert après le rejeu de la jambe DWELL (job 126723129219, tentative 3, terminé le 2026-11-04T16:57:09Z).

Geste. Dès le merge de #24681, cette branche est rebasée sur main et le job est relancé.

@github-actions github-actions Bot added the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-ai-01:CoursIA-2 a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #24518 (MED/ledger, merge a 2026-11-04T01:41:27Z), #24504 (MED/readme, merge a 2026-11-04T12:23:23Z), #24519 (MED/guard, merge a 2026-11-04T12:32:11Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-ai-01:CoursIA-2` voit ces signaux actifs sur les mergees du jour (UTC 2026-11-04) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=0 genre=3 cap=1)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=0 genre=3 cap=1)

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@github-actions github-actions Bot added the trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre guard dans la famille META (docs/guard/ledger/readme/test) + diff de 37 lignes changees (<= 100) + aucune exception ecrite dans le body : le litmus de la trivialite (une douzaine d'instances scannees a la suite) est credible. Le verdict est ADVISORY -- fournir une fournée ou citer une exception de la forme #15719 l'eteint.
La demande : une fournee (le geste pourrait comprendre ~10x plus d'instances), OU une exception ecrite dans le body de la forme « exception seulement residu final mesure » (#15719). Editer le body re-deroule cet organe et retire le label.

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lu à la tête ae16f72593. Le pas est dans le job scripts-tests (« Scripts Tests (CPU) »), avant pytest, et il affiche les quatre valeurs. J'ai vérifié que test_bound_thread_pools.py, qui asserte la sémantique « une valeur déjà posée gagne », vide ces variables par une fixture autouse : l'épinglage global du job ne le casse pas. Le job épinglé a tourné à cette tête avec un seul échec, le chemin d'exemption conway_lean hérité de main et corrigé par #24681 (24347 passed). Je rafraîchis la branche et je merge au vert, après le plancher DWELL.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #24697 (Fix(ci,#24696): epingler les pools de threads BLAS/OpenMP du job Scripts Tests (CPU)) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@myia-ai-01
myia-ai-01 merged commit b1e8a04 into main Nov 4, 2026
25 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants