Make blocking performance test measure throughput - #8160
Make blocking performance test measure throughput#8160Eddy Ashton (eddyashton) wants to merge 1 commit into
Conversation
…g perf test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors the perf submitter to support driving multiple logical HTTP sessions concurrently (libcurl multi + libuv), and updates the perf harness to batch multiple logical clients into a single submitter process for blocking perf runs. It also strengthens option validation (multi-session vs failover), improves Arrow Parquet parsing to support additional column types, and adds regression coverage for curl handle reuse and callback failures.
Changes:
- Add a multi-session async submit path in
submit.cpp(per-session request queues, curl easy-handle reuse, libuv loop integration). - Extend the workload Parquet format to optionally include
sessionID, and update the perf harness to generate/propagate it and batch clients per process. - Add regression tests for (a) reused easy handles clearing missing header lists and (b) submitter robustness when callbacks fail.
Custom instructions used:
.github/copilot-instructions.md.github/instructions/reviewing.instructions.md
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/perf-system/submitter/submit.cpp | Adds multi-session submitter (curl+uv) and validates multi-session CLI constraints. |
| tests/perf-system/submitter/parquet_data.h | Extends perf workload data model to include per-request session_ids. |
| tests/perf-system/submitter/handle_arguments.h | Adds --multi-session flag and improves help text wrapping. |
| tests/perf-system/submitter/CMakeLists.txt | Links submitter against curl + libuv to support the async multi-session path. |
| tests/infra/basicperf.py | Batches multiple logical clients per submitter process, adds CPU affinity support, and updates reporting to use sessionID. |
| tests/e2e_curl.py | Adds an end-to-end regression that the submitter doesn’t hang on callback failure; uses a DELETE request to trigger the failure. |
| src/http/test/curl_test.cpp | Adds a regression ensuring reused easy handles clear absent CURLOPT_HTTPHEADER lists. |
| src/http/curl.h | Always sets CURLOPT_HTTPHEADER (including null) to prevent stale header pointers; adds easy-handle extraction and connection-limit helper. |
| CMakeLists.txt | Adds tunables for the blocking perf test (client counts, per-process batching, sig intervals, affinity args). |
Suppressed comments (2)
tests/perf-system/submitter/submit.cpp:596
curl_contextis created but never referenced, which is likely to trigger-Wunused-variableunder-Wextra -Werror. Since you already addedset_connection_limits, call it directly oncurl_context(rather than viaget_instance()) to both use the object and avoid reliance on the singleton accessor here.
ccf::curl::CurlmLibuvContextSingleton curl_context(loop);
ccf::curl::CurlmLibuvContextSingleton::get_instance()
->set_connection_limits(pending.size());
tests/perf-system/submitter/submit.cpp:604
- The structured binding element
_is unused. With-Wextra -Werror, this is likely to fail compilation as an unused variable. Bind it to a named variable and explicitly ignore it (or iterate over keys only).
for (const auto& [session_id, _] : pending)
{
try
{
submit_next(session_id, ccf::curl::UniqueCURL(), true);
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| "Failed to initialise curl: {}", | ||
| curl_easy_strerror(curl_init_result))); | ||
| } | ||
| const CurlGlobalCleanup curl_cleanup; |
| if args.clients_per_process <= 0: | ||
| raise ValueError("--clients-per-process must be positive") | ||
| if args.stop_primary_after_s and args.clients_per_process != 1: | ||
| raise ValueError( | ||
| "Failover tests require --clients-per-process=1 because the " | ||
| "multi-session submitter does not support failover" | ||
| ) |
|
I think we prefer #8158 for this - off-the-shelf tooling, avoid awkward barely-used multi-session options for our explicitly pipeline-friendly submitter. Would be good to confirm that both approaches have similar results at similar parameters, or at least similar curve shapes? And then we can discuss what a "sensible" sig-ms-interval is, given it remains the dominant lever for controlling latency. |
|
@eddyasthon agreed, if there the numbers are substantially different, we want to understand why. |
Summary
Update
pi_basic_blockingfrom a basic load test that showed blocking responses could handle some concurrency into a useful measure of blocking transaction throughput.The previous test launched one synchronous submitter process per logical client. With 128 processes, 100 requests per client, and a 100ms signature interval, it was dominated by signature cadence and client process overhead. Its roughly 1,200 tx/s result mostly confirmed that blocking requests completed under load rather than measuring the throughput the service can sustain with blocking enabled.
This change adds an event-driven, multi-session mode to the Piccolo submitter. Each process drives multiple independent logical sessions through libcurl-multi/libuv while preserving one blocking request in flight and one persistent HTTP/1.1 connection per session. This reduces the physical client count from hundreds of processes to a small number of event loops without reducing logical concurrency.
The updated blocking benchmark uses:
On the development machine, the updated workload completed 640,000 requests without errors at approximately 27,500-29,000 tx/s, compared with an approximately 1,200 tx/s baseline.
Additional changes
Validation
submitandcurl_testtargets.e2e_curlfixture, including persistent-handle reuse and callback-failure regression coverage.