Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Benchmark contract state insertions with DB vs. DB transactions #1230

Merged
merged 22 commits into from
Jul 4, 2023
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 144 additions & 11 deletions benches/benches/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use criterion::{
BenchmarkGroup,
Criterion,
};
use fuel_core::database::vm_database::VmDatabase;
use fuel_core::database::{
vm_database::VmDatabase,
Database,
};
use fuel_core_storage::InterpreterStorage;
use fuel_core_types::{
blockchain::header::GeneratedConsensusFields,
Expand All @@ -23,7 +26,7 @@ use std::{
time::Duration,
};

fn setup(db: &mut VmDatabase, contract: &ContractId, n: usize) {
fn setup(db: &mut Database, contract: &ContractId, n: usize) {
let mut rng_keys = thread_rng();
let gen_keys = || -> Bytes32 { rng_keys.gen() };
let state_keys = iter::repeat_with(gen_keys).take(n);
Expand All @@ -35,12 +38,11 @@ fn setup(db: &mut VmDatabase, contract: &ContractId, n: usize) {
// State key-values
let state_key_values = state_keys.zip(state_values);

db.database_mut()
.init_contract_state(contract, state_key_values)
db.init_contract_state(contract, state_key_values)
.expect("Failed to initialize contract state");
}

fn state_single_contract(c: &mut Criterion) {
fn insert_state_single_contract_database(c: &mut Criterion) {
let mut rng = StdRng::seed_from_u64(0xF00DF00D);
let state: Bytes32 = rng.gen();
let value: Bytes32 = rng.gen();
Expand All @@ -49,7 +51,7 @@ fn state_single_contract(c: &mut Criterion) {
group.bench_function(name, |b| {
let mut db = VmDatabase::default();
let contract: ContractId = rng.gen();
setup(&mut db, &contract, n);
setup(db.database_mut(), &contract, n);
let outer = db.database_mut().transaction();
b.iter_custom(|iters| {
let mut elapsed_time = Duration::default();
Expand All @@ -71,7 +73,7 @@ fn state_single_contract(c: &mut Criterion) {
});
};

let mut group = c.benchmark_group("state single contract");
let mut group = c.benchmark_group("insert state single contract database");

bench_state(&mut group, "insert state with 0 preexisting entries", 0);
bench_state(&mut group, "insert state with 1 preexisting entry", 1);
Expand Down Expand Up @@ -101,7 +103,68 @@ fn state_single_contract(c: &mut Criterion) {
group.finish();
}

fn state_multiple_contracts(c: &mut Criterion) {
fn insert_state_single_contract_transaction(c: &mut Criterion) {
let mut rng = StdRng::seed_from_u64(0xF00DF00D);
let state: Bytes32 = rng.gen();
let value: Bytes32 = rng.gen();

let mut bench_state = |group: &mut BenchmarkGroup<WallTime>, name: &str, n: usize| {
group.bench_function(name, |b| {
let mut db = VmDatabase::default();
let contract: ContractId = rng.gen();
let mut outer = db.database_mut().transaction();
setup(outer.as_mut(), &contract, n);
b.iter_custom(|iters| {
let mut elapsed_time = Duration::default();
for _ in 0..iters {
let mut inner = outer.transaction();
let mut inner_db = VmDatabase::new::<GeneratedConsensusFields>(
Copy link
Contributor Author

@bvrooman bvrooman Jun 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally, I was exploring if I could implement From<DatabaseTransaction> for VmDatabase to simplify this logic. The implementation meant using the default for GeneratedConsensusFields, but that is only available under the test or test-helpers configuration. During benchmarking, neither of this flags are automatically available, and I did not think it would be valuable to require users to add a test configuration to their benchmarking at this time.

inner.as_mut().clone(),
&Default::default(),
Default::default(),
);
let start = std::time::Instant::now();
inner_db
.merkle_contract_state_insert(&contract, &state, &value)
.expect("failed to insert state into transaction");
elapsed_time += start.elapsed();
}
elapsed_time
});
});
};

let mut group = c.benchmark_group("insert state single contract transaction");

bench_state(&mut group, "insert state with 0 preexisting entries", 0);
bench_state(&mut group, "insert state with 1 preexisting entry", 1);
bench_state(&mut group, "insert state with 10 preexisting entries", 10);
bench_state(&mut group, "insert state with 100 preexisting entries", 100);
bench_state(
&mut group,
"insert state with 1,000 preexisting entries",
1_000,
);
bench_state(
&mut group,
"insert state with 10,000 preexisting entries",
10_000,
);
bench_state(
&mut group,
"insert state with 100,000 preexisting entries",
100_000,
);
bench_state(
&mut group,
"insert state with 1,000,000 preexisting entries",
1_000_000,
);

group.finish();
}

fn insert_state_multiple_contracts_database(c: &mut Criterion) {
let mut rng = StdRng::seed_from_u64(0xF00DF00D);
let state: Bytes32 = rng.gen();
let value: Bytes32 = rng.gen();
Expand All @@ -111,7 +174,7 @@ fn state_multiple_contracts(c: &mut Criterion) {
let mut db = VmDatabase::default();
for _ in 0..n {
let contract: ContractId = rng.gen();
setup(&mut db, &contract, 1);
setup(db.database_mut(), &contract, 1);
}
let outer = db.database_mut().transaction();
b.iter_custom(|iters| {
Expand All @@ -135,7 +198,71 @@ fn state_multiple_contracts(c: &mut Criterion) {
});
};

let mut group = c.benchmark_group("state multiple contracts");
let mut group = c.benchmark_group("insert state multiple contracts database");

bench_state(&mut group, "insert state with 0 preexisting entries", 0);
bench_state(&mut group, "insert state with 1 preexisting entry", 1);
bench_state(&mut group, "insert state with 10 preexisting entries", 10);
bench_state(&mut group, "insert state with 100 preexisting entries", 100);
bench_state(
&mut group,
"insert state with 1,000 preexisting entries",
1_000,
);
bench_state(
&mut group,
"insert state with 10,000 preexisting entries",
10_000,
);
bench_state(
&mut group,
"insert state with 100,000 preexisting entries",
100_000,
);
bench_state(
&mut group,
"insert state with 1,000,000 preexisting entries",
1_000_000,
);

group.finish();
}

fn insert_state_multiple_contracts_transaction(c: &mut Criterion) {
let mut rng = StdRng::seed_from_u64(0xF00DF00D);
let state: Bytes32 = rng.gen();
let value: Bytes32 = rng.gen();

let mut bench_state = |group: &mut BenchmarkGroup<WallTime>, name: &str, n: usize| {
group.bench_function(name, |b| {
let mut db = VmDatabase::default();
let mut outer = db.database_mut().transaction();
for _ in 0..n {
let contract: ContractId = rng.gen();
setup(outer.as_mut(), &contract, 1);
}
b.iter_custom(|iters| {
let mut elapsed_time = Duration::default();
let contract: ContractId = rng.gen();
for _ in 0..iters {
let mut inner = outer.transaction();
let mut inner_db = VmDatabase::new::<GeneratedConsensusFields>(
inner.as_mut().clone(),
&Default::default(),
Default::default(),
);
let start = std::time::Instant::now();
inner_db
.merkle_contract_state_insert(&contract, &state, &value)
.expect("failed to insert state into transaction");
elapsed_time += start.elapsed();
}
elapsed_time
})
});
};

let mut group = c.benchmark_group("insert state multiple contracts transaction");

bench_state(&mut group, "insert state with 0 preexisting entries", 0);
bench_state(&mut group, "insert state with 1 preexisting entry", 1);
Expand Down Expand Up @@ -165,5 +292,11 @@ fn state_multiple_contracts(c: &mut Criterion) {
group.finish();
}

criterion_group!(benches, state_single_contract, state_multiple_contracts);
criterion_group!(
benches,
insert_state_single_contract_database,
insert_state_single_contract_transaction,
insert_state_multiple_contracts_database,
insert_state_multiple_contracts_transaction
);
criterion_main!(benches);
Loading