From a7a1d36535b2faa8eb261f4e06098bd5eb3690ca Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Fri, 15 Nov 2024 17:27:11 +0000 Subject: [PATCH] Run and test benchmarks against C# as well (#1965) Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com> --- .github/workflows/benchmarks.yml | 14 ++- Cargo.lock | 1 + crates/bench/Cargo.toml | 1 + crates/bench/benches/generic.rs | 7 +- crates/bench/benches/special.rs | 23 ++-- crates/bench/src/database.rs | 2 +- crates/bench/src/lib.rs | 45 +++++--- crates/bench/src/spacetime_module.rs | 54 ++++----- crates/bench/src/spacetime_raw.rs | 4 +- crates/bench/src/sqlite.rs | 4 +- .../Runtime/build/SpacetimeDB.Runtime.targets | 7 ++ crates/testing/src/modules.rs | 71 +++++++++--- .../tests/standalone_integration_test.rs | 107 +++++++++++------- modules/benchmarks-cs/ia_loop.cs | 8 +- 14 files changed, 216 insertions(+), 132 deletions(-) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 3afba57bc14..cf8332655e4 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -76,7 +76,7 @@ jobs: # summary PR" step). otherwise, we can use a fully shallow checkout fetch-depth: ${{ env.PR_NUMBER && 1 || 2 }} - - name: Install stable toolchain + - name: Install Rust toolchain uses: actions-rs/toolchain@v1 with: profile: minimal @@ -85,6 +85,13 @@ jobs: target: wasm32-unknown-unknown override: true + - name: Install .NET toolchain + uses: actions/setup-dotnet@v3 + with: + dotnet-version: "8.x" + env: + DOTNET_INSTALL_DIR: ~/.dotnet + - name: Build working-directory: crates/bench/ run: | @@ -114,7 +121,7 @@ jobs: rm -rf .spacetime cargo bench --bench generic -- --save-baseline "$BASELINE_NAME" "$BENCH_FILTER" # sticker price benchmark - cargo bench --bench generic -- --save-baseline "$BASELINE_NAME" 'stdb_module/disk/update_bulk' + cargo bench --bench generic -- --save-baseline "$BASELINE_NAME" 'stdb_module/.*/disk/update_bulk' cargo bench --bench special -- --save-baseline "$BASELINE_NAME" cargo run --bin summarize pack "$BASELINE_NAME" popd @@ -192,7 +199,7 @@ jobs: - name: Install valgrind & iai-callgrind-runner run: | apt-get update - apt-get install -y valgrind protobuf-compiler bash sudo curl gh + apt-get install -y valgrind protobuf-compiler bash sudo curl gh cargo install --git https://github.com/clockworklabs/iai-callgrind.git --branch main iai-callgrind-runner git config --global --add safe.directory /__w/SpacetimeDB/SpacetimeDB @@ -343,4 +350,3 @@ jobs: echo "Letting anybody touch our git repo, in order to avoid breaking other jobs" echo "This is necessary because we are running as root inside a docker image" chmod -R a+rw . - diff --git a/Cargo.lock b/Cargo.lock index 24814ad21a4..7c5f712cf66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4696,6 +4696,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "serial_test", "spacetimedb-client-api", "spacetimedb-core", "spacetimedb-data-structures", diff --git a/crates/bench/Cargo.toml b/crates/bench/Cargo.toml index caa9f37aa7a..53bc3f3298e 100644 --- a/crates/bench/Cargo.toml +++ b/crates/bench/Cargo.toml @@ -54,6 +54,7 @@ regex.workspace = true rusqlite.workspace = true serde.workspace = true serde_json.workspace = true +serial_test.workspace = true tempdir.workspace = true tokio.workspace = true tracing-subscriber.workspace = true diff --git a/crates/bench/benches/generic.rs b/crates/bench/benches/generic.rs index eff874c3004..c35a21130c8 100644 --- a/crates/bench/benches/generic.rs +++ b/crates/bench/benches/generic.rs @@ -12,6 +12,7 @@ use spacetimedb_bench::{ }; use spacetimedb_lib::sats::AlgebraicType; use spacetimedb_primitives::ColId; +use spacetimedb_testing::modules::{Csharp, Rust}; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; @@ -23,11 +24,13 @@ lazy_static! { fn criterion_benchmark(c: &mut Criterion) { bench_suite::(c, true).unwrap(); bench_suite::(c, true).unwrap(); - bench_suite::(c, true).unwrap(); + bench_suite::>(c, true).unwrap(); + bench_suite::>(c, true).unwrap(); bench_suite::(c, false).unwrap(); bench_suite::(c, false).unwrap(); - bench_suite::(c, false).unwrap(); + bench_suite::>(c, false).unwrap(); + bench_suite::>(c, false).unwrap(); } #[inline(never)] diff --git a/crates/bench/benches/special.rs b/crates/bench/benches/special.rs index 54251a400f3..c62e4f709e0 100644 --- a/crates/bench/benches/special.rs +++ b/crates/bench/benches/special.rs @@ -1,5 +1,5 @@ use criterion::async_executor::AsyncExecutor; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion, SamplingMode}; use mimalloc::MiMalloc; use spacetimedb_bench::{ database::BenchDatabase, @@ -9,6 +9,7 @@ use spacetimedb_bench::{ use spacetimedb_lib::sats::{self, bsatn}; use spacetimedb_lib::{bsatn::ToBsatn as _, ProductValue}; use spacetimedb_schema::schema::TableSchema; +use spacetimedb_testing::modules::{Csharp, ModuleLanguage, Rust}; use std::sync::Arc; use std::sync::OnceLock; @@ -20,14 +21,19 @@ fn criterion_benchmark(c: &mut Criterion) { serialize_benchmarks::(c); serialize_benchmarks::(c); - let db = SpacetimeModule::build(true).unwrap(); + custom_benchmarks::(c); + custom_benchmarks::(c); +} + +fn custom_benchmarks(c: &mut Criterion) { + let db = SpacetimeModule::::build(true).unwrap(); custom_module_benchmarks(&db, c); custom_db_benchmarks(&db, c); } -fn custom_module_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { - let mut group = c.benchmark_group("special/stdb_module"); +fn custom_module_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { + let mut group = c.benchmark_group(format!("special/{}", SpacetimeModule::::name())); let args = sats::product!["0".repeat(65536).into_boxed_str()]; group.bench_function("large_arguments/64KiB", |b| { @@ -44,10 +50,11 @@ fn custom_module_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { } } -fn custom_db_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { - let mut group = c.benchmark_group("special/db_game"); +fn custom_db_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { + let mut group = c.benchmark_group(format!("special/db_game/{}", L::NAME)); // This bench take long, so adjust for it group.sample_size(10); + group.sampling_mode(SamplingMode::Flat); let init_db: OnceLock<()> = OnceLock::new(); for n in [10, 100] { @@ -69,14 +76,14 @@ fn custom_db_benchmarks(m: &SpacetimeModule, c: &mut Criterion) { } let init_db: OnceLock<()> = OnceLock::new(); - for n in [500, 5_000] { + for n in [10, 100] { let args = sats::product![n]; group.bench_function(format!("ia_loop/load={n}"), |b| { // Initialize outside the benchmark so the db is seed once, to avoid `unique` constraints violations init_db.get_or_init(|| { m.block_on(async { m.module - .call_reducer_binary("init_game_ia_loop", &sats::product![5_000]) + .call_reducer_binary("init_game_ia_loop", &sats::product![500]) .await .unwrap(); }) diff --git a/crates/bench/src/database.rs b/crates/bench/src/database.rs index 04bc1d9d4ea..21e1e9c5d28 100644 --- a/crates/bench/src/database.rs +++ b/crates/bench/src/database.rs @@ -10,7 +10,7 @@ use crate::ResultBench; /// /// Not all benchmarks have to go through this trait. pub trait BenchDatabase: Sized { - fn name() -> &'static str; + fn name() -> String; type TableId: Clone + 'static; diff --git a/crates/bench/src/lib.rs b/crates/bench/src/lib.rs index f5b5dd32727..ce56b2e12e8 100644 --- a/crates/bench/src/lib.rs +++ b/crates/bench/src/lib.rs @@ -16,6 +16,8 @@ mod tests { sqlite::SQLite, ResultBench, }; + use serial_test::serial; + use spacetimedb_testing::modules::{Csharp, Rust}; use std::{io, path::Path, sync::Once}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -101,30 +103,37 @@ mod tests { Ok(()) } + fn test_basic_invariants() -> ResultBench<()> { + basic_invariants::(IndexStrategy::Unique0, true)?; + basic_invariants::(IndexStrategy::Unique0, true)?; + basic_invariants::(IndexStrategy::BTreeEachColumn, true)?; + basic_invariants::(IndexStrategy::BTreeEachColumn, true)?; + Ok(()) + } + #[test] - fn test_basic_invariants_sqlite() { - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); + fn test_basic_invariants_sqlite() -> ResultBench<()> { + test_basic_invariants::() } #[test] - fn test_basic_invariants_spacetime_raw() { - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); + fn test_basic_invariants_spacetime_raw() -> ResultBench<()> { + test_basic_invariants::() + } + + // note: there can only be one #[test] invoking spacetime module stuff. + // #[test]s run concurrently and they fight over lockfiles. + // so, run the sub-tests here in sequence. + + #[test] + #[serial] + fn test_basic_invariants_spacetime_module_rust() -> ResultBench<()> { + test_basic_invariants::>() } #[test] - fn test_basic_invariants_spacetime_module() { - // note: there can only be one #[test] invoking spacetime module stuff. - // #[test]s run concurrently and they fight over lockfiles. - // so, run the sub-tests here in sequence. - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::Unique0, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); - basic_invariants::(IndexStrategy::BTreeEachColumn, true).unwrap(); + #[serial] + fn test_basic_invariants_spacetime_module_csharp() -> ResultBench<()> { + test_basic_invariants::>() } } diff --git a/crates/bench/src/spacetime_module.rs b/crates/bench/src/spacetime_module.rs index 0e18b9fb03d..d2284888255 100644 --- a/crates/bench/src/spacetime_module.rs +++ b/crates/bench/src/spacetime_module.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::{marker::PhantomData, path::Path}; use spacetimedb::db::{Config, Storage}; use spacetimedb_lib::{ @@ -7,7 +7,7 @@ use spacetimedb_lib::{ }; use spacetimedb_paths::RootDir; use spacetimedb_primitives::ColId; -use spacetimedb_testing::modules::{start_runtime, CompilationMode, CompiledModule, LoggerRecord, ModuleHandle}; +use spacetimedb_testing::modules::{start_runtime, LoggerRecord, ModuleHandle, ModuleLanguage}; use tokio::runtime::Runtime; use crate::{ @@ -17,23 +17,6 @@ use crate::{ }; use criterion::async_executor::AsyncExecutor; -lazy_static::lazy_static! { - pub static ref BENCHMARKS_MODULE: CompiledModule = { - if std::env::var_os("STDB_BENCH_CS").is_some() { - CompiledModule::compile("benchmarks-cs", CompilationMode::Release) - } else { - // Temporarily add CARGO_TARGET_DIR override to avoid conflicts with main target dir. - // Otherwise for some reason Cargo will mark all dependencies with build scripts as - // fresh - but only if running benchmarks (if modules are built in release mode). - // See https://github.com/clockworklabs/SpacetimeDB/issues/401. - std::env::set_var("CARGO_TARGET_DIR", concat!(env!("CARGO_MANIFEST_DIR"), "/target")); - let module = CompiledModule::compile("benchmarks", CompilationMode::Release); - std::env::remove_var("CARGO_TARGET_DIR"); - module - } - }; -} - /// A benchmark backend that invokes a spacetime module. /// /// This is tightly tied to the file `modules/benchmarks/src/lib.rs`; @@ -42,26 +25,27 @@ lazy_static::lazy_static! { /// /// See the doc comment there for information on the formatting expected for /// table and reducer names. -pub struct SpacetimeModule { +pub struct SpacetimeModule { // Module must be dropped BEFORE runtime otherwise there is a deadlock! // In Rust, struct fields are guaranteed to drop in declaration order, so don't reorder this field. pub module: ModuleHandle, runtime: Runtime, + lang: PhantomData, } // Note: we use block_on for the methods here. It adds about 70ns of overhead. // This isn't currently a problem. Overhead to call an empty reducer is currently 20_000 ns. -impl AsyncExecutor for &SpacetimeModule { +impl AsyncExecutor for &SpacetimeModule { fn block_on(&self, future: impl std::future::Future) -> T { self.runtime.block_on(future) } } // It's easier to do it this way because async traits are a mess. -impl BenchDatabase for SpacetimeModule { - fn name() -> &'static str { - "stdb_module" +impl BenchDatabase for SpacetimeModule { + fn name() -> String { + format!("stdb_module/{}", L::NAME) } type TableId = TableId; @@ -81,7 +65,7 @@ impl BenchDatabase for SpacetimeModule { // It's fine that we're constructing this path ad-hoc, as it's just // a path location for tests, not part of our stable directory structure. let path = RootDir(Path::new(env!("CARGO_MANIFEST_DIR")).join(".spacetime")); - BENCHMARKS_MODULE.load_module(config, Some(&path)).await + L::get_module().load_module(config, Some(&path)).await }); for table in module.client.module.info.module_def.tables() { @@ -90,7 +74,11 @@ impl BenchDatabase for SpacetimeModule { for reducer in module.client.module.info.module_def.reducers() { log::trace!("SPACETIME_MODULE: LOADED REDUCER: {:?}", reducer); } - Ok(SpacetimeModule { runtime, module }) + Ok(SpacetimeModule { + runtime, + module, + lang: PhantomData, + }) } fn create_table( @@ -105,7 +93,7 @@ impl BenchDatabase for SpacetimeModule { } fn clear_table(&mut self, table_id: &Self::TableId) -> ResultBench<()> { - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; runtime.block_on(async move { // FIXME: this doesn't work. delete is unimplemented!! /* @@ -122,7 +110,7 @@ impl BenchDatabase for SpacetimeModule { // message in the log. // This implementation will not work if other people are concurrently interacting with our module. fn count_table(&mut self, table_id: &Self::TableId) -> ResultBench { - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; let count = runtime.block_on(async move { let name = format!("count_{}", table_id.snake_case); @@ -140,7 +128,7 @@ impl BenchDatabase for SpacetimeModule { } fn empty_transaction(&mut self) -> ResultBench<()> { - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; runtime.block_on(async move { module.call_reducer_binary("empty", &[].into()).await?; @@ -151,7 +139,7 @@ impl BenchDatabase for SpacetimeModule { fn insert_bulk(&mut self, table_id: &Self::TableId, rows: Vec) -> ResultBench<()> { let rows = rows.into_iter().map(|row| row.into_product_value()).collect(); let args = product![ArrayValue::Product(rows)]; - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; let reducer_name = format!("insert_bulk_{}", table_id.snake_case); runtime.block_on(async move { @@ -162,7 +150,7 @@ impl BenchDatabase for SpacetimeModule { fn update_bulk(&mut self, table_id: &Self::TableId, row_count: u32) -> ResultBench<()> { let args = product![row_count]; - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; let reducer_name = format!("update_bulk_{}", table_id.snake_case); runtime.block_on(async move { @@ -172,7 +160,7 @@ impl BenchDatabase for SpacetimeModule { } fn iterate(&mut self, table_id: &Self::TableId) -> ResultBench<()> { - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; let reducer_name = format!("iterate_{}", table_id.snake_case); runtime.block_on(async move { @@ -187,7 +175,7 @@ impl BenchDatabase for SpacetimeModule { col_id: impl Into, value: AlgebraicValue, ) -> ResultBench<()> { - let SpacetimeModule { runtime, module } = self; + let SpacetimeModule { runtime, module, .. } = self; let product_type = T::product_type(); let column_name = product_type.elements[col_id.into().idx()].name.as_ref().unwrap(); diff --git a/crates/bench/src/spacetime_raw.rs b/crates/bench/src/spacetime_raw.rs index 65b0f56ce61..2b63dbf2a2e 100644 --- a/crates/bench/src/spacetime_raw.rs +++ b/crates/bench/src/spacetime_raw.rs @@ -21,8 +21,8 @@ pub struct SpacetimeRaw { } impl BenchDatabase for SpacetimeRaw { - fn name() -> &'static str { - "stdb_raw" + fn name() -> String { + "stdb_raw".to_owned() } type TableId = TableId; diff --git a/crates/bench/src/sqlite.rs b/crates/bench/src/sqlite.rs index 15a42e28a30..b51f5958812 100644 --- a/crates/bench/src/sqlite.rs +++ b/crates/bench/src/sqlite.rs @@ -23,8 +23,8 @@ pub struct SQLite { } impl BenchDatabase for SQLite { - fn name() -> &'static str { - "sqlite" + fn name() -> String { + "sqlite".to_owned() } fn build(in_memory: bool) -> ResultBench diff --git a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets index 34a49f45fbb..e8fa126158a 100644 --- a/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets +++ b/crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets @@ -3,16 +3,23 @@ + + + + + + + diff --git a/crates/testing/src/modules.rs b/crates/testing/src/modules.rs index 1b47733384b..a6cb57c679f 100644 --- a/crates/testing/src/modules.rs +++ b/crates/testing/src/modules.rs @@ -10,14 +10,14 @@ use spacetimedb::messages::control_db::HostType; use spacetimedb::Identity; use spacetimedb_client_api::auth::SpacetimeAuth; use spacetimedb_client_api::routes::subscribe::generate_random_address; -use spacetimedb_lib::ser::serde::SerializeWrapper; use spacetimedb_paths::{RootDir, SpacetimePaths}; use tokio::runtime::{Builder, Runtime}; use spacetimedb::client::{ClientActorId, ClientConfig, ClientConnection, DataMessage}; use spacetimedb::database_logger::DatabaseLogger; use spacetimedb::db::{Config, Storage}; -use spacetimedb::messages::websocket as ws; +use spacetimedb::host::ReducerArgs; +use spacetimedb::messages::websocket::CallReducerFlags; use spacetimedb_client_api::{ControlStateReadAccess, ControlStateWriteAccess, DatabaseDef, NodeDelegate}; use spacetimedb_lib::{bsatn, sats}; @@ -52,26 +52,29 @@ pub struct ModuleHandle { } impl ModuleHandle { - fn call_reducer_msg(reducer: &str, args: Args) -> ws::ClientMessage { - ws::ClientMessage::CallReducer(ws::CallReducer { - reducer: reducer.into(), - args, - request_id: 0, - flags: ws::CallReducerFlags::FullUpdate, - }) + async fn call_reducer(&self, reducer: &str, args: ReducerArgs) -> anyhow::Result<()> { + let result = self + .client + .call_reducer(reducer, args, 0, Instant::now(), CallReducerFlags::FullUpdate) + .await; + let result = match result { + Ok(result) => result.into(), + Err(err) => Err(err.into()), + }; + match result { + Ok(()) => Ok(()), + Err(err) => Err(err.context(format!("Logs:\n{}", self.read_log(None).await))), + } } pub async fn call_reducer_json(&self, reducer: &str, args: &sats::ProductValue) -> anyhow::Result<()> { let args = serde_json::to_string(&args).unwrap(); - let message = Self::call_reducer_msg(reducer, args); - self.send(serde_json::to_string(&SerializeWrapper::new(message)).unwrap()) - .await + self.call_reducer(reducer, ReducerArgs::Json(args.into())).await } pub async fn call_reducer_binary(&self, reducer: &str, args: &sats::ProductValue) -> anyhow::Result<()> { let args = bsatn::to_vec(&args).unwrap(); - let message = Self::call_reducer_msg(reducer, args); - self.send(bsatn::to_vec(&message).unwrap()).await + self.call_reducer(reducer, ReducerArgs::Bsatn(args.into())).await } pub async fn send(&self, message: impl Into) -> anyhow::Result<()> { @@ -228,3 +231,43 @@ pub struct LoggerRecord { pub line_number: Option, pub message: String, } + +const COMPILATION_MODE: CompilationMode = if cfg!(debug_assertions) { + CompilationMode::Debug +} else { + CompilationMode::Release +}; + +pub trait ModuleLanguage { + const NAME: &'static str; + + fn get_module() -> &'static CompiledModule; +} + +pub struct Csharp; + +impl ModuleLanguage for Csharp { + const NAME: &'static str = "csharp"; + + fn get_module() -> &'static CompiledModule { + lazy_static::lazy_static! { + pub static ref MODULE: CompiledModule = CompiledModule::compile("benchmarks-cs", COMPILATION_MODE); + } + + &MODULE + } +} + +pub struct Rust; + +impl ModuleLanguage for Rust { + const NAME: &'static str = "rust"; + + fn get_module() -> &'static CompiledModule { + lazy_static::lazy_static! { + pub static ref MODULE: CompiledModule = CompiledModule::compile("benchmarks", COMPILATION_MODE); + } + + &MODULE + } +} diff --git a/crates/testing/tests/standalone_integration_test.rs b/crates/testing/tests/standalone_integration_test.rs index a1fcb1bdda9..fe2acd229ec 100644 --- a/crates/testing/tests/standalone_integration_test.rs +++ b/crates/testing/tests/standalone_integration_test.rs @@ -1,7 +1,8 @@ use serial_test::serial; use spacetimedb_lib::sats::{product, AlgebraicValue}; use spacetimedb_testing::modules::{ - CompilationMode, CompiledModule, LogLevel, LoggerRecord, ModuleHandle, DEFAULT_CONFIG, IN_MEMORY_CONFIG, + CompilationMode, CompiledModule, Csharp, LogLevel, LoggerRecord, ModuleHandle, ModuleLanguage, Rust, + DEFAULT_CONFIG, IN_MEMORY_CONFIG, }; use std::{ future::Future, @@ -99,10 +100,10 @@ fn test_calling_a_reducer_with_private_table() { DEFAULT_CONFIG, |module| async move { module - .call_reducer_json("add_private", &product!["Tyrion"]) + .call_reducer_binary("add_private", &product!["Tyrion"]) .await .unwrap(); - module.call_reducer_json("query_private", &product![]).await.unwrap(); + module.call_reducer_binary("query_private", &product![]).await.unwrap(); let logs = read_logs(&module) .await @@ -216,25 +217,28 @@ fn test_index_scans() { |module| async move { let no_args = &product![]; - module.call_reducer_json("load_location_table", no_args).await.unwrap(); + module + .call_reducer_binary("load_location_table", no_args) + .await + .unwrap(); module - .call_reducer_json("test_index_scan_on_id", no_args) + .call_reducer_binary("test_index_scan_on_id", no_args) .await .unwrap(); module - .call_reducer_json("test_index_scan_on_chunk", no_args) + .call_reducer_binary("test_index_scan_on_chunk", no_args) .await .unwrap(); module - .call_reducer_json("test_index_scan_on_x_z_dimension", no_args) + .call_reducer_binary("test_index_scan_on_x_z_dimension", no_args) .await .unwrap(); module - .call_reducer_json("test_index_scan_on_x_z", no_args) + .call_reducer_binary("test_index_scan_on_x_z", no_args) .await .unwrap(); @@ -254,12 +258,10 @@ fn test_index_scans() { } async fn bench_call<'a>(module: &ModuleHandle, call: &str, count: &u32) -> Duration { - let json = - format!(r#"{{"CallReducer": {{"reducer": "{call}", "args": "[{count}]", "request_id": 0, "flags": 0 }}}}"#); - let now = Instant::now(); - module.send(json).await.unwrap(); + // Note: using JSON variant because some functions accept u64 instead, so we rely on JSON's dynamic typing. + module.call_reducer_json(call, &product![*count]).await.unwrap(); now.elapsed() } @@ -280,42 +282,59 @@ async fn _run_bench_db(module: ModuleHandle, benches: &[(&str, u32, &str)]) { } } +fn test_calling_bench_db_circles() { + L::get_module().with_module_async(DEFAULT_CONFIG, |module| async move { + #[rustfmt::skip] + let benches = [ + ("insert_bulk_food", 50, "INSERT FOOD: 50"), + ("insert_bulk_entity", 50, "INSERT ENTITY: 50"), + ("insert_bulk_circle", 500, "INSERT CIRCLE: 500"), + ("cross_join_circle_food", 50 * 500, "CROSS JOIN CIRCLE FOOD: 25000, processed: 2500"), + ("cross_join_all", 50 * 50 * 500, "CROSS JOIN ALL: 1250000, processed: 1250000"), + ]; + + _run_bench_db(module, &benches).await + }); +} + #[test] #[serial] -fn test_calling_bench_db_circles() { - CompiledModule::compile("benchmarks", CompilationMode::Release).with_module_async( - DEFAULT_CONFIG, - |module| async move { - #[rustfmt::skip] - let benches = [ - ("insert_bulk_food", 50, "INSERT FOOD: 50"), - ("insert_bulk_entity", 50, "INSERT ENTITY: 50"), - ("insert_bulk_circle", 500, "INSERT CIRCLE: 500"), - ("cross_join_circle_food", 50 * 500, "CROSS JOIN CIRCLE FOOD: 25000, processed: 2500"), - ("cross_join_all", 50 * 50 * 500, "CROSS JOIN ALL: 1250000, processed: 1250000"), - ]; - _run_bench_db(module, &benches).await - }, - ); +fn test_calling_bench_db_circles_rust() { + test_calling_bench_db_circles::(); } #[test] #[serial] -fn test_calling_bench_db_ia_loop() { - CompiledModule::compile("benchmarks", CompilationMode::Release).with_module_async( - DEFAULT_CONFIG, - |module| async move { - #[rustfmt::skip] - let benches = [ - ("insert_bulk_position", 20_000, "INSERT POSITION: 20000"), - ("insert_bulk_velocity", 10_000, "INSERT VELOCITY: 10000"), - ("update_position_all", 20_000, "UPDATE POSITION ALL: 20000, processed: 20000"), - ("update_position_with_velocity", 10_000, "UPDATE POSITION BY VELOCITY: 10000, processed: 10000"), - ("insert_world", 5_000, "INSERT WORLD PLAYERS: 5000"), - ("game_loop_enemy_ia", 5_000, "ENEMY IA LOOP PLAYERS: 5000, processed: 5000"), - ]; - - _run_bench_db(module, &benches).await - }, - ); +fn test_calling_bench_db_circles_csharp() { + test_calling_bench_db_circles::(); +} + +fn test_calling_bench_db_ia_loop() { + L::get_module().with_module_async(DEFAULT_CONFIG, |module| async move { + #[rustfmt::skip] + let benches = [ + ("insert_bulk_position", 20_000, "INSERT POSITION: 20000"), + ("insert_bulk_velocity", 10_000, "INSERT VELOCITY: 10000"), + ("update_position_all", 20_000, "UPDATE POSITION ALL: 20000, processed: 20000"), + ("update_position_with_velocity", 10_000, "UPDATE POSITION BY VELOCITY: 10000, processed: 10000"), + ("insert_world", 5_000, "INSERT WORLD PLAYERS: 5000"), + // Note: we set lower amount of ia loop players here than in benchmarks. + // Otherwise tests will take forever because they are built in debug mode. + ("game_loop_enemy_ia", 100, "ENEMY IA LOOP PLAYERS: 100, processed: 5000"), + ]; + + _run_bench_db(module, &benches).await + }); +} + +#[test] +#[serial] +fn test_calling_bench_db_ia_loop_rust() { + test_calling_bench_db_ia_loop::(); +} + +#[test] +#[serial] +fn test_calling_bench_db_ia_loop_csharp() { + test_calling_bench_db_ia_loop::(); } diff --git a/modules/benchmarks-cs/ia_loop.cs b/modules/benchmarks-cs/ia_loop.cs index 268046d5347..1ae204bfffa 100644 --- a/modules/benchmarks-cs/ia_loop.cs +++ b/modules/benchmarks-cs/ia_loop.cs @@ -134,7 +134,7 @@ int roaming_distance } [SpacetimeDB.Reducer] - public static void InsertBulkPosition(ReducerContext ctx, uint count) + public static void insert_bulk_position(ReducerContext ctx, uint count) { for (uint id = 0; id < count; id++) { @@ -144,7 +144,7 @@ public static void InsertBulkPosition(ReducerContext ctx, uint count) } [SpacetimeDB.Reducer] - public static void InsertBulkVelocity(ReducerContext ctx, uint count) + public static void insert_bulk_velocity(ReducerContext ctx, uint count) { for (uint id = 0; id < count; id++) { @@ -359,8 +359,8 @@ public static void init_game_ia_loop(ReducerContext ctx, uint initial_load) { Load load = new(initial_load); - InsertBulkPosition(ctx, load.biggest_table); - InsertBulkVelocity(ctx, load.big_table); + insert_bulk_position(ctx, load.biggest_table); + insert_bulk_velocity(ctx, load.big_table); update_position_all(ctx, load.biggest_table); update_position_with_velocity(ctx, load.big_table);