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

Reuse VM memory across executions #1888

Merged
merged 29 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
81dc78a
Reuse VM memory across executions
Dentosal May 8, 2024
42105ce
Add changelog entry
Dentosal May 8, 2024
e14cf0b
Merge branch 'master' into dento/reuse-vm-memory
Dentosal May 8, 2024
5caec42
Switch to a unified pool instead of per-thread one
Dentosal May 9, 2024
6340785
Move VmPool to fuel-vm, use it for predicates as well
Dentosal May 10, 2024
22fa926
Cleanup
Dentosal May 10, 2024
8c276e9
Cleanup
Dentosal May 10, 2024
0b11719
Fix benches
Dentosal May 10, 2024
4c6f29b
Add changes from the latest fuel-vm side update
Dentosal May 13, 2024
22f3ba4
Match fuel-vm changes
Dentosal May 14, 2024
4f9340c
Merge branch 'master' into dento/reuse-vm-memory
Dentosal May 14, 2024
57d2049
cargo sort
Dentosal May 14, 2024
0e41a28
Merge branch 'refs/heads/master' into dento/reuse-vm-memory
xgreenx Jun 3, 2024
a762483
Use `fuel-vm 0.51.0`
xgreenx Jun 3, 2024
131a91e
Merge branch 'master' into dento/reuse-vm-memory
xgreenx Jun 3, 2024
98c7495
Make clippy happy
xgreenx Jun 3, 2024
395077b
Fix CI
xgreenx Jun 3, 2024
36fa8be
Fix CI
xgreenx Jun 3, 2024
3baea26
Fix CI
xgreenx Jun 3, 2024
b13578f
Fixed VM initialization benchmark
xgreenx Jun 3, 2024
eb65aba
Merge branch 'master' into dento/reuse-vm-memory
xgreenx Jun 3, 2024
5196bab
Use release 0.51
xgreenx Jun 3, 2024
2e4bc5b
Merge remote-tracking branch 'origin/dento/reuse-vm-memory' into dent…
xgreenx Jun 3, 2024
c2034bb
Make clippy happy
xgreenx Jun 3, 2024
ec2a65b
Fixed becnhmark for aloc opcode
xgreenx Jun 3, 2024
fc15915
Fixed becnhmark for aloc opcode
xgreenx Jun 3, 2024
6000f11
Not include cloning of memory into the benchamrk results
xgreenx Jun 3, 2024
56915e7
Return back old benchmark
xgreenx Jun 3, 2024
8680666
Merge branch 'master' into dento/reuse-vm-memory
xgreenx Jun 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Removed
- [#1913](https://github.com/FuelLabs/fuel-core/pull/1913): Removed dead code from the project.

### Changed
- [#1888](https://github.com/FuelLabs/fuel-core/pull/1888): optimization: Reuse VM memory across executions.

#### Breaking
- [#1888](https://github.com/FuelLabs/fuel-core/pull/1888): Upgraded `fuel-vm` to `0.51.0`. See [release](https://github.com/FuelLabs/fuel-vm/releases/tag/v0.51.0) for more information.

### Fixed
- [#1914](https://github.com/FuelLabs/fuel-core/pull/1914): Fixed halting of the node during synchronization in PoA service.

Expand Down
34 changes: 17 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fuel-core-wasm-executor = { version = "0.27.0", path = "./crates/services/upgrad
fuel-core-xtask = { version = "0.0.0", path = "./xtask" }

# Fuel dependencies
fuel-vm-private = { version = "0.50.0", package = "fuel-vm", default-features = false }
fuel-vm-private = { version = "0.51.0", package = "fuel-vm", default-features = false }

# Common dependencies
anyhow = "1.0"
Expand Down
8 changes: 6 additions & 2 deletions benches/benches/block_target_gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ use fuel_core_types::{
fuel_vm::{
checked_transaction::EstimatePredicates,
consts::WORD_SIZE,
interpreter::MemoryInstance,
},
services::executor::TransactionExecutionResult,
};
Expand Down Expand Up @@ -408,8 +409,11 @@ fn run_with_service_with_extra_inputs(
}
let mut tx = tx_builder.finalize_as_transaction();
let chain_config = shared.config.snapshot_reader.chain_config().clone();
tx.estimate_predicates(&chain_config.consensus_parameters.clone().into())
.unwrap();
tx.estimate_predicates(
&chain_config.consensus_parameters.clone().into(),
MemoryInstance::new(),
)
.unwrap();
async move {
let tx_id = tx.id(&chain_config.consensus_parameters.chain_id());

Expand Down
13 changes: 8 additions & 5 deletions benches/benches/transaction_throughput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ use fuel_core_types::{
Immediate12,
Immediate18,
},
fuel_vm::checked_transaction::{
CheckPredicateParams,
EstimatePredicates,
fuel_vm::{
checked_transaction::{
CheckPredicateParams,
EstimatePredicates,
},
interpreter::MemoryInstance,
},
};
use rand::{
Expand Down Expand Up @@ -209,7 +212,7 @@ fn predicate_transfers(c: &mut Criterion) {
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize();
tx.estimate_predicates(&CheckPredicateParams::default())
tx.estimate_predicates(&CheckPredicateParams::default(), MemoryInstance::new())
.expect("Predicate check failed");
tx
};
Expand Down Expand Up @@ -275,7 +278,7 @@ fn predicate_transfers_eck1(c: &mut Criterion) {
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize();
tx.estimate_predicates(&CheckPredicateParams::default())
tx.estimate_predicates(&CheckPredicateParams::default(), MemoryInstance::new())
.expect("Predicate check failed");
tx
};
Expand Down
16 changes: 13 additions & 3 deletions benches/benches/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,19 @@ where
let clock = quanta::Clock::new();

let original_db = vm.as_mut().database_mut().clone();
let original_memory = vm.memory().clone();
// During block production/validation for each state, which may affect the state of the database,
// we create a new storage transaction. The code here simulates the same behavior to have
// the same nesting level and the same performance.
let block_database_tx = original_db.clone().into_transaction();
let relayer_database_tx = block_database_tx.into_transaction();
let thread_database_tx = relayer_database_tx.into_transaction();
let tx_database_tx = thread_database_tx.into_transaction();
let tx_database_tx = relayer_database_tx.into_transaction();
let database = GenesisDatabase::new(Arc::new(tx_database_tx));
*vm.as_mut().database_mut() = database.into_transaction();

let mut total = core::time::Duration::ZERO;
for _ in 0..iters {
vm.memory_mut().clone_from(&original_memory);
let start = black_box(clock.raw());
match instruction {
Instruction::CALL(call) => {
Expand All @@ -71,6 +72,7 @@ where
vm.as_mut().database_mut().reset_changes();
}
*vm.as_mut().database_mut() = original_db;
*vm.memory_mut() = original_memory;
total
})
});
Expand All @@ -94,8 +96,16 @@ criterion_main!(benches);
// But first you need to comment `criterion_group` and `criterion_main` macros above.
//
// fn main() {
// let mut criterio = Criterion::default();
// let criterio = Criterion::default();
// let mut criterio = criterio.with_filter("vm_initialization");
// alu::run(&mut criterio);
// crypto::run(&mut criterio);
// flow::run(&mut criterio);
// mem::run(&mut criterio);
// blockchain::run(&mut criterio);
// contract_root(&mut criterio);
// state_root(&mut criterio);
// vm_initialization(&mut criterio);
// }
//
// #[test]
Expand Down
43 changes: 27 additions & 16 deletions benches/benches/vm_initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ use fuel_core_types::{
IntoChecked,
Ready,
},
constraints::reg_key::Reg,
constraints::reg_key::{
Reg,
RegMut,
},
consts::VM_MAX_RAM,
interpreter::NotSupportedEcal,
interpreter::{
MemoryInstance,
NotSupportedEcal,
},
Interpreter,
},
};
Expand Down Expand Up @@ -84,7 +90,7 @@ pub fn vm_initialization(c: &mut Criterion) {

// Increase the size of the script to measure the performance of the VM initialization
// with a large script. THe largest allowed script is 64 KB = 8 * 2^13 bytes.
const TX_SIZE_POWER_OF_TWO: usize = 13;
const TX_SIZE_POWER_OF_TWO: usize = 12;

for i in 5..=TX_SIZE_POWER_OF_TWO {
let size = 8 * (1 << i);
Expand All @@ -98,22 +104,29 @@ pub fn vm_initialization(c: &mut Criterion) {
let tx = tx.test_into_ready();

let name = format!("vm_initialization_with_tx_size_{}", tx_size);
let mut vm = black_box(
Interpreter::<_, _, Script, NotSupportedEcal>::with_memory_storage(),
);
group.throughput(Throughput::Bytes(tx_size as u64));
group.bench_function(name, |b| {
b.iter(|| {
unoptimized_vm_initialization_with_allocating_full_range_of_memory(&tx);
unoptimized_vm_initialization_with_allocating_full_range_of_memory(
&mut vm, &tx,
);
})
});
}

group.finish();
}

fn unoptimized_vm_initialization_with_allocating_full_range_of_memory(
#[allow(clippy::unit_arg)]
fn unoptimized_vm_initialization_with_allocating_full_range_of_memory<S>(
vm: &mut Interpreter<MemoryInstance, S, Script>,
ready_tx: &Ready<Script>,
) {
let vm = black_box(Interpreter::<_, Script, NotSupportedEcal>::with_memory_storage());

) where
S: InterpreterStorage,
{
black_box(initialize_vm_with_allocated_full_range_of_memory(
black_box(ready_tx.clone()),
vm,
Expand All @@ -122,9 +135,8 @@ fn unoptimized_vm_initialization_with_allocating_full_range_of_memory(

fn initialize_vm_with_allocated_full_range_of_memory<S>(
ready_tx: Ready<Script>,
mut vm: Interpreter<S, Script>,
) -> Interpreter<S, Script>
where
vm: &mut Interpreter<MemoryInstance, S, Script>,
) where
S: InterpreterStorage,
{
vm.init_script(ready_tx)
Expand All @@ -133,22 +145,21 @@ where
const POWER_OF_TWO_OF_HALF_VM: u64 = 25;
const VM_MEM_HALF: u64 = 1 << POWER_OF_TWO_OF_HALF_VM;
assert_eq!(VM_MEM_HALF, VM_MAX_RAM / 2);
let mut hp = VM_MAX_RAM;

for i in 0..=POWER_OF_TWO_OF_HALF_VM {
let stack = 1 << i;
let heap = VM_MAX_RAM - stack;
let heap = stack / 2;

vm.memory_mut()
.grow_stack(stack)
.expect("Should be able to grow stack");
vm.memory_mut()
.grow_heap(Reg::new(&0), heap)
.grow_heap_by(Reg::new(&0), RegMut::new(&mut hp), heap)
.expect("Should be able to grow heap");
}

vm.memory_mut()
.grow_heap(Reg::new(&0), 0)
.grow_heap_by(Reg::new(&0), RegMut::new(&mut hp), VM_MEM_HALF)
.expect("Should be able to grow heap");

vm
}
2 changes: 1 addition & 1 deletion benches/benches/vm_set/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ pub fn run(c: &mut Criterion) {
let coin_input = Input::coin_predicate(
Default::default(),
owner,
Word::MAX,
Word::MAX >> 2,
AssetId::zeroed(),
Default::default(),
Default::default(),
Expand Down
18 changes: 13 additions & 5 deletions benches/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use fuel_core_types::{
interpreter::{
diff,
InterpreterParams,
MemoryInstance,
ReceiptsCtx,
},
*,
Expand Down Expand Up @@ -107,7 +108,11 @@ pub struct VmBench {

#[derive(Debug, Clone)]
pub struct VmBenchPrepared {
pub vm: Interpreter<VmStorage<StorageTransaction<GenesisDatabase>>, Script>,
pub vm: Interpreter<
MemoryInstance,
VmStorage<StorageTransaction<GenesisDatabase>>,
Script,
>,
pub instruction: Instruction,
pub diff: diff::Diff<diff::InitialVmState>,
}
Expand Down Expand Up @@ -454,16 +459,19 @@ impl TryFrom<VmBench> for VmBenchPrepared {
.maturity(maturity)
.with_params(params.clone())
.finalize();
tx.estimate_predicates(&CheckPredicateParams::from(&params))
.unwrap();
tx.estimate_predicates(
&CheckPredicateParams::from(&params),
MemoryInstance::new(),
)
.unwrap();
let tx = tx.into_checked(height, &params).unwrap();
let interpreter_params = InterpreterParams::new(gas_price, &params);

let mut txtor = Transactor::new(db, interpreter_params);
let mut txtor = Transactor::new(MemoryInstance::new(), db, interpreter_params);

txtor.transact(tx);

let mut vm: Interpreter<_, _> = txtor.into();
let mut vm: Interpreter<_, _, _> = txtor.into();

if let Some(receipts_ctx) = receipts_ctx {
*vm.receipts_mut() = receipts_ctx;
Expand Down