Skip to content

Commit

Permalink
Add gas profiling
Browse files Browse the repository at this point in the history
  • Loading branch information
Dentosal committed Dec 15, 2021
1 parent 1ad56e9 commit 2f09112
Show file tree
Hide file tree
Showing 12 changed files with 415 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/cargo_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ jobs:
command: test
args: --verbose --features random

- name: Run tests profiling
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --features random,profile-gas

- name: Run debug tests
uses: actions-rs/cargo@v1
with:
Expand Down
12 changes: 10 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ secp256k1 = { version = "0.20", features = ["recovery"] }
serde = { version = "1.0", features = ["derive"], optional = true }
sha3 = "0.9"
tracing = "0.1"
dyn-clone = { version = "1.0", optional = true }

[dev-dependencies]
rand = "0.8"

[features]
debug = []
random = ["fuel-types/random", "fuel-tx/random"]
serde-types = ["fuel-asm/serde-types", "fuel-types/serde-types", "fuel-tx/serde-types", "serde"]
profile-gas = [ "profile-any" ]
profile-any = [ "dyn-clone" ] # All profiling features should depend on this
random = [ "fuel-types/random", "fuel-tx/random" ]
serde-types = [ "fuel-asm/serde-types", "fuel-types/serde-types", "fuel-tx/serde-types", "serde" ]

[[test]]
name = "test-backtrace"
Expand All @@ -43,6 +46,11 @@ name = "test-contract"
path = "tests/contract.rs"
required-features = ["random"]

[[test]]
name = "test-profile-gas"
path = "tests/profile_gas.rs"
required-features = [ "random", "profile-gas" ]

[[test]]
name = "test-encoding"
path = "tests/encoding.rs"
Expand Down
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::convert::Infallible as StdInfallible;
use std::error::Error as StdError;
use std::{fmt, io};

#[derive(Debug)]
/// Interpreter runtime error variants.
#[derive(Debug)]
pub enum InterpreterError {
/// The instructions execution resulted in a well-formed panic, caused by an
/// explicit instruction.
Expand Down
14 changes: 14 additions & 0 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ mod transaction;
#[cfg(feature = "debug")]
mod debug;

#[cfg(feature = "profile-any")]
use crate::profiler::{InstructionLocation, Profiler};

pub use memory::MemoryRange;
pub use metadata::InterpreterMetadata;

Expand All @@ -49,6 +52,8 @@ pub struct Interpreter<S> {
debugger: Debugger,
context: Context,
block_height: u32,
#[cfg(feature = "profile-any")]
profiler: Profiler,
}

impl<S> Interpreter<S> {
Expand Down Expand Up @@ -87,6 +92,15 @@ impl<S> Interpreter<S> {
pub fn receipts(&self) -> &[Receipt] {
self.receipts.as_slice()
}

#[cfg(feature = "profile-any")]
fn current_location(&self) -> InstructionLocation {
use crate::consts::*;
InstructionLocation::new(
self.frames.last().map(|frame| *frame.to()),
self.registers[REG_PC] - self.registers[REG_IS],
)
}
}

impl<S> From<Interpreter<S>> for Transaction {
Expand Down
16 changes: 14 additions & 2 deletions src/interpreter/constructors.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! Exposed constructors API for the [`Interpreter`]
use fuel_tx::Transaction;

use super::Interpreter;
use crate::client::MemoryStorage;
use crate::consts::*;
use crate::context::Context;
use crate::prelude::*;
use crate::state::Debugger;

use fuel_tx::Transaction;
#[cfg(feature = "profile-any")]
use crate::profiler::{ProfileReceiver, Profiler};

impl<S> Interpreter<S> {
/// Create a new interpreter instance out of a storage implementation.
Expand All @@ -25,8 +28,17 @@ impl<S> Interpreter<S> {
debugger: Debugger::default(),
context: Context::default(),
block_height: 0,
#[cfg(feature = "profile-any")]
profiler: Profiler::default(),
}
}

/// Sets a profiler for the VM
#[cfg(feature = "profile-any")]
pub fn with_profiling(mut self, receiver: Box<dyn ProfileReceiver>) -> Self {
self.profiler.set_receiver(receiver);
self
}
}

impl<S> Default for Interpreter<S>
Expand Down
19 changes: 17 additions & 2 deletions src/interpreter/executors/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::consts::*;
use crate::contract::Contract;
use crate::crypto;
use crate::error::{InterpreterError, RuntimeError};
use crate::error::InterpreterError;
use crate::interpreter::{Interpreter, MemoryRange};
use crate::prelude::*;
use crate::state::{ExecuteState, ProgramState, StateTransitionRef};
use crate::storage::InterpreterStorage;

Expand Down Expand Up @@ -205,12 +206,26 @@ where
}
}

