Skip to content

Commit 7b6a57a

Browse files
daniel-nolandclaude
andcommitted
test(dpdk): ignore the idle-wait deadline test until AMD's waits are understood
an_idle_wait_sleeps_until_its_deadline fails now and then on AMD, in CI and locally: the EAL hands MWAITX the low 32 bits of the absolute TSC deadline (DPDK 1213a8895b, still so upstream), where its timer takes the time to wait, so an idle wait ends at the next interrupt instead (2 us to 1 ms for a 20 us wait on a Zen 4 workstation). Passing MWAITX the time to wait made every wait 10 us on a Threadripper 7000 (family 0x19 model 0x18), but on the Ryzen 7000 CI runner (model 0x61) every such wait returned in about 450 ns, so that change is not made yet. The test is ignored with a note until this is understood, so CI does not fail at random, and a failure now reports the CPU's vendor, family and model, the sleeper, and every wait's duration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Daniel Noland <daniel@githedgehog.com>
1 parent ab6a116 commit 7b6a57a

1 file changed

Lines changed: 46 additions & 8 deletions

File tree

‎dpdk/src/power/tests.rs‎

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,30 @@ fn sleeper(lcore: &LCore, watching: bool) -> Option<Sleeper> {
8484
Some(sleeper)
8585
}
8686

87+
/// The CPU's vendor, family and model, to tell hardware apart in a failure.
88+
fn cpu() -> String {
89+
#[cfg(target_arch = "x86_64")]
90+
{
91+
use core::arch::x86_64::__cpuid;
92+
let (vendor, signature) = (__cpuid(0), __cpuid(1));
93+
let bytes: Vec<u8> = [vendor.ebx, vendor.edx, vendor.ecx]
94+
.iter()
95+
.flat_map(|r| r.to_le_bytes())
96+
.collect();
97+
let eax = signature.eax;
98+
let family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
99+
let model = ((eax >> 4) & 0xf) | (((eax >> 16) & 0xf) << 4);
100+
format!(
101+
"{} family {family:#x} model {model:#x}",
102+
String::from_utf8_lossy(&bytes)
103+
)
104+
}
105+
#[cfg(not(target_arch = "x86_64"))]
106+
{
107+
"not x86_64".to_string()
108+
}
109+
}
110+
87111
/// The median of `n` runs of `f`.
88112
fn median(n: usize, mut f: impl FnMut() -> Duration) -> Duration {
89113
let mut runs: Vec<Duration> = (0..n).map(|_| f()).collect();
@@ -112,22 +136,36 @@ fn an_idle_ring_queue_is_watched_if_the_cpu_can() {
112136
/// The timeout must bound an idle wait without relying on an external interrupt.
113137
/// The lower bound allows faster hardware timers, including Zen 4's timer at twice the TSC rate,
114138
/// while rejecting waits that return immediately.
139+
///
140+
/// Ignored while AMD's waits are not understood. The EAL hands MWAITX the low 32 bits of the
141+
/// absolute TSC deadline (DPDK 1213a8895b), where its timer takes the time to wait, so an idle wait
142+
/// on AMD ends at the next interrupt instead: 2 us to 1 ms for a 20 us wait, and this test fails
143+
/// now and then. Passing MWAITX the time to wait fixed that on a Threadripper 7000 (family 0x19
144+
/// model 0x18: every wait 10 us), but on a Ryzen 7000 CI runner (model 0x61) every such wait
145+
/// returned in about 450 ns. Run it with `--ignored`; a failure reports the CPU and every wait.
115146
#[test]
147+
#[ignore = "AMD idle waits end at the next interrupt; see the doc comment"]
116148
fn an_idle_wait_sleeps_until_its_deadline() {
117149
on_a_ring(|lcore, rx, _, _| {
118150
let Some(sleeper) = sleeper(lcore, false) else {
119151
return;
120152
};
121-
let took = median(101, || {
122-
let start = clock::now();
123-
sleeper
124-
.sleep(lcore, [&*rx], Duration::from_micros(20))
125-
.unwrap();
126-
clock::elapsed(start)
127-
});
153+
let mut runs: Vec<Duration> = (0..101)
154+
.map(|_| {
155+
let start = clock::now();
156+
sleeper
157+
.sleep(lcore, [&*rx], Duration::from_micros(20))
158+
.unwrap();
159+
clock::elapsed(start)
160+
})
161+
.collect();
162+
runs.sort();
163+
let took = runs[runs.len() / 2];
128164
assert!(
129165
(Duration::from_micros(5)..Duration::from_micros(200)).contains(&took),
130-
"a 20 us wait took {took:?} at the median"
166+
"a 20 us wait took {took:?} at the median, on {} ({sleeper:?}); every wait, in ns: {:?}",
167+
cpu(),
168+
runs.iter().map(Duration::as_nanos).collect::<Vec<_>>()
131169
);
132170
});
133171
}

0 commit comments

Comments
 (0)