Repository navigation
Conversation
Stamp every armed event with CLOCK_MONOTONIC at arm time (one clock read and store) and check queue age at delivery in both reactor backends: a round-start scan pulls already-aged events to the front of the dispatch batch, and a per-delivery check catches events that age behind a slow earlier callback. An event past CWIST_REACTOR_TAIL_US (default 3500 us, 0 disables) is dispatched first and sees cwist_reactor_dispatch_late() true, so the HTTP layer serves its buffered pipeline without yielding -- the same bypass late-round mode (CWIST_REACTOR_LATE_US) uses, so both backends share one code path. RX-uring/RX-epoll completions carry their arm stamp on the HTTP side; the RX completion handler runs the same age check and raises the bypass. Aged-event counter is reported by the latency probe as tail_elevations.
Member
Author
|
Closing: neutral on every A/B in the description (no p99/p99.999 gain beyond noise up to c1024). The late-round heuristic it builds on is being removed in a follow-up PR. |
Member
Author
|
Closing: neutral on every A/B in the description. The existing late-round heuristic (CWIST_REACTOR_LATE_US) is removed in a follow-up PR. |
gg582
added a commit
that referenced
this pull request
Oct 15, 2026
The late-round mode from bc358b4 (issue #319 experiment) switched the rest of an io_uring dispatch round into a no-yield, flush-per-callback mode once the round had run past 3 ms. It never showed a tail improvement beyond noise in the same-runner A/B, and the follow-up age-based variant (#375) was neutral too. Drop it: - reactor.c: reactor_late_ns(), cwist_reactor_dispatch_late(), the per-callback clock read and late flush, and the late_rounds / late_callbacks probe counters; - reactor_rx.h: the cwist_reactor_dispatch_late() declaration and stub; - app.c: the HTTP handler yields every yield_batch requests again, with no late bypass; the now unused reactor_rx.h include goes too; - tests/test_reactor_late.c and its Makefile target; - the CWIST_REACTOR_LATE_US rows in docs/runtime-config.md (en, ko); - the "CWIST C1M (late mode off)" benchmark leg. The round-budget flush (CWIST_REACTOR_ROUND_BUDGET_US) and the post-drain chunking (CWIST_REACTOR_DRAIN_CHUNK) are unchanged. Past cwist_c1m_lateoff rows in benchmarks/webserver.json stay as history.
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.
Summary
Stamps every armed reactor event with CLOCK_MONOTONIC and, at delivery in both the io_uring and epoll paths, serves events whose queue age exceeds CWIST_REACTOR_TAIL_US (default 3500 us, 0 disables) first, reusing the existing late-round bypass path in the HTTP layer. The latency probe reports the elevated count as
tail_elevations.A/B measurement
Workload:
wrk -t4 -c256 -d30s -s scripts/ci/tail_latency.luaagainstbenchmarks/web-frameworks/cwist_benchon port 3000; medians over 8 runs (io_uring) / 3 runs (epoll). "off" =CWIST_REACTOR_TAIL_US=3600000(heuristic effectively disabled).io_uring (default backend):
epoll (
CWIST_REACTOR_BACKEND=epoll):High-concurrency validation (c512 / c1024,
wrk -t8, 3 runs per cell, heuristic on = 3500 us vs off)Latency-probe confirmation at c1024 (io_uring,
CWIST_LATENCY_PROBE=1): the heuristic fires only a handful of times per worker (tail_elevations≈ 3–4 per worker per 30 s run, vs ~1 with the heuristic off, out of ~10 M requests), while ~100–130 k queue_delay samples exceed 5 ms in both states and the queue_delay histogram (p50 ≈ 2500 us, p99 ≈ 25 ms) is unchanged. The age-at-arm stamp is refreshed too often for events to cross the 3500 us threshold at delivery, so dispatch order is measurably unaffected — which matches the flat wrk numbers.Conclusion
Neutral up to c1024 on this harness: no p99/p99.999 improvement beyond noise at any tested threshold or concurrency, and no RPS regression beyond ±1%. The mechanism is wired correctly (proven by
test_reactor_tailand the probe counter) but rarely triggers under this workload, so it is a safe, opt-out-by-env no-op rather than a measured win. Keeping the 3500 us default; results reported honestly rather than claimed as a speedup.