Skip to content

Commit

Permalink
perf: flush Record when deadline is exceeded
Browse files Browse the repository at this point in the history
Watermark and WakeupEvents allow reducing the rate at which user
space is woken up. This creates an edge case where Read() returns
os.ErrDeadlineExceeded even though there is data in one of the rings.

This is also a problem in the ringbuf package, where we've solved this
by checking whether there is any data when encountering
an ErrDeadlineExceeded. Adopt the same approach for the perf reader.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
  • Loading branch information
lmb committed Apr 10, 2024
1 parent dce5fef commit dbbce35
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 1 deletion.
7 changes: 6 additions & 1 deletion perf/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ func (pr *Reader) ReadInto(rec *Record) error {
pr.pauseMu.Unlock()
_, err := pr.poller.Wait(events, pr.deadline)
pr.pauseMu.Lock()
if err != nil {
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
return err
}

Expand All @@ -374,6 +374,11 @@ func (pr *Reader) ReadInto(rec *Record) error {
pr.epollRings = append(pr.epollRings, ring)
}
}

if len(pr.epollRings) == 0 {
// Woken up but no data, deadline exceeded.
return fmt.Errorf("read: %w", os.ErrDeadlineExceeded)
}
}

// Start at the last available event. The order in which we
Expand Down
21 changes: 21 additions & 0 deletions perf/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,27 @@ func TestPerfReaderWakeupEvents(t *testing.T) {
}
}

func TestReadWithoutWakeup(t *testing.T) {
t.Parallel()

events := perfEventArray(t)

rd, err := NewReaderWithOptions(events, 1, ReaderOptions{WakeupEvents: 2})
if err != nil {
t.Fatal(err)
}
defer rd.Close()

prog := outputSamplesProg(t, events, 5)
ret, _, err := prog.Test(internal.EmptyBPFContext)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.Equals(ret, 0))

rd.SetDeadline(time.Now())
checkRecord(t, rd)
}

func BenchmarkReader(b *testing.B) {
events := perfEventArray(b)
prog := outputSamplesProg(b, events, 80)
Expand Down

0 comments on commit dbbce35

Please sign in to comment.