Skip to content

Comments

Add ReadTimeout to perf/ring buffer#523

Closed
brycekahle wants to merge 6 commits intocilium:masterfrom
DataDog:bryce.kahle/perf-buffer-read-timeout
Closed

Add ReadTimeout to perf/ring buffer#523
brycekahle wants to merge 6 commits intocilium:masterfrom
DataDog:bryce.kahle/perf-buffer-read-timeout

Conversation

@brycekahle
Copy link
Contributor

Adds the function ReadTimeout to allow non-indefinite waits when reading from a perf buffer.

I'm not in love with the ErrNoRecords sentinel error, but I wanted to see what you folks thought. Maybe io.EOF or exporting errEOR instead?

Alternatively, I could make it more Go-ish, changing the function signature to ReadContext(ctx context.Context), but it would need to handle manual cancellation too.

Copy link
Contributor

@ti-mo ti-mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a concept, I think taking context.Context is fine (this is Go after all), but for such a low-level API, it doesn't make much sense performance-wise. context.WithTimeout makes several allocations, takes out a lock and needs to be called for every call to ReadTimeout(). A simple value for setting a timeout would be just fine here. 👍

Overall I think this is a good addition. Implementing cancellation is not needed IMO, either read with timeouts or close the reader if you're done with it.

@brycekahle
Copy link
Contributor Author

@ti-mo Addressed all your feedback if you want to give it another look.


// ReadTimeout is Read but will time out and return os.ErrDeadlineExceeded
// if the timeout expires.
func (pr *Reader) ReadTimeout(timeout time.Duration) (Record, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a deadline vs. a time out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean taking a time.Time and computing the millisecond timeout value from that? If so, that would make it hard/impossible to end up with a timeout value of 0 which is useful for polling.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the use case of polling to be honest, so I'd be OK to forego that for now.

As a user I'd expect the timeout to specify the time until the next Record. However, what it really does is bound how long we block in epoll. Those are two distinct, since we might in the future generate a spurious wakeup (e.g. to implement suspension without map shenanigans). As a user I don't (and shouldn't care) that epoll was woken. So taking a deadline here is simpler to implement and easier to understand I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So taking a deadline here is simpler to implement

Would you mind branching and showing me? A deadline seems to be more complicated to me, since the underlying epoll API supports the timeout, so we simply pass it on.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not stick with a timeout? For network i/o, expressing timeouts as deadlines makes sense e.g. to bound a send/recv to the same window, but I'm not sure if that would be very useful here.

So taking a deadline here is simpler to implement and easier to understand I think.

Hmm, epoll doesn't have the equivalent of (net.Conn).SetReadDeadline iirc. With your suggestion, would the caller pass in a time.Time using time.Now().Add(time.Millisecond * 100), which the library code then has to reverse using t.Sub(time.Now()) to obtain a relative timeout value to pass to epoll_pwait? That's going to be less accurate than passing a time.Duration and won't allow the caller to busypoll.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can implement both, I'm just trying to say that ReadTimeout() would be implemented in terms of ReadDeadline(time.Now().Add(to)).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since msec timeout is the native format taken by epoll_wait, why not the other way around? :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to say: the deadline or timeout parameter should indicate "the time i'm willing to wait until Read returns a record", not "the time I'm willing to wait for the next epoll notification". The current implementation does the latter.

Why is this relevant? For example, ringbuf can be woken from epoll but not produce a Record, because items in the ring may be marked as "discarded". The same can happen here if we end up changing the implementation. To avoid this the natural implementation is for Poller to take a deadline until which it may block.

If we add both timeout and deadline methods, how about SetTimeout and SetDeadline like for net.Conn etc.?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sorry for joining late here)

Why is this relevant? For example, ringbuf can be woken from epoll but not produce a Record,

Wanted to add the other use case ringbuf has: read from raw ring without epoll. Should this be handled as part of the Set* as a special case or we want it to be completely separate ReadRaw() call or something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mythi I probably need a more fully fleshed out example, maybe open a discussion about it?

@lmb
Copy link
Contributor

lmb commented Jan 14, 2022

@brycekahle do you want me to do another round of review?

@brycekahle
Copy link
Contributor Author

@brycekahle do you want me to do another round of review?

I think we probably need to figure out the API design issue first.

@lmb
Copy link
Contributor

lmb commented Feb 18, 2022

Closing for now. Feel free to reopen.

@lmb lmb closed this Feb 18, 2022
@lmb lmb mentioned this pull request Jul 14, 2022
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.

4 participants