Skip to content

Add support for PHP resp-bench - #28

Open
prateek-kumar-improving wants to merge 4 commits into
mainfrom
php/resp-bench
Open

prateek-kumar-improving wants to merge 4 commits into
mainfrom
php/resp-bench

Conversation

@prateek-kumar-improving

@prateek-kumar-improving prateek-kumar-improving commented Sep 14, 2026

Copy link
Copy Markdown

Implements the PHP benchmark engine, at parity with the Java (reference), Ruby, and C# engines.

What

  • New engine under php/ (composer install, php bin/resp-bench), driving:
    • valkey-glide-php — the Valkey GLIDE PHP client (native ext-valkey_glide extension, PHPRedis-compatible API)
    • phpredis — PHPRedis (ext-redis), the de-facto standard PHP client and the incumbent comparison baseline (analogous to redis-rb for Ruby / StackExchange.Redis for C#)
    • recording — in-memory driver for server-free tests
  • Consumes the shared driver/workload JSON and emits the exact NDJSON schema (metadata/phase/totals/metrics, unit:"us", uppercased command keys, HDR compressed base64).

Concurrency model

PHP's GLIDE client is synchronous and the standard PHP build is non-thread-safe (NTS), which rules out ext-parallel. The engine therefore uses process-per-connection via pcntl — the faithful, dependency-free analogue of Java's virtual-thread-per-client and Ruby's thread-per-client:

  • connections = N → fork N worker processes (capped at 256), each with one in-flight request at a time (the client == connection invariant), keeping results comparable across engines.
  • Each worker connects after forking — a connection is never inherited across a fork (required for correctness with the native extension).
  • Workers stream partial metrics to the parent over a stream_socket_pair; the parent reconstructs and merges the HdrHistograms losslessly (sparse bucket counts) before writing NDJSON.
  • Phase-level rps_limit is divided across workers so the aggregate matches the target.
  • An inline mode (--concurrency inline) runs all connections sequentially in one process; it's selected automatically for the recording driver and when pcntl is unavailable, and exercises the full pipeline for server-free tests.

Cross-engine parity

  • JavaRandom LCG port — verified byte-identical to Java's canonical new Random(0).nextInt() sequence [-1155484576, -723955400, 1033096058, -1690734402, -1557280266, ...]. PHP lacks 64-bit integer overflow wraparound, so the multiply uses a 24-bit split to preserve the low 48 bits.
  • sequential_int walks the keyspace; uniform_rand seeds per worker (seed + idx) for reproducible-yet-distinct sequences. Key formatting %0Nd honoring key_size_bytes.
  • Pure-PHP HdrHistogram (1, 600_000_000, 3); the V2 compressed base64 payload is byte-structured to match Java's encodeIntoCompressedByteBuffer(). Leaky-bucket rate limiter.

Harness

  • Makefile php-build/test/integration-test/run/clean/info targets.
  • Registered the PHP driver_id in scripts/run_benchmark_matrix.py (DRIVER_ENGINE_MAP) and scripts/generate_graphs.py (DRIVER_LANGUAGE_MAP).
  • Driver configs for both clients under configs/drivers/{default,high-throughput}/ + example-*-standalone.json, plus configs/matrices/php-driver-comparison.json (GLIDE-PHP vs PHPRedis across connection counts — the head-to-head that mirrors the Java/Node comparison matrices).
  • CI: a fast server-free test-php job (unit + integration) and a benchmark-php job that builds the valkey_glide extension from source and runs against a live server; wired into generate-graphs needs.
  • Docs: php/README.md, docs/BENCHMARKS_PHP.md, README "Supported Languages" + Make Targets updates.

Tests

58 tests (cd php && vendor/bin/phpunit): parity anchors (JavaRandom seed-0 Java anchor, key generator), rate limiter, command selector, config loader, client factory, HDR encode structure + percentiles; integration tests covering the recording-driver pipeline (NDJSON schema, inline + process fork modes, agreement on totals), rate limiting (RPS enforcement, shared limit across concurrent connections, unlimited throughput), error metrics (per-command error counts, errors excluded from latency histogram), and NDJSON/metrics output. Gated live tests for both valkey-glide-php and phpredis skip cleanly without their extension + a server. No server needed for the 50 non-live tests.

Verified locally (PHP 8.5, no server, no extension): full suite = 58 tests pass, 8 skipped (the gated live tests for the two real drivers). CLI smoke test with the recording driver produces valid NDJSON with correct totals (WARMUP 400, STEADY 1000 = GET+SET) and non-empty HDR payloads in both inline and --concurrency process (fork) modes.

Notes

  • valkey-glide-php follows the valkey-glide-ruby / valkey-glide-csharp naming convention (not the bare valkey-glide, which is Java's).
  • Live-server runs require the valkey_glide extension installed (php/README.md documents install via pie/PECL/source; the benchmark-php CI job builds it). The recording-driver e2e covers the engine paths without it.
  • The HDR payload's binary structure was verified (cookies, header fields, IEEE754 conversion ratio), but a live cross-decode against Java's decodeFromCompressedByteBuffer() was not run in this environment (no JRE); it's ported from the Java-validated Ruby encoder.

Signed-off-by: Kumar <kupratec@amazon.com>
Kumar added 2 commits September 14, 2026 10:07
Signed-off-by: Kumar <kupratec@amazon.com>
Signed-off-by: Kumar <kupratec@amazon.com>
@yipin-chen
yipin-chen requested a review from Aryex September 15, 2026 17:12
Resolve conflicts from the merged Node.js engine (#27), which touched the same
shared files as the PHP engine PR. All resolutions are additive — both engines
coexist:

- scripts/{run_benchmark_matrix,generate_graphs}.py: keep php + node driver maps
- Makefile: keep both PHP and Node engine target sections and .PHONY entries
- README.md: keep PHP and Node rows in languages/structure/target tables
- .github/workflows/benchmark.yml: keep test-php + benchmark-php and benchmark-node
  jobs; add 'php' to the engines input; generate-graphs needs all four engines
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.

1 participant