Skip to content

Split bounded-queue credits and add model-based tests - #3

Open
SamuelSchlesinger wants to merge 1 commit into
mainfrom
split-bounded-credits
Open

Split bounded-queue credits and add model-based tests#3
SamuelSchlesinger wants to merge 1 commit into
mainfrom
split-bounded-credits

Conversation

@SamuelSchlesinger

Copy link
Copy Markdown
Owner

Summary

  • Bounded queues tracked occupancy in one TVar that every enqueue and every dequeue wrote, so producers and the consumer conflicted on every operation — undoing the two-TVar layout's separation of the fast paths. This tracks free capacity as split read/write credits in the style of TBQueue: enqueue spends write credits, dequeue/flush release read credits, and only an enqueue that finds no write credits moves the read credits over. Conflicts on capacity accounting drop from once per operation to once per limit enqueues.
  • Moves the implementation to Data.Queue.Internal (documented as outside the PVP) so tests can check the representation invariants; Data.Queue re-exports the same public API.
  • Adds a QuickCheck model test (random op sequences against a FIFO list, invariants checked after every step: length bs <= length ts, front empty iff queue empty, credits == free capacity), a multi-producer stress test, and a --throughput-bounded benchmark comparing bounded Queue with TBQueue.
  • Also makes the enqueue-side rotation force rotate to WHNF like the dequeue side already did.

Measurements (GHC 9.6.7, -N8, 1 s wall clock, P senders -> 1 consumer)

senders bounded Queue before bounded Queue after TBQueue
1 3.3–4.2 M/s 5.8–13.9 M/s 8.8–19 M/s
4 0.7–1.6 M/s 1.8–2.7 M/s 1.0–3.5 M/s
16 0.07–0.11 M/s 0.60–0.74 M/s 0.22–0.41 M/s

Ranges span several runs; absolute numbers move a lot between runs on this machine but the ordering within a run is stable. Single-thread cost rises ~10% from the extra branch.

Test plan

  • cabal build --enable-tests --enable-benchmarks --ghc-options=-Werror all
  • cabal test — 22 examples incl. 1,000 model-test cases and the fan-in stress test (unbounded, capacity 16, capacity 1)
  • cabal check, cabal haddock --haddock-for-hackage, cabal sdist
  • stm-queue-benchmark --throughput-bounded

Bounded queues tracked occupancy in a single TVar that every enqueue and
every dequeue wrote, so producers and the consumer conflicted on every
operation even though the queue's two-TVar layout keeps their fast paths
apart. Track free capacity as split read and write credits instead, in the
style of TBQueue: enqueue spends write credits, dequeue and flush release
read credits, and only an enqueue that finds no write credits moves the
read credits over. Capacity accounting now conflicts once per `limit`
enqueues rather than once per operation.

Move the implementation to Data.Queue.Internal so tests can check the
representation invariants, with Data.Queue re-exporting the public API.
Add a QuickCheck model test that runs random operation sequences against
a FIFO list and checks the invariants after every step, a multi-producer
stress test, and a bounded Queue versus TBQueue throughput benchmark.
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