Skip to content

ringbuf: add UnsafeReader as zero-copy ringbuf reader#1979

Draft
jschwinger233 wants to merge 3 commits intocilium:mainfrom
jschwinger233:gray/zc4
Draft

ringbuf: add UnsafeReader as zero-copy ringbuf reader#1979
jschwinger233 wants to merge 3 commits intocilium:mainfrom
jschwinger233:gray/zc4

Conversation

@jschwinger233
Copy link
Copy Markdown
Member

@jschwinger233 jschwinger233 commented Apr 6, 2026

ringbuf.Reader.ReadInto always copies sample bytes into user-owned memory. That is safe and convenient, but it becomes a visible bottleneck as sample size grows.

This PR introduces that path as a separate type (UnsafeReader) so the tradeoff is explicit: performance vs safety/concurrency guarantees.

APIs

Read

// Zero-copy Read — slice valid until Commit.
rec, err := unsafeReader.Read()
// Batch commit after processing N records.
unsafeReader.Commit()

ReadInto

// Zero-copy ReadInto — slice valid until Commit.
err := unsafeReader.ReadInto(&rec)
// Batch commit after processing N records.
unsafeReader.Commit()

ReadFunc

// Callback mode — sample is valid only during callback.
// Record is committed implicitly after callback returns.
rem, err := unsafeReader.ReadFunc(func(sample []byte, rem int) error {})

Benchmark Results

Benchmark is done by https://github.com/jschwinger233/bpf_ringbuf_zc_benchmark

  for i in {1..20}; do
    echo $((i * 128))
    taskset -c 2 ./bpf_ringbuf_zc_benchmark -event-size $((i * 128))
  done

Observed throughput (UnsafeReader.ReadInto vs Reader.ReadInto):

Event size Speedup
128B 1.18x
1024B 3.61x
2048B 6.02x
2432B 6.39x

Trend: small records show modest gains; larger records show strong scaling, peaking at ~6.4x.

Related

#1968
#1930
#1915

No functional change intended.

This commit only reshapes internal call paths so upcoming zero-copy APIs can
reuse the same read/poll machinery.

Introduce two internal APIs:
- readWithPoll: centralizes the Reader poll/wait loop (deadline, flush,
pending errors, busy/EOR handling) and executes a caller-supplied record read
callback.
- readRecordFunc: centralizes ring record decoding and yields a zero-copy
sample view plus remaining bytes and next consumer position to a
caller-supplied callback.

Signed-off-by: graymon <greyschwinger@gmail.com>
Add a new ringbuf.UnsafeReader dedicated to zero-copy consumption.

It supports two ways of reading: either call Read/ReadInto and then
Commit explicitly, or use ReadFunc and have the record committed
automatically after the callback returns.

The new type reuses the same internal polling and ring decoding paths as
Reader (readWithPoll + readRecordFunc), and keeps Reader’s existing
copy-based behavior unchanged.

This API is intentionally unsafe for concurrent use.

Signed-off-by: graymon <greyschwinger@gmail.com>
Signed-off-by: graymon <greyschwinger@gmail.com>
@jschwinger233
Copy link
Copy Markdown
Member Author

@ti-mo I drafted this PR to address the comments and move the discussion forward: #1968 (comment)

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