ci: adopt CI/CD engineering standards, single rollup gate, and upstream CDN 504 resilience - #201
Conversation
…am CDN 504 resilience - Implement canonical CI/CD guide in docs/CI_CD_GUIDE.md detailing CI commandments, multi-project standards, upstream CDN resilience, and Miri/Valgrind tiers. - Add upstream CDN 504 resilience to ci.yml and release.yml: * Resilient curl retry loop with exponential backoff for downloads.php.net / windows.php.net * Matrix runner startup jitter across Linux, Alpine, and Windows runners * Wrap fragile steps (apt-get, PIE install, baseline fetch) in nick-fields/retry@v3 * Cap matrix parallel concurrency (max-parallel: 6) - Add two-tiered path filtering (dorny/paths-filter@v3) to skip heavy builds on doc-only PRs. - Implement single rollup gate job (ci-gate) evaluating statuses across all CI matrix jobs. - Standardize job names with functional categories: Core / ..., Compat / ..., Safety / ..., CI Gate / ... - Implement nightly.yml workflow with scheduled Valgrind memory leak checks, PHP-dev compatibility, and differential fuzz soak, with automated GitHub issue triage. - Update action versions to @v4 / @v7 across all workflows and validate with actionlint. Closes #200
Test Results
Benchmark Results
Run Status
Memory (Linux, PHP 8.6)Peak RSS of a child process building one structure, n = 500,000, minus an empty-process floor. Judy's memory advantage is type- and scale-dependent — see BENCHMARK.md for the curve across sizes on a dedicated host.
API Speedups (Linux, PHP 8.6)Speedup = PHP time / Judy time. Bold = Judy faster.
Core Types (Linux, PHP 8.6)Speedup = PHP time / Judy time. Bold = Judy faster.
All types detailCore Types (Linux, PHP 8.6) — AllSpeedup = PHP time / Judy time. Bold = Judy faster.
Cross-version detail (Linux)Core Types — LinuxEach cell: Judy ms (speedup vs PHP array).
API — Linux
Cross-version detail (Windows)Core Types — WindowsEach cell: Judy ms (speedup vs PHP array).
API — Windows
Windows results (PHP 8.6)Memory (Windows, PHP 8.6)Peak RSS of a child process building one structure, n = 500,000, minus an empty-process floor. Judy's memory advantage is type- and scale-dependent — see BENCHMARK.md for the curve across sizes on a dedicated host.
API Speedups (Windows, PHP 8.6)Speedup = PHP time / Judy time. Bold = Judy faster.
Core Types (Windows, PHP 8.6)Speedup = PHP time / Judy time. Bold = Judy faster.
All types detailCore Types (Windows, PHP 8.6) — AllSpeedup = PHP time / Judy time. Bold = Judy faster.
Release Comparison (2.6.0 → 2.7.1)
Summary:
Memory ComparisonMemory: 0 regressions, 10 unchanged
Full benchmark outputLinux — PHP 8.6Windows — PHP 8.6 |
Benchmark Gate — PASSRelative regression detection. Every quantity below is a ratio of two arms measured in the same interleaved rounds on the same runner, compared against the ratio stored in Platforms measured
ControlsThe PHP-array control sees runner drift. The C-vs-C rebuild control — two independently linked builds of identical source — is the one that matters, because it shares Judy's memory-access character (pointer-chasing, DRAM-bound) and can therefore see the LLC and memory-bandwidth contention the array control is structurally blind to. Its scatter is each run's own noise floor and raises that run's threshold when it exceeds the stored one.
Thresholds applied
S → C — the vendored libJudy patches (below 1.00 means the patches are faster)
A → C — php-judy against a PHP native array (above 1.00 means the array is faster)
Memory — PHP array bytes / php-judy bytes (above 1.00 is a php-judy win)
Arm S — verified unpatched on each platform
The operative evidence is the source-hash manifest ( Findings
A cell is flagged only when its whole bootstrap CI clears the threshold in the adverse direction. Full run: https://github.com/orieg/php-judy/actions/runs/32651096035 |
…sts under memcheck (#204) The nightly Valgrind job (new in #201) invoked run-tests.php directly, which never loads the freshly built modules/judy.so — 227/232 tests silently SKIPped on extension_loaded('judy') and the job has failed on every run since it was introduced. Switch to make test, which passes -d extension_dir=modules -d extension=judy.so; the -m/-q/--show-diff flags ride in TESTS, which the generated Makefile appends to the run-tests.php invocation. Two classes of false positives surface once the suite actually runs under memcheck (--trace-children=yes, USE_ZEND_ALLOC=0): - The three bench-harness tests spawn child PHP processes. Children are traced too: memcheck inflates their RSS by an order of magnitude (breaking bench_memory_measurement_001's heap-vs-RSS assertions) and child memory_limit fatals leave allocations unfreed by design, which memcheck attributes to the test as a leak (bench_memory_limit_001). All three now skip when USE_ZEND_ALLOC=0 is exported, the standard run-tests marker for a Valgrind run. - PCRE2's sljit-generated code trips uninitialised-value reports inside the php binary itself (no judy.so frame), flagging every preg_*-using test as LEAK. -d pcre.jit=0 in the Valgrind run silences it. Verified in a Linux container (PHP 8.4, valgrind): the fixed command runs 229/232 under memcheck with 0 failures and 0 leaks (3 skips are the guarded bench tests); the normal suite still passes 232/232 with 0 skips. Fixes #202
Closes #200