perf(poort): de tagpoort meet geen dekking meer, en de runner draait één taak tegelijk #796

Merged
brenno merged 3 commits from perf/ci-zonder-dekkingsmeting into main 2026-07-24 13:25:20 +00:00
Owner

De twee wijzigingen uit het onderzoek naar de trage gate. De derde optie — de gate op de Mac-runner — is bewust níet gedaan.

Wat er is gemeten

Een poortrun op de eigen runner duurde 46 minuten tegen 2,5 lokaal. Nagemeten waar die tijd zat:

pawprint bouwmachine
CPU Xeon D-2123IT @ 2,2 GHz (2018) Apple M5 Max
Echte kernen 4 12 performance
Dezelfde 1-kernproef 0,95 s 0,25 s
Schijf 2× 7200-toeren HDD in software-RAID NVMe

3,8× trager per kern × ~3× minder kernen ≈ 11×, en dat is precies de waargenomen factor. Schijf en opslagstuurprogramma nagekeken en vrijuit (overlayfs, ~106 MB/s sequentieel) — het werk is CPU-gebonden.

Van die 46 minuten ging 33 min 49 s naar één fase: flutter test --coverage. Die instrumentatie houdt per test een VM-Service-verbinding open tot het eind van de run en parallelliseert daarmee het slechtst van alles wat we draaien.

Wat er verandert

make check-no-coverage — elke statische poort die check ook draait, daarna test in plaats van coverage + coverage-per-file. De volledige suite draait onverkort en in willekeurige volgorde; alleen de instrumentatie gaat eraf. De statische poorten staan nu in één gedeelde STATIC_GATES-lijst, zodat een nieuwe poort niet aan één van de twee doelen kan ontbreken.

De tagpoort in .forgejo/workflows/ci.yml draait dat doel.

Runnercapaciteit 1 (op de server, buiten deze PR): stond op 4. Taak 661 deelde de bak met 662 en 663 — drie gates tegelijk op vier fysieke kernen, elk met een flutter test die per kern werkers opstart. Dat verergerde de wachttijd én was de bron van de flakes onder last. Config geback-upt, runner herstart met 0 taken onderbroken.

Wat dit kost

