Skip to content

ci: split valgrind extension tests and stop retrying real failures - #4097

Draft
bengl wants to merge 3 commits into
masterfrom
bengl/ci-quickwins
Draft

ci: split valgrind extension tests and stop retrying real failures#4097
bengl wants to merge 3 commits into
masterfrom
bengl/ci-quickwins

Conversation

@bengl

@bengl bengl commented Aug 6, 2026

Copy link
Copy Markdown

Description

Three CI cost/latency fixes in the tracer pipeline, found while looking at
this repo's CI times in CI Visibility.

1. test_extension_ci ran the extension .phpt suite twice in one job.
make test_extension_ci did a normal pass and then a valgrind leak-check
pass sequentially in a single job. The valgrind pass is roughly an order of
magnitude slower, and the pair routinely blew the job's 120m timeout —
throwing away the normal pass's results along with it. Over 14 days this job
class recorded 2440 failures against 3403 successes, with [8.0] (481
errors / 301 successes) and [7.4] (321 / 260) worst affected; a large share
ended in Job failed: execution took longer than 2h0m0s.

Now split into test_extension_ci_normal / test_extension_ci_valgrind make
targets, run as two CI jobs.

2. MAX_TEST_PARALLELISM didn't match the CPU request. The job requested
12 CPUs but ran 4 test workers. On PHP >= 7.4 the normal job now uses 12.

3. Two jobs overrode default.retry to re-add script_failure.
ASAN test_c used the bare retry: 2 shorthand (retries every failure
reason) and PHP Language Tests spelled out a when: list including
script_failure. Both re-ran genuine test failures up to 3x. Neither job can
block a merge — both are in flaky-jobs.txt — so the retries bought no
signal. Both now inherit the repo-wide infrastructure-only default.retry
from generate-common.php.

Timeouts are version-conditional on purpose

RUN_TESTS_IS_PARALLEL gates -j on PHP >= 7.4, so 7.0–7.3 run the suite
serially and MAX_TEST_PARALLELISM is dead config there. Measured durations
for successful runs over 14 days (both passes combined):

PHP pc95 max
7.0–7.3 82–89m 91–99m
7.4–8.5 29–31m 32–39m

So >= 7.4 normal jobs get 45m + parallelism 12; < 7.4 keeps 120m with
no parallelism override. Cutting the pre-7.4 budget without per-pass timing
would risk timeouts that default.retry then pays for three times over.

Behaviour explicitly preserved

  • Merge gate unchanged. Both job names keep the test_extension_ci:
    prefix, so they still match the test_extension_ci:* glob in
    flaky-jobs.txt. Simulated merge-gate.sh's bash glob matching over all
    generated job names: 245 gating jobs before and after, and all 22
    test_extension_ci jobs non-gating.
  • make test_extension_ci still runs both passes, via recursive
    $(MAKE) rather than prerequisites, so make -jN can't run them
    concurrently over the same .phpt sandbox.
  • The valgrind recipe keeps TEST_PHP_OUTPUT, DD_SPAWN_WORKER_STABLE_TRAMPOLINE,
    DD_TRACE_AGENT_TIMEOUT, the tests/ext/valgrind PATH shim and the
    trailing ! grep -e '^LEAKED TEST SUMMARY' check verbatim.

Known tradeoffs

  • Pods for this job class go 11 → 22, each still requesting 12 CPUs, plus a
    duplicated after_script. Net wall clock still improves.
  • The valgrind pass now runs even when the normal pass fails, where set -xe
    previously skipped it. That's the cost of getting normal-pass results back
    promptly on a broken branch.
  • ASAN failures will become more visible now that script_failure isn't
    retried away. That's intended; they were already non-gating.
  • The >= 7.4 timing sample is successful runs only, so the tail that hit the
    old 120m budget is censored. Margin looks large, but worth watching the
    first week.

Verification

  • php -l clean on all .gitlab/generate-*.php; all five generators run.
  • Generated YAML for appsec / profiler / shared / package is byte-identical
    to master; only the tracer pipeline changed.
  • Tracer pipeline: exactly 11 jobs added, 0 removed; exactly 36 existing
    jobs changed (14 ASAN test_c retry-only, 11 PHP Language Tests
    retry-only, 11 test_extension_ci). Zero real - script_failure entries
    remain.
  • Generated YAML parses; every timeout emits at job level in both
    conditional branches.
  • Not verified locally: actual job runtimes. The per-pass split of the pre-7.4
    budget is unmeasured — that's why it was left at 120m.

Reviewer checklist

  • Test coverage seems ok.
  • Appropriate labels assigned.

