Merge branch 'selftests-bpf-xdp-lb-benchmark-fixes'

Puranjay Mohan says:

====================
selftests/bpf: XDP LB benchmark fixes

Changelog:
v1: https://lore.kernel.org/all/20260519163632.2220753-1-puranjay@kernel.org/
Changes in v2:
- Drop patch 3 as it was fixing a situation that can never happen in practice.
- Replace | 1 logic in patch 1 with replacing ^ operator with +

Three bug fixes and one improvement for the XDP LB and batch-timing
benchmarks.

The cold_lru validation was failing a lot because batch_hash could
compute to zero when batch_gen matched the CPU id. Similarly,
pre-populated UDP LRU entries had atime=0 so they'd expire immediately
on any CPU that calibration didn't warm. Both are fixed in patches 1-2.

Patch 3 adds IQR outlier filtering to the timing stats to stabilize
scenarios with high stddev.
====================

Link: https://patch.msgid.link/20260520133338.3392667-1-puranjay@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2026-05-20 09:25:47 -07:00
commit 3db0419c01
3 changed files with 38 additions and 1 deletions

View File

@ -65,6 +65,31 @@ static int collect_samples(struct bpf_bench_timing *t,
return total;
}
static int filter_outliers_iqr(double *sorted, int n)
{
double q1, q3, iqr, lo, hi;
int start = 0, end = n;
if (n < 8)
return n;
q1 = sorted[n / 4];
q3 = sorted[3 * n / 4];
iqr = q3 - q1;
lo = q1 - 1.5 * iqr;
hi = q3 + 1.5 * iqr;
while (start < end && sorted[start] < lo)
start++;
while (end > start && sorted[end - 1] > hi)
end--;
if (start > 0)
memmove(sorted, sorted + start, (end - start) * sizeof(double));
return end - start;
}
static void compute_stats(const double *sorted, int n,
struct timing_stats *s)
{
@ -150,6 +175,7 @@ void bpf_bench_timing_report(struct bpf_bench_timing *t, const char *name, const
return;
}
total = filter_outliers_iqr(all, total);
compute_stats(all, total, &s);
if (t->machine_readable) {

View File

@ -563,12 +563,23 @@ static void create_per_cpu_lru_maps(struct xdp_lb_bench *skel)
nr_inner_maps = nr_cpus;
}
static __u64 ktime_get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (__u64)ts.tv_sec * 1000000000ULL + ts.tv_nsec;
}
static void populate_lru(const struct test_scenario *sc, __u32 real_idx)
{
struct real_pos_lru lru = { .pos = real_idx };
struct flow_key fk;
int i, err;
if (sc->ip_proto == IPPROTO_UDP)
lru.atime = ktime_get_ns();
build_flow_key(&fk, sc);
/* Insert into every per-CPU inner LRU so the entry is found

View File

@ -618,7 +618,7 @@ int xdp_lb_bench(struct xdp_md *xdp)
__u32 *saddr = data + saddr_off;
batch_gen++;
batch_hash = (batch_gen ^ bpf_get_smp_processor_id()) * KNUTH_HASH_MULT;
batch_hash = (batch_gen + bpf_get_smp_processor_id()) * KNUTH_HASH_MULT;
if ((void *)(saddr + 1) <= data_end)
*saddr ^= batch_hash;
}