Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions aya/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,18 @@ once_cell = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
criterion = "0.5"
tempfile = { workspace = true }
test-case = { workspace = true }

[features]
bench = []

[[bench]]
name = "perf_buffer"
harness = false
required-features = ["bench"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs", "-D", "warnings"]
102 changes: 102 additions & 0 deletions aya/benches/perf_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#![allow(unused_crate_dependencies)]

use std::{mem, ptr};

use aya::maps::perf::bench::{BenchBuffer, default_page_size};
use aya_obj::generated::{perf_event_header, perf_event_type::PERF_RECORD_SAMPLE};
use bytes::BytesMut;
use criterion::{Throughput, black_box, criterion_group, criterion_main, Criterion};

fn write<T: Copy>(buf: &mut BenchBuffer, offset: usize, value: T) -> usize {
let dst = buf.data_mut().as_mut_ptr();
let head = offset + mem::size_of::<T>();
unsafe {
ptr::write_unaligned(dst.add(offset).cast(), value);
buf.mmap_page_mut().data_head = head as u64;
}
head
}

fn write_sample(buf: &mut BenchBuffer, offset: usize, sample_size: usize) -> usize {
let header = perf_event_header {
type_: PERF_RECORD_SAMPLE as u32,
misc: 0,
size: (mem::size_of::<perf_event_header>() + mem::size_of::<u32>() + sample_size) as u16,
};
let start = write(buf, offset, header);
let start = write(buf, start, sample_size as u32);
unsafe {
let dst = buf.data_mut().as_mut_ptr().add(start);
ptr::write_bytes(dst, 0xAB, sample_size);
}
let head = start + sample_size;
buf.mmap_page_mut().data_head = head as u64;
head
}

fn fill_samples(buf: &mut BenchBuffer, events: usize, sample_size: usize) -> usize {
let mut offset = 0;
for _ in 0..events {
offset = write_sample(buf, offset, sample_size);
}
buf.mmap_page_mut().data_tail = 0;
offset
}

fn bench_perf_buffer(c: &mut Criterion) {
let page_size = default_page_size();
let sample_sizes = [64, 256, 1024, 4096];
let page_counts = [1usize, 8, 32];

let mut group = c.benchmark_group("perf_buffer");
for &sample_size in &sample_sizes {
for &page_count in &page_counts {
let mut bench = BenchBuffer::new(page_size, page_count).unwrap();
let ring_size = page_size * page_count;
let event_size =
mem::size_of::<perf_event_header>() + mem::size_of::<u32>() + sample_size;
if event_size > ring_size {
continue;
}
let events = (ring_size / event_size).max(1);
fill_samples(&mut bench, events, sample_size);

let mut out_bufs = (0..events)
.map(|_| BytesMut::with_capacity(sample_size))
.collect::<Vec<_>>();

group.throughput(Throughput::Bytes((events * sample_size) as u64));
group.bench_function(
format!("copy/size{}_pages{}", sample_size, page_count),
|b| {
b.iter(|| {
bench.mmap_page_mut().data_tail = 0;
let result = bench.read_events(&mut out_bufs).unwrap();
black_box(result);
black_box(&out_bufs);
})
},
);

group.bench_function(
format!("raw/size{}_pages{}", sample_size, page_count),
|b| {
b.iter(|| {
bench.mmap_page_mut().data_tail = 0;
let raw = bench.read_events_raw().unwrap();
let mut total = 0usize;
for sample in raw {
let (first, second) = sample.data().as_slices();
total += first.len() + second.len();
}
black_box(total);
})
},
);
}
}
group.finish();
}

criterion_group!(benches, bench_perf_buffer);
criterion_main!(benches);
22 changes: 11 additions & 11 deletions aya/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,52 +58,52 @@ pub use sys::netlink_set_link_up;
// process when we try to close a fake file descriptor.
#[derive(Debug)]
struct MockableFd {
#[cfg(not(test))]
#[cfg(not(any(test, feature = "bench")))]
fd: OwnedFd,
#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
fd: Option<OwnedFd>,
}

impl MockableFd {
#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
const fn mock_signed_fd() -> i32 {
1337
}

#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
const fn mock_unsigned_fd() -> u32 {
1337
}

#[cfg(not(test))]
#[cfg(not(any(test, feature = "bench")))]
fn from_fd(fd: OwnedFd) -> Self {
Self { fd }
}

#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
fn from_fd(fd: OwnedFd) -> Self {
let fd = Some(fd);
Self { fd }
}

#[cfg(not(test))]
#[cfg(not(any(test, feature = "bench")))]
fn inner(&self) -> &OwnedFd {
let Self { fd } = self;
fd
}

#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
fn inner(&self) -> &OwnedFd {
let Self { fd } = self;
fd.as_ref().unwrap()
}

#[cfg(not(test))]
#[cfg(not(any(test, feature = "bench")))]
fn into_inner(self) -> OwnedFd {
self.fd
}

#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
fn into_inner(mut self) -> OwnedFd {
self.fd.take().unwrap()
}
Expand Down Expand Up @@ -144,7 +144,7 @@ impl FromRawFd for MockableFd {
}
}

#[cfg(test)]
#[cfg(any(test, feature = "bench"))]
impl Drop for MockableFd {
fn drop(&mut self) {
use std::os::fd::AsRawFd as _;
Expand Down
Loading
Loading