Skip to content

Commit

Permalink
[gas] infrastructure for gas profiling
Browse files Browse the repository at this point in the history
This implements the infrastructure required to support gas profiling and
adds an alternative mode to aptos-node, which if enabled, will generate
a flamegraph for each transaction being executed.
  • Loading branch information
vgao1996 committed Mar 24, 2023
1 parent d957664 commit cc7436b
Show file tree
Hide file tree
Showing 21 changed files with 2,122 additions and 322 deletions.
328 changes: 282 additions & 46 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"aptos-move/aptos-aggregator",
"aptos-move/aptos-debugger",
"aptos-move/aptos-gas",
"aptos-move/aptos-gas-profiling",
"aptos-move/aptos-release-builder",
"aptos-move/aptos-resource-viewer",
"aptos-move/aptos-sdk-builder",
Expand Down Expand Up @@ -282,6 +283,7 @@ aptos-framework = { path = "aptos-move/framework" }
aptos-fuzzer = { path = "testsuite/aptos-fuzzer" }
aptos-gas = { path = "aptos-move/aptos-gas" }
aptos-gas-algebra-ext = { path = "aptos-move/gas-algebra-ext" }
aptos-gas-profiling = { path = "aptos-move/aptos-gas-profiling" }
aptos-genesis = { path = "crates/aptos-genesis" }
aptos-github-client = { path = "secure/storage/github" }
aptos-global-constants = { path = "config/global-constants" }
Expand Down Expand Up @@ -454,6 +456,7 @@ hyper-tls = "0.5.0"
include_dir = { version = "0.7.2", features = ["glob"] }
indicatif = "0.15.0"
indoc = "1.0.6"
inferno = "0.11.14"
ipnet = "2.5.0"
itertools = "0.10.3"
jemallocator = { version = "0.3.2", features = [
Expand Down
2 changes: 2 additions & 0 deletions aptos-move/aptos-debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ edition = "2021"
anyhow = { workspace = true }
aptos-crypto = { workspace = true }
aptos-gas = { workspace = true }
aptos-gas-profiling = { workspace = true }
aptos-logger = { workspace = true }
aptos-resource-viewer = { workspace = true }
aptos-rest-client = { workspace = true }
aptos-state-view = { workspace = true }
aptos-types = { workspace = true }
aptos-validator-interface = { workspace = true }
aptos-vm = { workspace = true }
aptos-vm-logging = { workspace = true }
clap = { workspace = true }
move-binary-format = { workspace = true }
move-cli = { workspace = true }
Expand Down
52 changes: 50 additions & 2 deletions aptos-move/aptos-debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@

use anyhow::{format_err, Result};
use aptos_gas::{
AbstractValueSizeGasParameters, ChangeSetConfigs, NativeGasParameters,
AbstractValueSizeGasParameters, ChangeSetConfigs, NativeGasParameters, StandardGasMeter,
LATEST_GAS_FEATURE_VERSION,
};
use aptos_gas_profiling::{GasProfiler, TransactionGasLog};
use aptos_resource_viewer::{AnnotatedAccountStateBlob, AptosValueAnnotator};
use aptos_rest_client::Client;
use aptos_state_view::TStateView;
use aptos_types::{
account_address::AccountAddress,
chain_id::ChainId,
on_chain_config::{Features, OnChainConfig, TimedFeatures},
transaction::{ChangeSet, Transaction, TransactionInfo, TransactionOutput, Version},
transaction::{
ChangeSet, SignedTransaction, Transaction, TransactionInfo, TransactionOutput,
TransactionPayload, Version,
},
vm_status::VMStatus,
};
use aptos_validator_interface::{
AptosValidatorInterface, DBDebuggerInterface, DebuggerStateView, RestDebuggerInterface,
Expand All @@ -22,6 +28,7 @@ use aptos_vm::{
move_vm_ext::{MoveVmExt, SessionExt, SessionId},
AptosVM, VMExecutor,
};
use aptos_vm_logging::log_schema::AdapterLogSchema;
use move_binary_format::errors::VMResult;
use std::{path::Path, sync::Arc};

Expand Down Expand Up @@ -54,6 +61,47 @@ impl AptosDebugger {
.map_err(|err| format_err!("Unexpected VM Error: {:?}", err))
}

pub fn execute_transaction_at_version_with_gas_profiler(
&self,
version: Version,
txn: SignedTransaction,
) -> Result<(VMStatus, TransactionOutput, TransactionGasLog)> {
let state_view = DebuggerStateView::new(self.debugger.clone(), version);
let log_context = AdapterLogSchema::new(state_view.id(), 0);
let txn = txn
.check_signature()
.map_err(|err| format_err!("Unexpected VM Error: {:?}", err))?;

let (status, output, gas_profiler) =
AptosVM::execute_user_transaction_with_custom_gas_meter(
&state_view,
&txn,
&log_context,
|gas_feature_version, gas_params, storage_gas_params, balance| {
let gas_meter = StandardGasMeter::new(
gas_feature_version,
gas_params,
storage_gas_params,
balance,
);
let gas_profiler = match txn.payload() {
TransactionPayload::Script(_) => GasProfiler::new_script(gas_meter),
TransactionPayload::EntryFunction(entry_func) => GasProfiler::new_function(
gas_meter,
entry_func.module().clone(),
entry_func.function().to_owned(),
entry_func.ty_args().to_vec(),
),
TransactionPayload::ModuleBundle(..) => unreachable!("not supported"),
TransactionPayload::Multisig(..) => unimplemented!("not supported yet"),
};
Ok(gas_profiler)
},
)?;

Ok((status, output, gas_profiler.finish()))
}

pub async fn execute_past_transactions(
&self,
mut begin: Version,
Expand Down
26 changes: 26 additions & 0 deletions aptos-move/aptos-gas-profiling/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "aptos-gas-profiling"
version = "0.1.0"

# Workspace inherited keys
authors = { workspace = true }
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
publish = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }

[dependencies]
anyhow = { workspace = true }
inferno = { workspace = true }
regex = { workspace = true }

aptos-framework = { workspace = true }
aptos-gas = { workspace = true }
aptos-package-builder = { workspace = true }
aptos-types = { workspace = true }

move-binary-format = { workspace = true }
move-core-types = { workspace = true }
move-vm-types = { workspace = true }
41 changes: 41 additions & 0 deletions aptos-move/aptos-gas-profiling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Gas Profiling

## Overview
This crate implements a gas profiler that can be plugged into the Aptos VM to generate comprehensive traces of gas usage, referred to as the transaction gas log.
It also contains a module for visualizing the transaction gas log, in the form of a flamegraph.

## Running the Gas Profiler
You can run the gas profiler by appending the `--profile-gas` option to the aptos cli's `move publish`, `move run` & `move run-script` commands. Here is an example:
```
>> cargo run -p aptos -- move publish --profile-gas
Finished dev [unoptimized + debuginfo] target(s) in 0.51s
Running `/home/vgao/aptos-core/target/debug/aptos move publish --profile-gas`
Compiling, may take a little while to download git dependencies...
BUILDING empty_fun
package size 427 bytes
Simulating transaction locally with the gas profiler...
This is still experimental so results may be inaccurate.
Execution & IO Gas flamegraph saved to gas-profiling/txn-69e19ee4-0x1-code-publish_package_txn.exec_io.svg
Storage fee flamegraph saved to gas-profiling/txn-69e19ee4-0x1-code-publish_package_txn.storage.svg
{
"Result": {
"transaction_hash": "0x69e19ee4cc89cb1f84ee21a46e6b281bd8696115aa332275eca38c4857818dfe",
"gas_used": 1007,
"gas_unit_price": 100,
"sender": "dbcbe741d003a7369d87ec8717afb5df425977106497052f96f4e236372f7dd5",
"success": true,
"version": 473269362,
"vm_status": "status EXECUTED of type Execution"
}
}
```

## Performance Implications
It is important to note that the current gas profiler implementation is quite heavy-weight since it records every Move bytecode instruction and its cost. If real-time gas profiling is required, it is recommended to develop a custom profiler that operates on aggregated data. A standard light-weight implementation may be provided in the future.

## Known Issues & Future Plans
1. While addresses are truncated in the flamegraphs, they are still somewhat cumbersome. We plan to come up with a smart rendering algorithm that omits addresses, provided that the functions/items can still be unambiguously identified.
2. At present, the storage fee graph does not display the free quota for events. We plan to address this in a future update.
Loading

0 comments on commit cc7436b

Please sign in to comment.