use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use std::hint::black_box;
use ipnetx::ipset::{IpSet, IpSetBuilder};
use ipnetx::range::IpRange;
use std::net::Ipv4Addr;
fn make_set(start: u32, count: u32) -> IpSet<Ipv4Addr> {
let mut builder = IpSetBuilder::<Ipv4Addr>::new();
for i in start..start + count {
let b2 = ((i / 256) % 256) as u8;
let b3 = (i % 256) as u8;
builder.add_range(IpRange::new(
Ipv4Addr::new(10, b2, b3, 0),
Ipv4Addr::new(10, b2, b3, 255),
));
}
builder.build()
}
fn make_raw_ranges(count: u32) -> Vec<IpRange<Ipv4Addr>> {
(0..count)
.rev()
.map(|i| {
let b2 = ((i / 256) % 256) as u8;
let b3 = (i % 256) as u8;
IpRange::new(
Ipv4Addr::new(10, b2, b3, 0),
Ipv4Addr::new(10, b2, b3, 255),
)
})
.collect()
}
fn make_unaligned_set(count: u32) -> IpSet<Ipv4Addr> {
let mut builder = IpSetBuilder::<Ipv4Addr>::new();
for i in 0..count {
let b2 = ((i / 256) % 256) as u8;
let b3 = (i % 256) as u8;
builder.add_range(IpRange::new(
Ipv4Addr::new(10, b2, b3, 1),
Ipv4Addr::new(10, b2, b3, 254),
));
}
builder.build()
}
fn make_sparse_set(start_offset: u32, count: u32) -> IpSet<Ipv4Addr> {
let mut builder = IpSetBuilder::<Ipv4Addr>::new();
for i in 0..count {
let idx = start_offset + i * 3;
let b2 = ((idx / 256) % 256) as u8;
let b3 = (idx % 256) as u8;
builder.add_range(IpRange::new(
Ipv4Addr::new(10, b2, b3, 0),
Ipv4Addr::new(10, b2, b3, 100),
));
}
builder.build()
}
fn bench_contains_ip(c: &mut Criterion) {
let mut group = c.benchmark_group("contains_ip");
for &size in &[100u32, 1_000, 10_000] {
let set = make_set(0, size);
let mid = size / 2;
let ip = Ipv4Addr::new(10, ((mid / 256) % 256) as u8, (mid % 256) as u8, 128);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| {
b.iter(|| set.contains_ip(black_box(ip)));
});
}
group.finish();
}
fn bench_build(c: &mut Criterion) {
let mut group = c.benchmark_group("build");
for &size in &[100u32, 1_000, 10_000] {
let raw = make_raw_ranges(size);
group.bench_with_input(BenchmarkId::from_parameter(size), &raw, |b, raw| {
b.iter(|| {
let mut builder = IpSetBuilder::<Ipv4Addr>::new();
for &range in raw {
builder.add_range(range);
}
black_box(builder.build())
});
});
}
group.finish();
}
fn bench_union(c: &mut Criterion) {
let mut group = c.benchmark_group("union");
for &size in &[100u32, 1_000, 10_000] {
let a = make_set(0, size);
let b = make_set(size / 2, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.union(black_box(&b))));
});
}
group.finish();
}
fn bench_union_sparse(c: &mut Criterion) {
let mut group = c.benchmark_group("union_sparse");
for &size in &[100u32, 1_000, 10_000] {
let a = make_sparse_set(0, size);
let b = make_sparse_set(1, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.union(black_box(&b))));
});
}
group.finish();
}
fn bench_intersection(c: &mut Criterion) {
let mut group = c.benchmark_group("intersection");
for &size in &[100u32, 1_000, 10_000] {
let a = make_set(0, size);
let b = make_set(size / 2, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.intersection(black_box(&b))));
});
}
group.finish();
}
fn bench_difference(c: &mut Criterion) {
let mut group = c.benchmark_group("difference");
for &size in &[100u32, 1_000, 10_000] {
let a = make_set(0, size);
let b = make_set(size / 2, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.difference(black_box(&b))));
});
}
group.finish();
}
fn bench_complement(c: &mut Criterion) {
let mut group = c.benchmark_group("complement");
for &size in &[100u32, 1_000, 10_000] {
let a = make_set(0, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.complement()));
});
}
group.finish();
}
fn bench_count(c: &mut Criterion) {
let mut group = c.benchmark_group("count");
for &size in &[100u32, 1_000, 10_000] {
let a = make_set(0, size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |bench, _| {
bench.iter(|| black_box(a.count()));
});
}
group.finish();
}
fn bench_build_with_removals(c: &mut Criterion) {
let mut group = c.benchmark_group("build_with_removals");
for &size in &[100u32, 1_000, 10_000] {
let raw_adds: Vec<IpRange<Ipv4Addr>> = (0..size)
.rev()
.map(|i| {
let b2 = ((i / 256) % 256) as u8;
let b3 = (i % 256) as u8;
IpRange::new(Ipv4Addr::new(10, b2, b3, 0), Ipv4Addr::new(10, b2, b3, 255))
})
.collect();
let raw_removes: Vec<IpRange<Ipv4Addr>> = (size / 2..size)
.map(|i| {
let b2 = ((i / 256) % 256) as u8;
let b3 = (i % 256) as u8;
IpRange::new(Ipv4Addr::new(10, b2, b3, 0), Ipv4Addr::new(10, b2, b3, 255))
})
.collect();
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| {
b.iter(|| {
let mut builder = IpSetBuilder::<Ipv4Addr>::new();
for &range in &raw_adds {
builder.add_range(range);
}
for &range in &raw_removes {
builder.remove_range(range);
}
black_box(builder.build())
});
});
}
group.finish();
}
fn bench_is_subset_of(c: &mut Criterion) {
let mut group = c.benchmark_group("is_subset_of");
for &size in &[100u32, 1_000, 10_000] {
let a_sub = make_set(size / 4, size / 2);
let b_full = make_set(0, size);
group.bench_with_input(BenchmarkId::new("true_subset", size), &size, |bench, _| {
bench.iter(|| black_box(a_sub.is_subset_of(black_box(&b_full))));
});
let a_ext = make_set(size / 2, size);
let b_half = make_set(0, size / 2);
group.bench_with_input(BenchmarkId::new("false_subset", size), &size, |bench, _| {
bench.iter(|| black_box(a_ext.is_subset_of(black_box(&b_half))));
});
let a_lo = make_set(0, size / 2);
let b_hi = make_set(size, size / 2);
group.bench_with_input(BenchmarkId::new("disjoint", size), &size, |bench, _| {
bench.iter(|| black_box(a_lo.is_subset_of(black_box(&b_hi))));
});
}
group.finish();
}
fn bench_iprange_prefixes(c: &mut Criterion) {
let mut group = c.benchmark_group("iprange_prefixes");
let aligned = IpRange::new(Ipv4Addr::new(192, 168, 1, 0), Ipv4Addr::new(192, 168, 1, 255));
group.bench_with_input(BenchmarkId::from_parameter("aligned"), &aligned, |b, r| {
b.iter(|| black_box(r.prefixes()));
});
let unaligned = IpRange::new(Ipv4Addr::new(10, 0, 0, 1), Ipv4Addr::new(10, 0, 0, 254));
group.bench_with_input(BenchmarkId::from_parameter("unaligned"), &unaligned, |b, r| {
b.iter(|| black_box(r.prefixes()));
});
group.finish();
}
fn bench_ipset_prefixes(c: &mut Criterion) {
let mut group = c.benchmark_group("ipset_prefixes");
for &size in &[100u32, 1_000, 10_000] {
let aligned = make_set(0, size);
group.bench_with_input(BenchmarkId::new("aligned", size), &size, |b, _| {
b.iter(|| black_box(aligned.prefixes()));
});
let unaligned = make_unaligned_set(size);
group.bench_with_input(BenchmarkId::new("unaligned", size), &size, |b, _| {
b.iter(|| black_box(unaligned.prefixes()));
});
}
group.finish();
}
criterion_group!(
benches,
bench_contains_ip,
bench_build,
bench_build_with_removals,
bench_union,
bench_union_sparse,
bench_intersection,
bench_difference,
bench_complement,
bench_count,
bench_is_subset_of,
bench_iprange_prefixes,
bench_ipset_prefixes,
);
criterion_main!(benches);