Skip to content

Commit

Permalink
[gas] infrastructure for gas profiling (#6535)
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.

Co-authored-by: Greg Nazario <[email protected]>
  • Loading branch information
vgao1996 and gregnazario authored Mar 27, 2023
1 parent 3afb29d commit f66d717
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 f66d717

Please sign in to comment.