/// Allocate internally a new instance of [`Interpreter`] with the provided
/// storage, initialize it with the provided transaction and return the
/// result of th execution in form of [`StateTransition`]
pub fn transact_owned(storage: S, tx: Transaction) -> Result<StateTransition, InterpreterError> {
Interpreter::with_storage(storage)
.transact(tx)
.map(|st| st.into_owned())
}

/// Initialize a pre-allocated instance of [`Interpreter`] with the provided
/// transaction and execute it. The result will be bound to the lifetime
/// of the interpreter and will avoid unnecessary copy with the data
/// that can be referenced from the interpreter instance itself.
pub fn transact(&mut self, tx: Transaction) -> Result<StateTransitionRef<'_>, InterpreterError> {
let state = self.init(tx).and_then(|_| self.run())?;
let state_result = self.init(tx).and_then(|_| self.run());

#[cfg(feature = "profile-any")]
self.profiler.on_transaction(&state_result);

let state = state_result?;

let transition = StateTransitionRef::new(state, self.transaction(), self.receipts());

Expand Down
7 changes: 7 additions & 0 deletions src/interpreter/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ impl<S> Interpreter<S> {
pub(crate) fn gas_charge(&mut self, gas: Word) -> Result<(), RuntimeError> {
let gas = !self.is_predicate() as Word * gas;

#[cfg(feature = "profile-gas")]
{
let gas_use = gas.min(self.registers[REG_CGAS]);
let location = self.current_location();
self.profiler.data_mut().gas_mut().add(location, gas_use);
}

if gas > self.registers[REG_CGAS] {
self.registers[REG_GGAS] -= self.registers[REG_CGAS];
self.registers[REG_CGAS] = 0;
Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@

pub mod backtrace;
pub mod call;
pub mod client;
pub mod consts;
pub mod context;
pub mod contract;
pub mod crypto;
pub mod error;
pub mod gas;
pub mod interpreter;
pub mod memory_client;
pub mod state;
pub mod storage;
pub mod transactor;

#[cfg(feature = "profile-any")]
pub mod profiler;

pub mod prelude {
//! Required implementations for full functionality
Expand All @@ -30,11 +33,11 @@ pub mod prelude {

pub use crate::backtrace::Backtrace;
pub use crate::call::{Call, CallFrame};
pub use crate::client::{MemoryClient, MemoryStorage};
pub use crate::context::Context;
pub use crate::contract::Contract;
pub use crate::error::{Infallible, InterpreterError, RuntimeError};
pub use crate::interpreter::{Interpreter, InterpreterMetadata, MemoryRange};
pub use crate::memory_client::{MemoryClient, MemoryStorage};
pub use crate::state::{Debugger, ProgramState, StateTransition, StateTransitionRef};
pub use crate::storage::InterpreterStorage;
pub use crate::transactor::Transactor;
Expand Down
5 changes: 5 additions & 0 deletions src/client.rs → src/memory_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ impl<'a> MemoryClient<'a> {
}
}

/// Create a new instance of the memory client out of a provided storage.
pub fn from_txtor(transactor: Transactor<'a, MemoryStorage>) -> Self {
Self { transactor }
}

/// If a transaction was executed and produced a VM panic, returns the
/// backtrace; return `None` otherwise.
pub fn backtrace(&self) -> Option<Backtrace> {
Expand Down
File renamed without changes.
Loading

0 comments on commit 2f09112

Please sign in to comment.