Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion benchmarks/server-port/v3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ run's native source, optimized binary and machine facts filled in. The
workload, artifacts, limits and probe hashes are unchanged. The
[October 20 observations](observations-2026-10-20.md) are one PHP/native
pair on a disposable VM, run with `scripts/perf/run-server-port-matched.sh`
and summarized with `scripts/perf/summarize-server-port-matched.py`.
and summarized with `scripts/perf/summarize-server-port-matched.py`. The
[repeated observations](repeated-2026-10-20.md) are two alternating pairs
on a second host, after #516.

To repeat it on a fresh dedicated host with Docker and Compose:

Expand Down
101 changes: 101 additions & 0 deletions benchmarks/server-port/v3/repeated-2026-10-20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Repeated matched observations, October 20

Two alternating PHP/native pairs on one dedicated experiment host, after #516
landed on main. They repeat the [morning pair](observations-2026-10-20.md)
with the same workload, artifacts, limits and commands. These are development
observations on one host and one database family, not a release claim.

## Conditions

- **Source.** Server main `8957ba27a` (#516 merged), native tree `55aec4d8`.
The optimized binary was built with `cargo build --release --locked --bin
durable-workflow-server`, SHA-256 `edc283f1…6e2cc`. The PHP references,
PHP SDK, MySQL and Redis artifacts are the profile's, unchanged.
- **Host.** A fresh Vultr `vhp-4c-8gb-amd` VM: 4 vCPU AMD EPYC-Rome, 7.7 GiB,
Ubuntu 24.04.5 with kernel 6.8, Docker 29.1.3 and Compose 2.40.3, no swap.
No other workload ran. It ran from 13:15 to 15:48 UTC, was deleted at the
end and its deletion was verified, at about $0.20.
- **Procedure.** A native smoke check, then PHP, native, PHP and native full
runs in that order. Each run uses its own Compose project and fresh
database. Each run is the morning procedure: warmup, three 120 s windows at
0.25, 0.5 and 1 workflow/s, the 0.25/s windows repeated after as a drift
check, and mixed idle polls. The four runs' summaries are in
`summary-repeated-{php,native}-{1,2}-2026-10-20.json`.

All four runs finished with status 0. Every window's workflows verified, with
nothing pending. No container restarted or was OOM-killed.

## Offered work and latency

Each cell gives the range of the three per-window values.

| Run / rate | In-window completions | p50 s | p95 s | p99 s |
| --- | --- | --- | --- | --- |
| PHP 1 / 0.25 before | 30/30/30 | 1.129–1.188 | 1.459–1.620 | 1.515–1.652 |
| PHP 1 / 0.5 | 60/60/60 | 1.129–1.215 | 1.517–1.545 | 1.633–1.675 |
| PHP 1 / 1 | 69/68/66 of 120 | 44.782–48.343 | 64.771–67.389 | 66.026–69.027 |
| PHP 1 / 0.25 after | 30/30/30 | 1.195–1.226 | 1.568–1.732 | 1.686–1.818 |
| Native 1 / 0.25 before | 30/30/30 | 0.815–1.171 | 1.485–1.785 | 1.867–2.202 |
| Native 1 / 0.5 | 60/60/60 | 0.806–0.862 | 1.361–1.434 | 1.490–1.730 |
| Native 1 / 1 | 120/120/120 | 0.642–0.688 | 1.139–2.111 | 1.604–2.545 |
| Native 1 / 0.25 after | 30/30/30 | 1.061–1.139 | 1.691–1.887 | 1.916–2.042 |
| PHP 2 / 0.25 before | 30/30/30 | 1.236–1.306 | 1.649–1.680 | 1.697–1.818 |
| PHP 2 / 0.5 | 60/60/60 | 1.179–1.268 | 1.557–1.635 | 1.694–1.867 |
| PHP 2 / 1 | 62/67/65 of 120 | 48.434–55.744 | 65.491–72.870 | 66.325–74.189 |
| PHP 2 / 0.25 after | 30/30/30 | 1.164–1.258 | 1.441–1.643 | 1.531–1.731 |
| Native 2 / 0.25 before | 30/30/30 | 0.942–0.989 | 1.655–1.876 | 1.860–1.944 |
| Native 2 / 0.5 | 60/60/60 | 0.874–0.985 | 1.380–1.555 | 1.618–1.918 |
| Native 2 / 1 | 120/119/120 | 0.675–0.715 | 1.121–1.567 | 1.759–2.945 |
| Native 2 / 0.25 after | 30/30/30 | 0.951–1.049 | 1.503–1.822 | 1.716–1.958 |

PHP still does not sustain 1/s. Its in-window completions at 1/s fell from
93–96 this morning to 62–69 here, and its 1/s median latency grew from 15–18 s
to 45–56 s. Its CPU per workflow also rose about a quarter on this host, as the
next table shows. Native completed all 120 in both pairs here and this
morning. The two PHP runs agree with each other, and so do the two native runs.
So the change is between hosts, not drift within this one.

## CPU and memory

Core-seconds per verified workflow, and the highest container memory sampled.

| Run / rate | Runtime core-s/wf | MySQL core-s/wf | Runtime max MiB |
| --- | --- | --- | --- |
| PHP 1 / 0.25 before | 2.574–2.755 | 0.662–0.713 | 192.0 |
| PHP 1 / 1 | 1.599–1.638 | 0.554–0.566 | 201.2 |
| PHP 2 / 0.25 before | 2.737–2.829 | 0.710–0.748 | 203.0 |
| PHP 2 / 1 | 1.603–1.676 | 0.549–0.573 | 213.1 |
| Native 1 / 0.25 before | 0.239–0.247 | 0.489–0.506 | 6.3 |
| Native 1 / 1 | 0.102–0.104 | 0.241–0.245 | 7.0 |
| Native 2 / 0.25 before | 0.245–0.256 | 0.503–0.518 | 6.9 |
| Native 2 / 1 | 0.110–0.116 | 0.264–0.275 | 6.8 |

At 1/s, native uses about a fifteenth of PHP's runtime CPU per workflow and
about half of its database CPU. Its peak memory is about 7 MiB against PHP's
190–215 MiB.

## Idle mixed long polls

Runtime core-seconds per idle window, three windows each.

| Run | 6 polls | 12 polls | 24 polls | Health failures |
| --- | --- | --- | --- | --- |
| PHP 1 | 6.117–6.877 | 7.279–8.642 | 9.160–9.564 | 0, 1, 2 per window |
| Native 1 | 0.645–0.683 | 0.790–0.917 | 1.206–1.256 | none |
| PHP 2 | 5.699–6.651 | 7.803–8.198 | 9.408–9.695 | 0, 1, 2–3 per window |
| Native 2 | 0.684–0.755 | 0.822–0.922 | 1.189–1.241 | none |

PHP answers part of its 12- and 24-poll windows with backpressure, and its
health checks fail in them. Native answers every poll empty, as expected.

## What this shows and what it does not

On this profile, native meets or beats PHP on throughput, CPU, memory and idle
long-poll cost in every window of two repeated pairs. The before and after
windows show no drift within any run.

It does not show the result on PostgreSQL or SQLite, on other machine types,
across nodes, or under the CPU-heavy deadline profile. The host-to-host change
in PHP's capacity also says one host is not enough for a release claim. The
driver records host load and swap but not CPU steal. Sampling steal in
`host-state.tsv` is the next change to the driver.
Loading
Loading