Skip to content

Commit b93ee8c

Browse files
tamirdCodex
andcommitted
Use plain arrays in ring buf tests
Store ring buffer accounting in plain arrays instead of per-CPU arrays and use atomic increments in the eBPF test program where concurrent writers still share the counters. Co-authored-by: Codex <noreply@openai.com>
1 parent b9cb76b commit b93ee8c

File tree

5 files changed

+32
-50
lines changed

5 files changed

+32
-50
lines changed

ebpf/aya-ebpf/src/programs/probe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl ProbeContext {
2626
/// unsafe fn try_kprobe_try_to_wake_up(ctx: ProbeContext) -> Result<u32, u32> {
2727
/// let tp: *const task_struct = ctx.arg(0).ok_or(1u32)?;
2828
/// let pid = unsafe {
29-
/// bpf_probe_read(core::ptr::addr_of!((*tp).pid))
29+
/// bpf_probe_read(&raw const (*tp).pid)
3030
/// }.map_err(|err| err as u32)?;
3131
///
3232
/// // Do something with pid or something else with tp

test/integration-common/src/lib.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,6 @@ pub mod ring_buf {
6262
pub rejected: u64,
6363
}
6464

65-
impl core::ops::Add for Registers {
66-
type Output = Self;
67-
fn add(self, rhs: Self) -> Self::Output {
68-
Self {
69-
dropped: self.dropped + rhs.dropped,
70-
rejected: self.rejected + rhs.rejected,
71-
}
72-
}
73-
}
74-
75-
impl<'a> core::iter::Sum<&'a Self> for Registers {
76-
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
77-
iter.fold(Default::default(), |a, b| a + *b)
78-
}
79-
}
80-
8165
#[cfg(feature = "user")]
8266
unsafe impl aya::Pod for Registers {}
8367
}

test/integration-ebpf/src/kprobe.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
1-
#![cfg_attr(
2-
target_arch = "bpf",
3-
expect(
4-
internal_features,
5-
reason = "core_intrinsics is required for atomic_xadd on BPF targets"
6-
),
7-
expect(
8-
unstable_features,
9-
reason = "core_intrinsics is required for atomic_xadd on BPF targets"
10-
),
11-
feature(core_intrinsics)
12-
)]
131
#![no_std]
142
#![no_main]
153
#![expect(unused_crate_dependencies, reason = "used in other bins")]
4+
#![expect(internal_features, reason = "atomic_xadd is unstable")]
5+
#![expect(unstable_features, reason = "atomic_xadd is unstable")]
6+
#![feature(core_intrinsics)]
167

178
use aya_ebpf::{
189
EbpfContext as _, Global,
@@ -46,14 +37,11 @@ fn test_kprobe_trigger(ctx: ProbeContext) -> u32 {
4637
return 0;
4738
};
4839

49-
#[cfg(target_arch = "bpf")]
5040
unsafe {
5141
core::intrinsics::atomic_xadd::<u64, u64, { core::intrinsics::AtomicOrdering::Relaxed }>(
5242
hits, 1,
5343
);
5444
}
5545

56-
let _: *mut u64 = hits;
57-
5846
0
5947
}

test/integration-ebpf/src/ring_buf.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#![no_std]
22
#![no_main]
33
#![expect(unused_crate_dependencies, reason = "used in other bins")]
4+
#![expect(internal_features, reason = "atomic_xadd is unstable")]
5+
#![expect(unstable_features, reason = "atomic_xadd is unstable")]
6+
#![feature(core_intrinsics)]
47

58
use aya_ebpf::{
69
btf_maps::RingBuf as BtfRingBuf,
710
macros::{btf_map, map, uprobe},
8-
maps::{PerCpuArray, RingBuf as LegacyRingBuf},
11+
maps::{Array, RingBuf as LegacyRingBuf},
912
programs::ProbeContext,
1013
};
1114
use integration_common::ring_buf::Registers;
@@ -21,26 +24,27 @@ static RING_BUF_MISMATCH: BtfRingBuf<u32, 0, 0> = BtfRingBuf::new();
2124
#[map]
2225
static RING_BUF_LEGACY: LegacyRingBuf = LegacyRingBuf::with_byte_size(0, 0);
2326

24-
// Use a PerCpuArray to store the registers so that we can update the values from multiple CPUs
25-
// without needing synchronization. Atomics exist [1], but aren't exposed.
26-
//
27-
// [1]: https://lwn.net/Articles/838884/
2827
#[map]
29-
static REGISTERS: PerCpuArray<Registers> = PerCpuArray::with_max_entries(1, 0);
28+
static REGISTERS: Array<Registers> = Array::with_max_entries(1, 0);
3029

