From cf4cfc1908bb04c4f5680aa011fcf0d93075bd7f Mon Sep 17 00:00:00 2001 From: Emmanuel Keller Date: Fri, 7 Jul 2023 19:43:16 +0100 Subject: [PATCH] processor micro-benchmark (#2216) --- Cargo.lock | 1 + lib/Cargo.toml | 6 ++- lib/benches/processor.rs | 112 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 lib/benches/processor.rs diff --git a/Cargo.lock b/Cargo.lock index 74d264a7..f4f4b5be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1191,6 +1191,7 @@ dependencies = [ "ciborium", "clap 3.2.25", "criterion-plot", + "futures 0.3.28", "itertools 0.10.5", "lazy_static", "num-traits", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 9b3b8b56..bf7641b0 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -114,7 +114,7 @@ url = "2.4.0" bytes = "1.4.0" [dev-dependencies] -criterion = "0.4" +criterion = { version="0.4", features= [ "async_futures" ] } env_logger = "0.10.0" test-log = "0.2.12" pprof = { version = "0.11.1", features = [ "flamegraph", "criterion" ] } @@ -147,3 +147,7 @@ harness = false [[bench]] name = "parser" harness = false + +[[bench]] +name = "processor" +harness = false \ No newline at end of file diff --git a/lib/benches/processor.rs b/lib/benches/processor.rs new file mode 100644 index 00000000..e8a1eb30 --- /dev/null +++ b/lib/benches/processor.rs @@ -0,0 +1,112 @@ +use criterion::async_executor::FuturesExecutor; +use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; +use std::time::Duration; +use surrealdb::dbs::Session; +use surrealdb::kvs::Datastore; +use surrealdb::sql::Value; + +fn bench_processor(c: &mut Criterion) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let i = rt.block_on(prepare_data()); + + let mut group = c.benchmark_group("processor"); + group.throughput(Throughput::Elements(1)); + group.sample_size(10); + group.measurement_time(Duration::from_secs(15)); + + group.bench_function("table-iterator", |b| { + b.to_async(FuturesExecutor).iter(|| run(&i, "SELECT * FROM item", i.count * 5)) + }); + + group.bench_function("table-iterator-parallel", |b| { + b.to_async(FuturesExecutor).iter(|| run(&i, "SELECT * FROM item PARALLEL", i.count * 5)) + }); + + group.bench_function("non-uniq-index-iterator", |b| { + b.to_async(FuturesExecutor).iter(|| run(&i, "SELECT * FROM item WHERE number=4", i.count)) + }); + + group.bench_function("non-uniq-index-iterator-parallel", |b| { + b.to_async(FuturesExecutor) + .iter(|| run(&i, "SELECT * FROM item WHERE number=4 PARALLEL", i.count)) + }); + + group.bench_function("full-text-index-iterator", |b| { + b.to_async(FuturesExecutor) + .iter(|| run(&i, "SELECT * FROM item WHERE label @@ 'charlie'", i.count)) + }); + + group.bench_function("full-text-index-iterator-parallel", |b| { + b.to_async(FuturesExecutor) + .iter(|| run(&i, "SELECT * FROM item WHERE label @@ 'charlie' PARALLEL", i.count)) + }); + + group.finish(); +} + +struct Input { + dbs: Datastore, + ses: Session, + count: usize, +} + +async fn prepare_data() -> Input { + let dbs = Datastore::new("memory").await.unwrap(); + let ses = Session::for_kv().with_ns("bench").with_db("bench"); + let sql = format!( + r"DEFINE INDEX number ON item FIELDS number; + DEFINE ANALYZER simple TOKENIZERS blank,class; + DEFINE INDEX search ON item FIELDS label SEARCH ANALYZER simple BM25" + ); + let res = &mut dbs.execute(&sql, &ses, None).await.unwrap(); + for _ in 0..3 { + assert!(res.remove(0).result.is_ok()); + } + + let count = if cfg!(debug_assertions) { + 100 // debug is much slower! + } else { + 10_000 + }; + + for i in 0..count { + let j = i * 5; + let a = j; + let b = j + 1; + let c = j + 2; + let d = j + 3; + let e = j + 4; + let sql = format!( + r"CREATE item SET id = {a}, name = '{a}', number = 0, label='alpha'; + CREATE item SET id = {b}, name = '{b}', number = 1, label='bravo'; + CREATE item SET id = {c}, name = '{c}', number = 2, label='charlie'; + CREATE item SET id = {d}, name = '{d}', number = 3, label='delta'; + CREATE item SET id = {e}, name = '{e}', number = 4, label='echo';", + ); + let res = &mut dbs.execute(&sql, &ses, None).await.unwrap(); + for _ in 0..5 { + assert!(res.remove(0).result.is_ok()); + } + } + Input { + dbs, + ses, + count, + } +} + +async fn run(i: &Input, q: &str, expected: usize) { + let mut r = i.dbs.execute(black_box(q), &i.ses, None).await.unwrap(); + if cfg!(debug_assertions) { + assert_eq!(r.len(), 1); + if let Value::Array(a) = r.remove(0).result.unwrap() { + assert_eq!(a.len(), expected); + } else { + panic!("Fail"); + } + } + black_box(r); +} + +criterion_group!(benches, bench_processor); +criterion_main!(benches);