[perf] client worker - #205
Draft
SouradeepBera wants to merge 6 commits into
Draft
Conversation
Make the benchmark harness measure its own scheduling fidelity so we can tell harness-induced timing drift apart from real server behavior. - traffic/workers: record scheduler_ready_at as the item's intended ready_at (when it was *due*), not when the dispatcher happened to pick it up, so ready->dispatch lag becomes observable rather than hidden. - core/response: carry the paired lifecycle timestamps (ready/dispatched/ picked-up/client-sent) plus always-recorded client_sent_at. - evaluator/performance: accumulate ready->dispatch, dispatch->pickup, pickup->send and end-to-end ready->send drift into CDF sketches, surface them in the aggregated summary, and soft-WARN past a configurable threshold (lifecycle_drift_warn_threshold_ms, default 50ms). - core/tokenizer: make the transformers import lazy so importing the text client no longer forces the GIL back on under free-threading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add opt-in record-book instrumentation (record_preflight_timing) to every client modality so preflight can join client- and server-side timelines by request id without putting any timing values on the wire. - All six clients (chat, completions, tts, realtime_tts, vajra_tts_stream, stt) stamp chunk_recv_times and attach a correlation request-id header. - The three streaming-input WS clients (realtime_tts, vajra_tts_stream, stt) additionally record per-segment input_send_times and their intended input_send_deadlines, enabling input-delivery and input-pacing metrics. - config/client: add the record_preflight_timing flag (off by default, so normal benchmarks are unaffected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Give the AUDIO channel modality a real generator so STT workloads can be driven without a real audio dataset. - config/generator/channel: make AudioChannelGeneratorConfig concrete (duration_seconds, sample_rate, waveform=sine|silence, frequency_hz) with validation, replacing the NotImplementedError stub. - generator/channel/audio: AudioChannelGenerator writes a deterministic PCM-16 WAV (tone or silence) once per parameter set to a cache dir and reuses it across all requests; numpy/soundfile imported lazily. - generator/channel/registry: register AUDIO -> AudioChannelGenerator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `veeksha preflight`, which certifies the harness keeps time honestly before its benchmark numbers are trusted. It drives the real scheduler -> dispatch -> client path against deterministic mock servers and gates p99 timing drift against thresholds. - servers: per-modality mock servers (raw-asyncio HTTP/SSE for chat/ completions/tts; websockets-based for realtime_tts/vajra_tts_stream/stt), each a pinned subprocess that records its own ground-truth timeline and serves it back over /preflight/records for a request-id join. - scorer: pure drift math over the paired record books -- request/response delivery, server ttfc/tpoc pacing fidelity, lifecycle dispatch drift, streaming-input delivery + pacing, and informational client-observed ttfc/tpoc. - validator: PASS / FAIL / SERVER_AT_CAPACITY verdicts (server-pacing breach is blamed on the mock, not the harness). - config/runner/report: benchmark-style config -- polymorphic traffic_scheduler, per-category workload/mock timing (text/tts/stt), configurable input length, and sessions = K * concurrency sizing. - cli: register the preflight subcommand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SouradeepBera
force-pushed
the
users/sbera/client-transport-intake
branch
from
July 26, 2026 23:33
4519141 to
a337018
Compare
SouradeepBera
marked this pull request as draft
July 27, 2026 06:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes client worker threading
Client worker threading: measurement-fidelity impact
Compares the baseline against the dedicated-puller-thread change on the preflight gate.
e0316eb8a337018f1500 requests per workload per run, 1500 paired, 0.000% unpaired on every run — no request
dropped or mismatched. All values are milliseconds, median across the runs on each commit
(medians because the after runs have large run-to-run spread; see Variance).
Ground truth did not move.
server_ttfc_abs_error_msp99 is 1.161 → 1.174 ms andserver_tpoc_abs_error_msp99 is 1.018 → 1.062 ms, both against a 5 ms threshold and effectivelyidentical before and after. The mock servers held their pacing on both commits, so every difference
below is harness-side and the comparison is valid.
What gets better
chat— large tail win, exactly where the change targetslifecycle_ready_to_send_ms)The win localises to the stage the commit addresses.
lifecycle_dispatch_to_pickup_msp99 drops5336 → 546 ms (×0.10) and its mean 757 → 111 ms (×0.15). Before, intake was awaited on the event
loop, so item N+1 was not requested until task N had been created; the dedicated
_pull_loopthread(
veeksha/workers/client_runner.py:71) posts items viacall_soon_threadsafeand the loop convertsthem to tasks in batches.
Secondary effects follow the same direction:
lifecycle_pickup_to_send_mslifecycle_ready_to_dispatch_msclient_observed_ttfc_msclient_observed_tpoc_mstts— neutral, as expectedttsnever had the dispatch-to-pickup pileup this change fixes (161 ms p99 before, not 5336 ms), sothere was nothing to win. The deltas here are within run-to-run spread.
What gets marginally worse — and why it doesn't matter
Regressions that stay far under threshold
response_delivery_msp50chatresponse_delivery_msp50ttsresponse_delivery_msp99ttslifecycle_pickup_to_send_msp99ttslifecycle_ready_to_dispatch_msp99ttsSub-millisecond values against 5 ms and 10 ms gates. These ratios look large only because the
absolute numbers are tiny; none of them changes a gate outcome.
The p50/p99 trade on
chatrequest_delivery_mslifecycle_ready_to_send_mslifecycle_dispatch_to_pickup_msThe change trades body for tail: the median request waits longer, the worst-case request waits far
less. Every gate in
validator.py:76is a p99 gate, so this trade is favourable as scored. Worthstating explicitly that it is a trade — removing the self-throttling intake puts more requests in
flight, so the typical request contends with more work.
chatresponse delivery p99 (969 → 1634 ms) — confounded, not a real regression signalThis is the one metric that moves the wrong way at p99, and it is not interpretable from these runs.
Per-run
chatresponse_delivery_msp99:One after run was dramatically better on every metric (request delivery p99 266 ms vs
2681–2969 ms for the other four). One run in five landed in a much better operating point; 5 runs
cannot tell whether the change occasionally reaches a better steady state or that run simply caught a
quiet machine. Both commits are ~200× over the 5 ms threshold here, so neither produces a trustworthy
response-delivery number at this load and the change does not alter that.
The dispatch-drift and request-delivery wins are robust: they hold in all 5 after runs,
including the four "bad" ones.