3130
#[map]
32-
static REGISTERS_LEGACY: PerCpuArray<Registers> = PerCpuArray::with_max_entries(1, 0);
31+
static REGISTERS_LEGACY: Array<Registers> = Array::with_max_entries(1, 0);
3332

3433
macro_rules! define_ring_buf_test {
3534
($registers:ident, $name:ident, $reserve:expr) => {
3635
#[uprobe]
3736
fn $name(ctx: ProbeContext) {
38-
let Registers { dropped, rejected } = match $registers.get_ptr_mut(0) {
39-
Some(regs) => unsafe { &mut *regs },
40-
None => return,
37+
let Some(regs) = $registers.get_ptr_mut(0) else {
38+
return;
4139
};
4240
let Some(mut entry) = $reserve else {
43-
*dropped += 1;
41+
unsafe {
42+
core::intrinsics::atomic_xadd::<
43+
u64,
44+
u64,
45+
{ core::intrinsics::AtomicOrdering::Relaxed },
46+
>(&raw mut (*regs).dropped, 1);
47+
}
4448
return;
4549
};
4650
// Write the first argument to the function back out to RING_BUF if it is even,
@@ -53,7 +57,13 @@ macro_rules! define_ring_buf_test {
5357
entry.write(arg);
5458
entry.submit(0);
5559
} else {
56-
*rejected += 1;
60+
unsafe {
61+
core::intrinsics::atomic_xadd::<
62+
u64,
63+
u64,
64+
{ core::intrinsics::AtomicOrdering::Relaxed },
65+
>(&raw mut (*regs).rejected, 1);
66+
}
5767
entry.discard(0);
5868
}
5969
}

test/integration-test/src/tests/ring_buf.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use anyhow::Context as _;
1313
use assert_matches::assert_matches;
1414
use aya::{
1515
Ebpf, EbpfLoader,
16-
maps::{MapData, array::PerCpuArray, ring_buf::RingBuf},
16+
maps::{Array, MapData, ring_buf::RingBuf},
1717
programs::UProbe,
1818
};
1919
use aya_obj::generated::BPF_RINGBUF_HDR_SZ;
@@ -25,7 +25,7 @@ use tokio::io::{Interest, unix::AsyncFd};
2525
struct RingBufTest {
2626
bpf: Ebpf,
2727
ring_buf: RingBuf<MapData>,
28-
regs: PerCpuArray<MapData, Registers>,
28+
regs: Array<MapData, Registers>,
2929
}
3030

3131
const RING_BUF: &str = "RING_BUF";
@@ -87,7 +87,7 @@ impl RingBufTest {
8787
let ring_buf = bpf.take_map(variant.map).unwrap();
8888
let ring_buf = RingBuf::try_from(ring_buf).unwrap();
8989
let regs = bpf.take_map(variant.regs).unwrap();
90-
let regs = PerCpuArray::<_, Registers>::try_from(regs).unwrap();
90+
let regs = Array::<_, Registers>::try_from(regs).unwrap();
9191
let prog: &mut UProbe = bpf.program_mut(variant.prog).unwrap().try_into().unwrap();
9292
prog.load().unwrap();
9393
prog.attach("ring_buf_trigger_ebpf_program", "/proc/self/exe", None)
@@ -166,7 +166,7 @@ fn ring_buf(n: usize) {
166166
// Ensure that the data that was read matches what was passed, and the rejected count was set
167167
// properly.
168168
assert_eq!(seen, expected);
169-
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum();
169+
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap();
170170
assert_eq!(dropped, expected_dropped);
171171
assert_eq!(rejected, expected_rejected);
172172
}
@@ -322,7 +322,7 @@ async fn ring_buf_async_with_drops() {
322322
u64::try_from(data.len().saturating_sub(RING_BUF_MAX_ENTRIES - 1)).unwrap();
323323
let max_seen = u64::try_from(data.iter().filter(|v| *v % 2 == 0).count()).unwrap();
324324
let max_rejected = u64::try_from(data.len()).unwrap() - max_seen;
325-
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum();
325+
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap();
326326
let total = u64::try_from(data.len()).unwrap();
327327
let min_seen = max_seen.saturating_sub(max_dropped);
328328
let min_rejected = max_rejected.saturating_sub(dropped);
@@ -408,7 +408,7 @@ async fn ring_buf_async_no_drop() {
408408

409409
// Ensure that the data that was read matches what was passed.
410410
assert_eq!(&seen, &expected);
411-
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum();
411+
let Registers { dropped, rejected } = regs.get(&0, 0).unwrap();
412412
assert_eq!(dropped, 0);
413413
assert_eq!(rejected, (data.len() - expected.len()).try_into().unwrap());
414414
}

0 commit comments

Comments
 (0)