Skip to content

Commit

Permalink
FW-1090: add some benchmarks for functions (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
marmeladema authored Mar 27, 2019
1 parent c449e9c commit bbc62a7
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 17 deletions.
155 changes: 139 additions & 16 deletions engine/benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,31 @@ 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};
use std::{clone::Clone, fmt::Debug, net::IpAddr};
use wirefilter::{
ExecutionContext, Function, FunctionArg, FunctionArgKind, FunctionImpl, GetType, LhsValue,
Scheme, Type,
};

fn lowercase<'a>(args: &[LhsValue<'a>]) -> LhsValue<'a> {
let input = &args[0];
match input {
LhsValue::Bytes(bytes) => LhsValue::Bytes(bytes.to_ascii_lowercase().into()),
_ => panic!("Invalid type: expected Bytes, got {:?}", input),
}
}

fn uppercase<'a>(args: &[LhsValue<'a>]) -> LhsValue<'a> {
let input = &args[0];
match input {
LhsValue::Bytes(bytes) => LhsValue::Bytes(bytes.to_ascii_uppercase().into()),
_ => panic!("Invalid type: expected Bytes, got {:?}", input),
}
}

struct FieldBench<'a, T: 'static> {
field: &'static str,
functions: &'a [(&'static str, Function)],
filters: &'static [&'static str],
values: &'a [T],
}
Expand All @@ -24,6 +44,7 @@ impl<'a, T: 'static + Copy + Debug + Into<LhsValue<'static>>> FieldBench<'a, T>
fn run(self, c: &mut Criterion) {
let FieldBench {
filters,
functions,
field,
values,
} = self;
Expand All @@ -44,42 +65,60 @@ impl<'a, T: 'static + Copy + Debug + Into<LhsValue<'static>>> FieldBench<'a, T>

c.bench(
"parsing",
Benchmark::new(name, move |b: &mut Bencher| {
Benchmark::new(name, {
let mut scheme = Scheme::default();
scheme.add_field(field.to_owned(), ty).unwrap();

b.iter(|| scheme.parse(filter).unwrap());
for (name, function) in functions {
scheme
.add_function((*name).into(), function.clone())
.unwrap();
}
move |b: &mut Bencher| {
b.iter(|| scheme.parse(filter).unwrap());
}
}),
);

c.bench(
"compilation",
Benchmark::new(name, move |b: &mut Bencher| {
Benchmark::new(name, {
let mut scheme = Scheme::default();
scheme.add_field(field.to_owned(), ty).unwrap();
for (name, function) in functions {
scheme
.add_function((*name).into(), function.clone())
.unwrap();
}
move |b: &mut Bencher| {
let filter = scheme.parse(filter).unwrap();

let filter = scheme.parse(filter).unwrap();

b.iter_with_setup(move || filter.clone(), |filter| filter.compile());
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();
for (name, function) in functions {
scheme
.add_function((*name).into(), function.clone())
.unwrap();
}
move |b: &mut Bencher, value: &T| {
let filter = scheme.parse(filter).unwrap();

let filter = scheme.parse(filter).unwrap();

let filter = filter.compile();
let filter = filter.compile();

let mut exec_ctx = ExecutionContext::new(&scheme);
exec_ctx.set_field_value(field, *value).unwrap();
let mut exec_ctx = ExecutionContext::new(&scheme);
exec_ctx.set_field_value(field, *value).unwrap();

b.iter(|| filter.execute(&exec_ctx));
b.iter(|| filter.execute(&exec_ctx));
}
},
values.iter().cloned(),
),
Expand All @@ -91,6 +130,7 @@ impl<'a, T: 'static + Copy + Debug + Into<LhsValue<'static>>> FieldBench<'a, T>
fn bench_ip_comparisons(c: &mut Criterion) {
FieldBench {
field: "ip.addr",
functions: &[],
filters: &[
"ip.addr == 173.245.48.1",
"ip.addr == 2606:4700:4700::1111",
Expand All @@ -110,6 +150,7 @@ fn bench_ip_comparisons(c: &mut Criterion) {
fn bench_int_comparisons(c: &mut Criterion) {
FieldBench {
field: "tcp.port",
functions: &[],
filters: &[
"tcp.port == 80",
"tcp.port >= 1024",
Expand All @@ -123,6 +164,7 @@ fn bench_int_comparisons(c: &mut Criterion) {
fn bench_string_comparisons(c: &mut Criterion) {
FieldBench {
field: "ip.geoip.country",
functions: &[],
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" }"#,
Expand All @@ -134,6 +176,7 @@ fn bench_string_comparisons(c: &mut Criterion) {
fn bench_string_matches(c: &mut Criterion) {
FieldBench {
field: "http.user_agent",
functions: &[],
filters: &[
r#"http.user_agent ~ "(?i)googlebot/\d+\.\d+""#,
r#"http.user_agent ~ "Googlebot""#,
Expand All @@ -146,6 +189,84 @@ fn bench_string_matches(c: &mut Criterion) {
}.run(c)
}

fn bench_simple_string_function_comparison(c: &mut Criterion) {
FieldBench {
field: "http.host",
functions: &[(
"lowercase",
Function {
args: vec![FunctionArg {
arg_kind: FunctionArgKind::Field,
val_type: Type::Bytes,
}],
opt_args: vec![],
return_type: Type::Bytes,
implementation: FunctionImpl::new(lowercase),
},
)],
filters: &[
r#"lowercase(http.host) == "EXAMPLE.ORG""#,
r#"lowercase(http.host) == "example.org""#,
r#"lowercase(http.host) in { "EXAMPLE.ORG" "example.org" }"#,
],
values: &[
"example.org",
"EXAMPLE.ORG",
"ExAmPlE.oRg",
"cloudflare.org",
"CLOUDFLARE.ORG",
"ClOuDfArE.oRg",
],
}
.run(c)
}

fn bench_nested_string_function_comparison(c: &mut Criterion) {
FieldBench {
field: "http.host",
functions: &[
(
"lowercase",
Function {
args: vec![FunctionArg {
arg_kind: FunctionArgKind::Field,
val_type: Type::Bytes,
}],
opt_args: vec![],
return_type: Type::Bytes,
implementation: FunctionImpl::new(lowercase),
},
),
(
"uppercase",
Function {
args: vec![FunctionArg {
arg_kind: FunctionArgKind::Field,
val_type: Type::Bytes,
}],
opt_args: vec![],
return_type: Type::Bytes,
implementation: FunctionImpl::new(uppercase),
},
),
],
filters: &[
r#"uppercase(lowercase(http.host)) == "EXAMPLE.ORG""#,
r#"uppercase(lowercase(http.host)) == "example.org""#,
r#"uppercase(lowercase(http.host)) in { "EXAMPLE.ORG" "example.org" }"#,
],
values: &[
"example.org",
"EXAMPLE.ORG",
"ExAmPlE.oRg",
"cloudflare.org",
"CLOUDFLARE.ORG",
"ClOuDfArE.oRg",
],
}
.run(c)
}

criterion_group! {
name = field_benchmarks;
config = Criterion::default();
Expand All @@ -154,6 +275,8 @@ criterion_group! {
bench_int_comparisons,
bench_string_comparisons,
bench_string_matches,
bench_simple_string_function_comparison,
bench_nested_string_function_comparison,
}

criterion_main!(field_benchmarks);
3 changes: 2 additions & 1 deletion engine/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use types::{LhsValue, RhsValue, Type};
type FunctionPtr = for<'a> fn(&[LhsValue<'a>]) -> LhsValue<'a>;

/// Wrapper around a function pointer providing the runtime implemetation.
#[derive(Clone)]
pub struct FunctionImpl(FunctionPtr);

impl FunctionImpl {
Expand Down Expand Up @@ -62,7 +63,7 @@ pub struct FunctionOptArg {
}

/// Defines a function.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Function {
/// List of mandatory arguments.
pub args: Vec<FunctionArg>,
Expand Down

0 comments on commit bbc62a7

Please sign in to comment.