The `test_extension_ci` job ran the extension .phpt suite twice in one
job: once normally, then again under valgrind for leak checking. The
valgrind pass is roughly an order of magnitude slower, and the pair
routinely exceeded the job's 120m timeout — discarding the normal pass's
results along with it. Over the last two weeks this job class failed 2440
times against 3403 successes, with `[8.0]` and `[7.4]` worst affected.

Split the two passes into `test_extension_ci_normal` and
`test_extension_ci_valgrind` make targets, and run them as two jobs. Both
job names keep the `test_extension_ci:` prefix so they still match the
`test_extension_ci:*` glob in flaky-jobs.txt; merge-gate behaviour is
unchanged. `make test_extension_ci` still runs both, via recursive
`$(MAKE)` rather than prerequisites so that `make -jN` cannot run the two
passes concurrently over the same .phpt sandbox.

On PHP >= 7.4 the normal job now sets MAX_TEST_PARALLELISM to 12 to match
its CPU request, and its timeout drops to 45m. Both passes together have
a pc95 of ~30m and a worst case of ~39m on those versions, so the normal
pass alone has headroom. Below 7.4 the timeout stays at 120m and no
parallelism override is set: the Makefile only passes -j to run-tests.php
when RUN_TESTS_IS_PARALLEL is set, which is gated on PHP >= 7.4, so those
versions run serially. The inherited value of 8 from .base_test is unused
there. Both passes together currently take a pc95 of 82-89m and a worst
case of 91-99m on those versions; cutting that budget without per-pass
timing would risk timeouts that `default.retry` then pays for three
times over.

Note the split means the valgrind pass now runs even when the normal pass
fails, where previously `set -xe` skipped it. That is the cost of getting
the normal pass's results back promptly on a broken branch.

Separately, drop two `retry:` overrides that re-added `script_failure` on
top of the repo-wide infrastructure-only `default.retry`:

- `ASAN test_c` used the bare `retry: 2` shorthand, which retries every
  failure reason. Inheriting the default also restores the
  `exit_codes: [75, 128]` retry that the shorthand had replaced.
- `PHP Language Tests` spelled out a `when:` list including
  `script_failure`.

Both re-ran genuine test failures up to three times, tripling the compute
and wall clock of an already-failing pipeline. Neither job can block a
merge — both are listed in flaky-jobs.txt — so the retries bought no
signal. Expect ASAN failures to become more visible as a result.
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Aug 6, 2026

Copy link
Copy Markdown

Pipelines  Tests

⚠️ Warnings

🚦 1 Pipeline job failed

DataDog/apm-reliability/dd-trace-php | ASAN test_c: [8.2, arm64]   View in Datadog   GitLab

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 60.60% (-0.08%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 24e25e8 | Docs | Datadog PR Page | Give us feedback!

Comment thread .gitlab/generate-tracer.php Outdated
ARCH: "<?= $arch ?>"
artifacts: true
retry: 2
# No `retry:` override: inherit the repo-wide `default.retry` from

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this comment probably isn't needed long term / only really applies as context to the PR.

Comment thread .gitlab/generate-tracer.php Outdated
- api_failure
- stuck_or_timeout_failure
- job_execution_timeout
# No `retry:` override: inherit the repo-wide `default.retry` from

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here

Comment thread .gitlab/generate-tracer.php Outdated
foreach ($all_minor_major_targets as $major_minor):
?>
<?php /*
* The extension .phpt suite runs as two jobs, not two passes of one job. The

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here, I think this comment can be simplified as saying to parallelize them separately since valgrind takes a long time.

we don't need all the context you have here

Most of the comments added in the previous commit explained the change
rather than the code, which is PR context and goes stale. Drop the two
`retry:` notes entirely — the absence of an override is not itself
noteworthy — and cut the rest to a line or two.

Two are kept because they document non-obvious constraints a future
change could silently break: that run-tests.php only gets -j on PHP >=
7.4, which is why the pre-7.4 timeout is higher, and that the composite
`test_extension_ci` target uses recursive $(MAKE) so `make -jN` cannot
run both passes over the same .phpt sandbox.

Comments only; the generated YAML is unchanged apart from the comment
lines it emits.

@brettlangdon brettlangdon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit, otherwise lgtm

Comment thread .gitlab/generate-tracer.php Outdated
foreach ($all_minor_major_targets as $major_minor):
?>
<?php /* Normal and valgrind passes run as separate jobs: valgrind is far
slower, so pairing them in one job blew its timeout. */ ?>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
slower, so pairing them in one job blew its timeout. */ ?>
slower, so run in parallel. */ ?>

Applies review suggestion. Comment only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants