Skip to content

Commit

Permalink
[move] Benchmarking historical transactions (#15329)
Browse files Browse the repository at this point in the history
A tool to benchmark execution of past transactions. The user has to provide first and last
versions of the interval that need to be benchmarked. The tool partitions transactions in
the specified closed interval into blocks, and runs all blocks end-to-end, measuring the
time. During this run, executor is shared (and so are environment and module caches).

There is no commit here, only execution time. For each block, we maintain the state
(read-set estimated from 1 run before the benchmarks) on top of which it should run.
And so, the benchmark just runs in sequence blocks on top of their initial states
(outputs are only used for comparison against the on-chain data).

The tool allows one to override configs to experiment with new features, or with how
the execution would look like without some features. For now, we support:
- enabling features
- disabling features
In the future, we can add more overrides: gas schedule, modules, etc.
  • Loading branch information
georgemitenkov authored Dec 6, 2024
1 parent 3c6e693 commit 809457f
Show file tree
Hide file tree
Showing 20 changed files with 1,506 additions and 145 deletions.
21 changes: 21 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ members = [
"aptos-move/move-examples",
"aptos-move/mvhashmap",
"aptos-move/package-builder",
"aptos-move/replay-benchmark",
"aptos-move/script-composer",
"aptos-move/vm-genesis",
"aptos-node",
Expand Down Expand Up @@ -419,6 +420,7 @@ aptos-push-metrics = { path = "crates/aptos-push-metrics" }
aptos-rate-limiter = { path = "crates/aptos-rate-limiter" }
aptos-release-builder = { path = "aptos-move/aptos-release-builder" }
aptos-reliable-broadcast = { path = "crates/reliable-broadcast" }
aptos-replay-benchmark = { path = "aptos-move/replay-benchmark" }
aptos-resource-viewer = { path = "aptos-move/aptos-resource-viewer" }
aptos-rest-client = { path = "crates/aptos-rest-client" }
aptos-retrier = { path = "crates/aptos-retrier" }
Expand Down
73 changes: 34 additions & 39 deletions aptos-move/aptos-debugger/src/aptos_debugger.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, format_err, Result};
use aptos_block_executor::{
code_cache_global_manager::AptosModuleCacheManager,
txn_commit_hook::NoOpTransactionCommitHook,
txn_provider::{default::DefaultTxnProvider, TxnProvider},
};
use anyhow::{bail, format_err};
use aptos_block_executor::txn_provider::{default::DefaultTxnProvider, TxnProvider};
use aptos_gas_profiling::{GasProfiler, TransactionGasLog};
use aptos_rest_client::Client;
use aptos_types::{
Expand All @@ -28,9 +24,7 @@ use aptos_validator_interface::{
AptosValidatorInterface, DBDebuggerInterface, DebuggerStateView, RestDebuggerInterface,
};
use aptos_vm::{
block_executor::{AptosTransactionOutput, AptosVMBlockExecutorWrapper},
data_cache::AsMoveResolver,
AptosVM,
aptos_vm::AptosVMBlockExecutor, data_cache::AsMoveResolver, AptosVM, VMBlockExecutor,
};
use aptos_vm_environment::environment::AptosEnvironment;
use aptos_vm_logging::log_schema::AdapterLogSchema;
Expand All @@ -47,23 +41,31 @@ impl AptosDebugger {
Self { debugger }
}

pub fn rest_client(rest_client: Client) -> Result<Self> {
pub fn rest_client(rest_client: Client) -> anyhow::Result<Self> {
Ok(Self::new(Arc::new(RestDebuggerInterface::new(rest_client))))
}

pub fn db<P: AsRef<Path> + Clone>(db_root_path: P) -> Result<Self> {
pub fn db<P: AsRef<Path> + Clone>(db_root_path: P) -> anyhow::Result<Self> {
Ok(Self::new(Arc::new(DBDebuggerInterface::open(
db_root_path,
)?)))
}

pub async fn get_committed_transactions(
&self,
begin: Version,
limit: u64,
) -> anyhow::Result<(Vec<Transaction>, Vec<TransactionInfo>)> {
self.debugger.get_committed_transactions(begin, limit).await
}

pub fn execute_transactions_at_version(
&self,
version: Version,
txns: Vec<Transaction>,
repeat_execution_times: u64,
concurrency_levels: &[usize],
) -> Result<Vec<TransactionOutput>> {
) -> anyhow::Result<Vec<TransactionOutput>> {
let sig_verified_txns: Vec<SignatureVerifiedTransaction> =
txns.into_iter().map(|x| x.into()).collect::<Vec<_>>();
let txn_provider = DefaultTxnProvider::new(sig_verified_txns);
Expand Down Expand Up @@ -114,7 +116,7 @@ impl AptosDebugger {
&self,
version: Version,
txn: SignedTransaction,
) -> Result<(VMStatus, VMOutput, TransactionGasLog)> {
) -> anyhow::Result<(VMStatus, VMOutput, TransactionGasLog)> {
let state_view = DebuggerStateView::new(self.debugger.clone(), version);
let log_context = AdapterLogSchema::new(state_view.id(), 0);
let txn = txn
Expand Down Expand Up @@ -166,11 +168,8 @@ impl AptosDebugger {
use_same_block_boundaries: bool,
repeat_execution_times: u64,
concurrency_levels: &[usize],
) -> Result<Vec<TransactionOutput>> {
let (txns, txn_infos) = self
.debugger
.get_committed_transactions(begin, limit)
.await?;
) -> anyhow::Result<Vec<TransactionOutput>> {
let (txns, txn_infos) = self.get_committed_transactions(begin, limit).await?;

if use_same_block_boundaries {
// when going block by block, no need to worry about epoch boundaries
Expand Down Expand Up @@ -238,7 +237,7 @@ impl AptosDebugger {
txns: Vec<Transaction>,
repeat_execution_times: u64,
concurrency_levels: &[usize],
) -> Result<Vec<TransactionOutput>> {
) -> anyhow::Result<Vec<TransactionOutput>> {
let results = self.execute_transactions_at_version(
begin,
txns,
Expand Down Expand Up @@ -268,7 +267,7 @@ impl AptosDebugger {
repeat_execution_times: u64,
concurrency_levels: &[usize],
mut txn_infos: Vec<TransactionInfo>,
) -> Result<Vec<TransactionOutput>> {
) -> anyhow::Result<Vec<TransactionOutput>> {
let mut ret = vec![];
while limit != 0 {
println!(
Expand Down Expand Up @@ -301,7 +300,7 @@ impl AptosDebugger {
txns: Vec<Transaction>,
repeat_execution_times: u64,
concurrency_levels: &[usize],
) -> Result<Vec<TransactionOutput>> {
) -> anyhow::Result<Vec<TransactionOutput>> {
let mut ret = vec![];
let mut cur = vec![];
let mut cur_version = begin;
Expand Down Expand Up @@ -336,7 +335,7 @@ impl AptosDebugger {
&self,
account: AccountAddress,
seq: u64,
) -> Result<Option<Version>> {
) -> anyhow::Result<Option<Version>> {
self.debugger
.get_version_by_account_sequence(account, seq)
.await
Expand All @@ -345,7 +344,7 @@ impl AptosDebugger {
pub async fn get_committed_transaction_at_version(
&self,
version: Version,
) -> Result<(Transaction, TransactionInfo)> {
) -> anyhow::Result<(Transaction, TransactionInfo)> {
let (mut txns, mut info) = self.debugger.get_committed_transactions(version, 1).await?;

let txn = txns.pop().expect("there must be exactly 1 txn in the vec");
Expand Down Expand Up @@ -434,20 +433,16 @@ fn execute_block_no_limit(
state_view: &DebuggerStateView,
concurrency_level: usize,
) -> Result<Vec<TransactionOutput>, VMStatus> {
AptosVMBlockExecutorWrapper::execute_block::<
_,
NoOpTransactionCommitHook<AptosTransactionOutput, VMStatus>,
DefaultTxnProvider<SignatureVerifiedTransaction>,
>(
txn_provider,
state_view,
&AptosModuleCacheManager::new(),
BlockExecutorConfig {
local: BlockExecutorLocalConfig::default_with_concurrency_level(concurrency_level),
onchain: BlockExecutorConfigFromOnchain::new_no_block_limit(),
},
TransactionSliceMetadata::unknown(),
None,
)
.map(BlockOutput::into_transaction_outputs_forced)
let executor = AptosVMBlockExecutor::new();
executor
.execute_block_with_config(
txn_provider,
state_view,
BlockExecutorConfig {
local: BlockExecutorLocalConfig::default_with_concurrency_level(concurrency_level),
onchain: BlockExecutorConfigFromOnchain::new_no_block_limit(),
},
TransactionSliceMetadata::unknown(),
)
.map(BlockOutput::into_transaction_outputs_forced)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@

use crate::transactions;
use aptos_bitvec::BitVec;
use aptos_block_executor::{
code_cache_global_manager::AptosModuleCacheManager,
txn_commit_hook::NoOpTransactionCommitHook,
txn_provider::{default::DefaultTxnProvider, TxnProvider},
};
use aptos_block_executor::txn_provider::{default::DefaultTxnProvider, TxnProvider};
use aptos_block_partitioner::{
v2::config::PartitionerV2Config, BlockPartitioner, PartitionerConfig,
};
Expand All @@ -32,15 +28,15 @@ use aptos_types::{
},
ExecutionStatus, Transaction, TransactionOutput, TransactionStatus,
},
vm_status::VMStatus,
};
use aptos_vm::{
block_executor::{AptosTransactionOutput, AptosVMBlockExecutorWrapper},
aptos_vm::AptosVMBlockExecutor,
data_cache::AsMoveResolver,
sharded_block_executor::{
local_executor_shard::{LocalExecutorClient, LocalExecutorService},
ShardedBlockExecutor,
},
VMBlockExecutor,
};
use proptest::{collection::vec, prelude::Strategy, strategy::ValueTree, test_runner::TestRunner};
use std::{net::SocketAddr, sync::Arc, time::Instant};
Expand Down Expand Up @@ -217,20 +213,18 @@ where
) -> (Vec<TransactionOutput>, usize) {
let block_size = txn_provider.num_txns();
let timer = Instant::now();
let output = AptosVMBlockExecutorWrapper::execute_block::<
_,
NoOpTransactionCommitHook<AptosTransactionOutput, VMStatus>,
DefaultTxnProvider<SignatureVerifiedTransaction>,
>(
txn_provider,
self.state_view.as_ref(),
&AptosModuleCacheManager::new(),
BlockExecutorConfig::new_maybe_block_limit(1, maybe_block_gas_limit),
TransactionSliceMetadata::unknown(),
None,
)
.expect("VM should not fail to start")
.into_transaction_outputs_forced();

let executor = AptosVMBlockExecutor::new();
let output = executor
.execute_block_with_config(
txn_provider,
self.state_view.as_ref(),
BlockExecutorConfig::new_maybe_block_limit(1, maybe_block_gas_limit),
TransactionSliceMetadata::unknown(),
)
.expect("Sequential block execution should succeed")
.into_transaction_outputs_forced();

let exec_time = timer.elapsed().as_millis();

(output, block_size * 1000 / exec_time as usize)
Expand Down Expand Up @@ -263,28 +257,25 @@ where
fn execute_benchmark_parallel(
&self,
txn_provider: &DefaultTxnProvider<SignatureVerifiedTransaction>,
concurrency_level_per_shard: usize,
concurrency_level: usize,
maybe_block_gas_limit: Option<u64>,
) -> (Vec<TransactionOutput>, usize) {
let block_size = txn_provider.num_txns();
let timer = Instant::now();
let output = AptosVMBlockExecutorWrapper::execute_block::<
_,
NoOpTransactionCommitHook<AptosTransactionOutput, VMStatus>,
DefaultTxnProvider<SignatureVerifiedTransaction>,
>(
txn_provider,
self.state_view.as_ref(),
&AptosModuleCacheManager::new(),
BlockExecutorConfig::new_maybe_block_limit(
concurrency_level_per_shard,
maybe_block_gas_limit,
),
TransactionSliceMetadata::unknown(),
None,
)
.expect("VM should not fail to start")
.into_transaction_outputs_forced();

let executor = AptosVMBlockExecutor::new();
let output = executor
.execute_block_with_config(
txn_provider,
self.state_view.as_ref(),
BlockExecutorConfig::new_maybe_block_limit(
concurrency_level,
maybe_block_gas_limit,
),
TransactionSliceMetadata::unknown(),
)
.expect("Parallel block execution should succeed")
.into_transaction_outputs_forced();
let exec_time = timer.elapsed().as_millis();

(output, block_size * 1000 / exec_time as usize)
Expand Down
Loading

0 comments on commit 809457f

Please sign in to comment.