use std::alloc::System;
#[global_allocator]
static A: System = System;
extern crate criterion;
extern crate wirefilter;
use criterion::{
criterion_group, criterion_main, Bencher, Benchmark, Criterion, ParameterizedBenchmark,
};
use std::{fmt::Debug, net::IpAddr};
use wirefilter::{ExecutionContext, GetType, LhsValue, Scheme};
struct FieldBench<'a, T: 'static> {
field: &'static str,
filters: &'static [&'static str],
values: &'a [T],
}
impl<'a, T: 'static + Copy + Debug + Into<LhsValue<'static>>> FieldBench<'a, T> {
fn run(self, c: &mut Criterion) {
let FieldBench {
filters,
field,
values,
} = self;
let ty = values[0].into().get_type();
for &filter in filters {
let owned_name;
let name = if let Some(pos) = filter.find(" in {") {
owned_name = format!("{} in ...", &filter[..pos]);
&owned_name
} else {
filter
};
c.bench(
"parsing",
Benchmark::new(name, move |b: &mut Bencher| {
let mut scheme = Scheme::default();
scheme.add_field(field.to_owned(), ty).unwrap();
b.iter(|| scheme.parse(filter).unwrap());
}),
);
c.bench(
"compilation",
Benchmark::new(name, move |b: &mut Bencher| {
let mut scheme = Scheme::default();
scheme.add_field(field.to_owned(), ty).unwrap();
let filter = scheme.parse(filter).unwrap();
b.iter_with_setup(move || filter.clone(), |filter| filter.compile());
}),
);
c.bench(
"execution",
ParameterizedBenchmark::new(
name,
move |b: &mut Bencher, value: &T| {
let mut scheme = Scheme::default();
scheme.add_field(field.to_owned(), ty).unwrap();
let filter = scheme.parse(filter).unwrap();
let filter = filter.compile();
let mut exec_ctx = ExecutionContext::new(&scheme);
exec_ctx.set_field_value(field, *value).unwrap();
b.iter(|| filter.execute(&exec_ctx));
},
values.iter().cloned(),
),
);
}
}
}
fn bench_ip_comparisons(c: &mut Criterion) {
FieldBench {
field: "ip.addr",
filters: &[
"ip.addr == 173.245.48.1",
"ip.addr == 2606:4700:4700::1111",
"ip.addr >= 173.245.48.0 && ip.addr < 173.245.49.0",
"ip.addr >= 2606:4700:: && ip.addr < 2606:4701::",
"ip.addr in { 103.21.244.0/22 2405:8100::/32 104.16.0.0/12 2803:f800::/32 131.0.72.0/22 173.245.48.0/20 2405:b500::/32 172.64.0.0/13 190.93.240.0/20 103.22.200.0/22 2606:4700::/32 198.41.128.0/17 197.234.240.0/22 162.158.0.0/15 108.162.192.0/18 2c0f:f248::/32 2400:cb00::/32 103.31.4.0/22 2a06:98c0::/29 141.101.64.0/18 188.114.96.0/20 }"
],
values: &[
IpAddr::from([127, 0, 0, 1]),
IpAddr::from([0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334]),
IpAddr::from([173, 245, 48, 1]),
IpAddr::from([0x2606, 0x4700, 0x4700, 0x0000, 0x0000, 0x0000, 0x0000, 0x1111]),
]
}.run(c)
}
fn bench_int_comparisons(c: &mut Criterion) {
FieldBench {
field: "tcp.port",
filters: &[
"tcp.port == 80",
"tcp.port >= 1024",
"tcp.port in { 80 8080 8880 2052 2082 2086 2095 }",
],
values: &[80, 8081],
}
.run(c)
}
fn bench_string_comparisons(c: &mut Criterion) {
FieldBench {
field: "ip.geoip.country",
filters: &[
r#"ip.geoip.country == "GB""#,
r#"ip.geoip.country in { "AT" "BE" "BG" "HR" "CY" "CZ" "DK" "EE" "FI" "FR" "DE" "GR" "HU" "IE" "IT" "LV" "LT" "LU" "MT" "NL" "PL" "PT" "RO" "SK" "SI" "ES" "SE" "GB" "GF" "GP" "MQ" "ME" "YT" "RE" "MF" "GI" "AX" "PM" "GL" "BL" "SX" "AW" "CW" "WF" "PF" "NC" "TF" "AI" "BM" "IO" "VG" "KY" "FK" "MS" "PN" "SH" "GS" "TC" "AD" "LI" "MC" "SM" "VA" "JE" "GG" "GI" "CH" }"#,
],
values: &["GB", "T1"],
}.run(c)
}
fn bench_string_matches(c: &mut Criterion) {
FieldBench {
field: "http.user_agent",
filters: &[
r#"http.user_agent ~ "(?i)googlebot/\d+\.\d+""#,
r#"http.user_agent ~ "Googlebot""#,
r#"http.user_agent contains "Googlebot""#
],
values: &[
"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
]
}.run(c)
}
criterion_group! {
name = field_benchmarks;
config = Criterion::default();
targets =
bench_ip_comparisons,
bench_int_comparisons,
bench_string_comparisons,
bench_string_matches,
}
criterion_main!(field_benchmarks);