Skip to content

bench: cross-thread fanout, including the case this crate loses - #32

Merged
userFRM merged 1 commit into
masterfrom
bench/fanout-threaded
Jul 27, 2026
Merged

userFRM merged 1 commit into
masterfrom
bench/fanout-threaded

Conversation

@userFRM

@userFRM userFRM commented Jul 27, 2026

Copy link
Copy Markdown
Owner

The in-cache benchmark isolates protocol cost, but cannot measure a design whose builder owns its consumer threads — that shape has no single-threaded mode, so the most relevant broadcast comparison was missing entirely. This measures the deployed arrangement: one producer, N consumer threads on their own cores, 100k messages, every consumer accounting for all of them.

Total milliseconds, lower is better:

semantics N=1 N=2 N=4 N=8
photon lossless 0.49 0.52 0.58 2.62
sequence-barrier ring lossless 0.45 2.94 6.99 12.15
per-consumer queue lossless 1.39 14.90 27.92 46.79
shared-ring broadcast lossy 8.23 8.61 33.86 119.47

At one consumer the barrier ring wins. No contention for a barrier to lose to, and its handler drains a batch where this crate takes messages one at a time. That stays in the table. From two consumers onward the positions reverse, and photon holds close to flat through N=4.

Two things the numbers do not establish, published alongside them:

  • photon's own N=8 jump (0.58 → 2.62) may be scheduling rather than architecture — nine threads on a sixteen-thread machine that was not idle. Needs a pinned rerun on a quiet box before anyone relies on it.
  • the shared-ring row is lossy by construction: a receiver that falls behind is told what it missed rather than holding the producer back. It belongs against this crate's lossy channel(), not the lossless rows. Writing this surfaced it — an earlier version asserted lossless delivery for every case, and that design cannot provide it.

Reproduce with cargo bench --bench fanout_threaded.

Verified: 219 tests, clippy clean, fmt clean.

The in-cache benchmark isolates protocol cost, but it cannot measure a design whose builder owns its consumer threads — there is no single-threaded mode for that shape. Omitting it left the most relevant broadcast comparison missing. This measures the deployed arrangement instead: one producer, N consumer threads on their own cores, 100k messages, every consumer accounting for all of them.

Total milliseconds:

                        semantics   N=1    N=2    N=4    N=8
  photon                lossless   0.49   0.52   0.58   2.62
  sequence-barrier ring lossless   0.45   2.94   6.99  12.15
  per-consumer queue    lossless   1.39  14.90  27.92  46.79
  shared-ring broadcast lossy      8.23   8.61  33.86 119.47

At one consumer the barrier ring wins: there is no contention for a barrier to lose to, and its handler drains a batch where this crate takes messages one at a time. That is in the table. From two consumers onward the positions reverse.

Two things the numbers do not establish, stated with them. The jump in photon's own N=8 figure may be scheduling rather than architecture — nine threads on a sixteen-thread machine that was not idle — and needs a pinned rerun before anyone relies on it. And the shared-ring row is lossy by construction: a receiver that falls behind is told what it missed rather than holding the producer back, so it belongs against this crate's lossy channel() rather than the lossless rows. Writing the benchmark surfaced that; an earlier version asserted lossless delivery for every case and that design cannot provide it.
@userFRM
userFRM merged commit 74f4189 into master Jul 27, 2026
18 checks passed
@userFRM
userFRM deleted the bench/fanout-threaded branch July 27, 2026 11:27
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