De dekkingsvloer en de per-bestandsvloer draaien in CI niet meer. Ze zijn onveranderd en onverkort verplicht in make check, op de machine van de committer, vóór main. Dat is een verplaatsing en geen versoepeling, en ze houdt alleen omdat de samenvoegpoort daar toch al lag (#790). Het staat expliciet in het Makefile-doel zelf, in de workflow, en in CHECKS.md — op drie plekken, want dit is precies het soort ding dat stil wegzakt.

Eerlijk over de opbrengst

Die 74% is niet de winst — de suite moet nog steeds draaien. Lokaal nagemeten: make test 112 s wandklok / 595 s CPU tegen make coverage 147 s / 971 s, dus −24% wandklok en −39% CPU. Op vier kernen zit de run tegen zijn CPU aan en nadert de wandklokwinst die −39%: geschat 33 min 49 s → ~21 min, oftewel ~13 minuten van de 46. Reëel, maar geen factor.

Ik had eerder ~34 minuten winst genoemd. Dat was fout: ik verwarde de duur van de fase met de winst van het weghalen van de instrumentatie.

Poorten

  • make check groen (6300 toetsen, exit 0) — de dekkingsvloeren dus ook.
  • make check-no-coverage groen (6300 toetsen, exit 0).
  • make check-secrets groen, make sast groen (0 bevindingen).
  • Onderweg één flake: render_page_serialisation_test viel om bij het laden onder --coverage, na vier volledige suites achter elkaar. Weg na rm -rf build/test_cache; los draaien was altijd groen. Bekende klasse, geen bevinding van deze wijziging.
  • DAST niet gedraaid (raakt geen geserveerd oppervlak). Bewaker niet aangeroepen, expliciet: geen formaat, opslag, afhankelijkheid, verkeer of publieke belofte geraakt — wel een belofte in de documentatie, en die is daarom in dezelfde PR bijgewerkt in plaats van later.
De twee wijzigingen uit het onderzoek naar de trage gate. De derde optie — de gate op de Mac-runner — is bewust níet gedaan. ## Wat er is gemeten Een poortrun op de eigen runner duurde 46 minuten tegen 2,5 lokaal. Nagemeten waar die tijd zat: | | pawprint | bouwmachine | | --- | --- | --- | | CPU | Xeon D-2123IT @ 2,2 GHz (2018) | Apple M5 Max | | Echte kernen | **4** | 12 performance | | Dezelfde 1-kernproef | **0,95 s** | **0,25 s** | | Schijf | 2× 7200-toeren HDD in software-RAID | NVMe | 3,8× trager per kern × ~3× minder kernen ≈ 11×, en dat is precies de waargenomen factor. Schijf en opslagstuurprogramma nagekeken en vrijuit (`overlayfs`, ~106 MB/s sequentieel) — het werk is CPU-gebonden. Van die 46 minuten ging **33 min 49 s naar één fase**: `flutter test --coverage`. Die instrumentatie houdt per test een VM-Service-verbinding open tot het eind van de run en parallelliseert daarmee het slechtst van alles wat we draaien. ## Wat er verandert **`make check-no-coverage`** — elke statische poort die `check` ook draait, daarna `test` in plaats van `coverage` + `coverage-per-file`. De volledige suite draait onverkort en in willekeurige volgorde; alleen de instrumentatie gaat eraf. De statische poorten staan nu in één gedeelde `STATIC_GATES`-lijst, zodat een nieuwe poort niet aan één van de twee doelen kan ontbreken. De tagpoort in `.forgejo/workflows/ci.yml` draait dat doel. **Runnercapaciteit 1** (op de server, buiten deze PR): stond op 4. Taak 661 deelde de bak met 662 en 663 — drie gates tegelijk op vier fysieke kernen, elk met een `flutter test` die per kern werkers opstart. Dat verergerde de wachttijd én was de bron van de flakes onder last. Config geback-upt, runner herstart met 0 taken onderbroken. ## Wat dit kost **De dekkingsvloer en de per-bestandsvloer draaien in CI niet meer.** Ze zijn onveranderd en onverkort verplicht in `make check`, op de machine van de committer, vóór main. Dat is een verplaatsing en geen versoepeling, en ze houdt alleen omdat de samenvoegpoort daar toch al lag (#790). Het staat expliciet in het Makefile-doel zelf, in de workflow, en in CHECKS.md — op drie plekken, want dit is precies het soort ding dat stil wegzakt. ## Eerlijk over de opbrengst Die 74% is **niet** de winst — de suite moet nog steeds draaien. Lokaal nagemeten: `make test` 112 s wandklok / 595 s CPU tegen `make coverage` 147 s / 971 s, dus −24% wandklok en −39% CPU. Op vier kernen zit de run tegen zijn CPU aan en nadert de wandklokwinst die −39%: geschat 33 min 49 s → ~21 min, oftewel **~13 minuten van de 46**. Reëel, maar geen factor. Ik had eerder ~34 minuten winst genoemd. Dat was fout: ik verwarde de duur van de fase met de winst van het weghalen van de instrumentatie. ## Poorten - `make check` groen (6300 toetsen, exit 0) — de dekkingsvloeren dus ook. - `make check-no-coverage` groen (6300 toetsen, exit 0). - `make check-secrets` groen, `make sast` groen (0 bevindingen). - Onderweg één flake: `render_page_serialisation_test` viel om bij het laden onder `--coverage`, na vier volledige suites achter elkaar. Weg na `rm -rf build/test_cache`; los draaien was altijd groen. Bekende klasse, geen bevinding van deze wijziging. - DAST niet gedraaid (raakt geen geserveerd oppervlak). Bewaker niet aangeroepen, expliciet: geen formaat, opslag, afhankelijkheid, verkeer of publieke belofte geraakt — wel een belofte in de *documentatie*, en die is daarom in dezelfde PR bijgewerkt in plaats van later.
`flutter test --coverage` houdt per test een VM-Service-verbinding open tot het
eind van de run, en dat is zowel de duurste fase als de fase die het slechtst
parallelliseert. Op de eigen runner ging 33 min 49 s van een gate van 46
minuten naar precies die ene fase.

Het nieuwe doel draait elke statische poort die `check` draait, en daarna
`test` in plaats van `coverage` + `coverage-per-file`. De volledige suite
draait dus onverkort en in willekeurige volgorde; alleen de instrumentatie gaat
eraf. De statische poorten staan nu in één gedeelde lijst, zodat een nieuwe
poort niet aan één van de twee doelen kan ontbreken — dat is precies het soort
stille afwijking waar niemand meer op let.

Wat je inlevert staat in het doel zelf: de dekkingsvloer en de
per-bestandsvloer draaien hier niet. Die blijven verplicht in `make check`, op
de machine van de committer, vóór main.

Nagemeten opbrengst, want die 74% is niet de winst — de suite moet nog steeds
draaien: `make test` 112 s wandklok / 595 s CPU tegen `make coverage` 147 s /
971 s, dus -24% wandklok en -39% CPU. Op vier kernen zit de run tegen zijn CPU
aan en nadert de wandklokwinst die -39%: naar schatting ~13 minuten van de 46.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
De uitbrengpoort op een `v*`-tag beantwoordt "draait alles nog, op andermans
hardware" — niet "hoeveel raakt het". Dat tweede is een vraag voor `make check`
op de machine van de committer, en daar blijft hij onverkort staan.

De referentiedefinitie in `.github/` droeg nog de oude belofte en is
bijgewerkt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CHECKS.md droeg op drie plekken de belofte dat CI `make check` draait. Dat
klopt niet meer, en het verschil is er een die een lezer moet weten: de
dekkingsvloeren draaien nergens meer behalve op zijn eigen machine.

De kolom "In CI workflow" is bewust ongemoeid gelaten — die beschrijft wat
`.github/workflows/ci.yml` *declareert*, niet wat draait, en dat staat in de
voetnoot eronder. Alleen die voetnoot is bijgewerkt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 19862c0a90 into main 2026-07-24 13:25:20 +00:00
Sign in to join this conversation.
No description provided.