From ad1636d2e795212ed6e326bd7df0fc60794be115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=C2=A0Decina?= Date: Sun, 10 Apr 2022 08:31:11 +0000 Subject: [PATCH] aya: perf_buffer: call BytesMut::reserve() internally This changes PerfBuffer::read_events() to call BytesMut::reserve() internally, and deprecates PerfBufferError::MoreSpaceNeeded. This makes for a more ergonomic API, and allows for a more idiomatic usage of BytesMut. For example consider: let mut buffers = vec![BytesMut::with_capacity(N), ...]; loop { let events = oob_cpu_buf.read_events(&mut buffers).unwrap(); for buf in &mut buffers[..events.read] { let sub: Bytes = buf.split_off(n).into(); process_sub_buf(sub); } ... } This is a common way to process perf bufs, where a sub buffer is split off from the original buffer and then processed. In the next iteration of the loop when it's time to read again, two things can happen: - if processing of the sub buffer is complete and `sub` has been dropped, read_events() will call buf.reserve(sample_size) and hit a fast path in BytesMut that will just restore the original capacity of the buffer (assuming sample_size <= N). - if processing of the sub buffer hasn't ended (eg the buffer has been stored or is being processed in another thread), buf.reserve(sample_size) will actually allocate the new memory required to read the sample. In other words, calling buf.reserve(sample_size) inside read_events() simplifies doing zero-copy processing of buffers in many cases. --- aya/src/maps/perf/perf_buffer.rs | 15 +++++---------- aya/src/maps/perf/perf_event_array.rs | 3 --- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/aya/src/maps/perf/perf_buffer.rs b/aya/src/maps/perf/perf_buffer.rs index e90a39ba..285d99ec 100644 --- a/aya/src/maps/perf/perf_buffer.rs +++ b/aya/src/maps/perf/perf_buffer.rs @@ -59,6 +59,10 @@ pub enum PerfBufferError { /// `read_events()` was called with a buffer that is not large enough to /// contain the next event in the perf buffer. + #[deprecated( + since = "0.10.8", + note = "read_events() now calls BytesMut::reserve() internally, so this error is never returned" + )] #[error("the buffer needs to be of at least {size} bytes")] MoreSpaceNeeded { /// expected size @@ -192,10 +196,7 @@ impl PerfBuffer { match event_type { x if x == PERF_RECORD_SAMPLE as u32 => { buf.clear(); - if sample_size > buf.capacity() { - return Err(PerfBufferError::MoreSpaceNeeded { size: sample_size }); - } - + buf.reserve(sample_size); unsafe { buf.set_len(sample_size) }; fill_buf(sample_start, base, self.size, buf); @@ -239,12 +240,6 @@ impl PerfBuffer { events.lost += lost; } Ok(None) => { /* skip unknown event type */ } - Err(PerfBufferError::MoreSpaceNeeded { .. }) if events.read > 0 => { - // we have processed some events so we're going to return those. In the - // next read_events() we'll return an error unless the caller increases the - // buffer size - break; - } Err(e) => { // we got an error and we didn't process any events, propagate the error // and give the caller a chance to increase buffers diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 73a04161..ff4d02ac 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -51,9 +51,6 @@ impl> PerfEventArrayBuffer { /// # Errors /// /// [`PerfBufferError::NoBuffers`] is returned when `out_bufs` is empty. - /// - /// [`PerfBufferError::MoreSpaceNeeded { size }`](PerfBufferError) is returned when the size of the events is - /// bigger than the size of the out_bufs provided. pub fn read_events(&mut self, out_bufs: &mut [BytesMut]) -> Result { self.buf.read_events(out_bufs) }