Skip to content

Commit

Permalink
Rooch Gas Profiling Implementation
Browse files Browse the repository at this point in the history
enable the gas event recording

finish the gas profiling

convert linear gas event list to stacked

implement flamegraph for execution

cargo clippy

render html template

add the content of the execution trace

Put the gas profiling in moveos repo

implement ClassifiedGasMeter and SwitchableGasMeter for GasProfiler
  • Loading branch information
steelgeek091 committed Sep 19, 2024
1 parent 99c3fb4 commit 1a93d61
Show file tree
Hide file tree
Showing 23 changed files with 1,505 additions and 64 deletions.
52 changes: 51 additions & 1 deletion Cargo.lock

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

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"moveos/moveos-commons/bcs_ext",
"moveos/moveos-commons/moveos-common",
"moveos/moveos-commons/timeout-join-handler",
"moveos/moveos-commons/moveos-common",
"moveos/moveos-compiler",
"moveos/moveos-config",
"moveos/moveos-object-runtime",
Expand All @@ -18,6 +19,7 @@ members = [
"moveos/raw-store",
"moveos/smt",
"moveos/moveos-eventbus",
"moveos/moveos-gas-profiling",
"crates/data_verify",
"crates/rooch",
"crates/rooch-benchmarks",
Expand Down Expand Up @@ -96,6 +98,7 @@ moveos-object-runtime = { path = "moveos/moveos-object-runtime" }
moveos-compiler = { path = "moveos/moveos-compiler" }
moveos-eventbus = { path = "moveos/moveos-eventbus" }
accumulator = { path = "moveos/moveos-commons/accumulator" }
moveos-gas-profiling = { path = "moveos/moveos-gas-profiling" }

# crates for Rooch
rooch = { path = "crates/rooch" }
Expand Down Expand Up @@ -337,6 +340,9 @@ vergen-git2 = { version = "1.0.0", features = ["build", "cargo", "rustc"] }
vergen-pretty = "0.3.4"
crossbeam-channel = "0.5.13"

inferno = "0.11.14"
handlebars = "4.2.2"

# Note: the BEGIN and END comments below are required for external tooling. Do not remove.
# BEGIN MOVE DEPENDENCIES
move-abigen = { git = "https://github.com/rooch-network/move", rev = "c05b5f71a24beb498eb743d73be4f69d8d325e62" }
Expand Down
4 changes: 4 additions & 0 deletions moveos/moveos-commons/moveos-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ bcs = { workspace = true }
log = { workspace = true }
itertools = { workspace = true }
libc = { workspace = true }

move-core-types = { workspace = true }
move-binary-format = { workspace = true }
move-vm-types = { workspace = true }
1 change: 1 addition & 0 deletions moveos/moveos-commons/moveos-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

pub mod types;
pub mod utils;
59 changes: 59 additions & 0 deletions moveos/moveos-commons/moveos-common/src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use move_binary_format::errors::PartialVMResult;
use move_core_types::gas_algebra::InternalGas;
use move_vm_types::gas::{GasMeter, UnmeteredGasMeter};

#[derive(Debug, Clone)]
pub struct GasStatement {
pub execution_gas_used: InternalGas,
pub storage_gas_used: InternalGas,
}

pub trait ClassifiedGasMeter {
fn charge_execution(&mut self, gas_cost: u64) -> PartialVMResult<()>;
// fn charge_io_read(&mut self);
fn charge_io_write(&mut self, data_size: u64) -> PartialVMResult<()>;
//fn charge_event(&mut self, events: &[TransactionEvent]) -> PartialVMResult<()>;
//fn charge_change_set(&mut self, change_set: &StateChangeSet) -> PartialVMResult<()>;
fn check_constrains(&self, max_gas_amount: u64) -> PartialVMResult<()>;
fn gas_statement(&self) -> GasStatement;
}

impl ClassifiedGasMeter for UnmeteredGasMeter {
fn charge_execution(&mut self, _gas_cost: u64) -> PartialVMResult<()> {
Ok(())
}

fn charge_io_write(&mut self, _data_size: u64) -> PartialVMResult<()> {
Ok(())
}

fn check_constrains(&self, _max_gas_amount: u64) -> PartialVMResult<()> {
Ok(())
}

fn gas_statement(&self) -> GasStatement {
GasStatement {
execution_gas_used: InternalGas::from(0),
storage_gas_used: InternalGas::from(0),
}
}
}

pub trait SwitchableGasMeter: GasMeter {
fn stop_metering(&mut self);
fn start_metering(&mut self);
fn is_metering(&self) -> bool;
}

impl SwitchableGasMeter for UnmeteredGasMeter {
fn stop_metering(&mut self) {}

fn start_metering(&mut self) {}

fn is_metering(&self) -> bool {
false
}
}
26 changes: 26 additions & 0 deletions moveos/moveos-gas-profiling/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "moveos-gas-profiling"

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

[dependencies]
inferno = { workspace = true }
move-core-types = { workspace = true }
move-vm-types = { workspace = true }
move-binary-format = { workspace = true }
anyhow = { workspace = true }
regex = { workspace = true }
serde_json = { workspace = true }
smallvec = { workspace = true }
handlebars = { workspace = true }

moveos-types = { workspace = true }
moveos-common = { workspace = true }
96 changes: 96 additions & 0 deletions moveos/moveos-gas-profiling/src/aggregate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::log::ExecutionAndIOCosts;
use crate::log::ExecutionGasEvent;
use crate::render::Render;
use move_core_types::gas_algebra::{GasQuantity, InternalGas};
use std::collections::{btree_map, BTreeMap};

/// Represents an aggregation of execution gas events, including the count and total gas costs for each type of event.
///
/// The events are sorted by the amount of gas used, from high to low.
#[derive(Debug)]
pub struct AggregatedExecutionGasEvents {
pub ops: Vec<(String, usize, InternalGas)>,
}

fn insert_or_add<K, U>(
map: &mut BTreeMap<K, (usize, GasQuantity<U>)>,
key: K,
amount: GasQuantity<U>,
) where
K: Ord,
{
if amount.is_zero() {
return;
}
match map.entry(key) {
btree_map::Entry::Occupied(entry) => {
let r = entry.into_mut();
r.0 += 1;
r.1 += amount;
}
btree_map::Entry::Vacant(entry) => {
entry.insert((1, amount));
}
}
}

fn into_sorted_vec<I, K, N>(collection: I) -> Vec<(K, usize, N)>
where
N: Ord,
I: IntoIterator<Item = (K, (usize, N))>,
{
let mut v = collection
.into_iter()
.map(|(key, (count, amount))| (key, count, amount))
.collect::<Vec<_>>();
// Sort in descending order.
v.sort_by(|(_key1, _count1, amount1), (_key2, _count2, amount2)| amount2.cmp(amount1));
v
}

impl ExecutionAndIOCosts {
/// Counts the number of hits and aggregates the gas costs for each type of event.
pub fn aggregate_gas_events(&self) -> AggregatedExecutionGasEvents {
use ExecutionGasEvent::*;

let mut ops = BTreeMap::new();
let mut storage_reads = BTreeMap::new();

for event in self.gas_events() {
match event {
Loc(..) | Call(..) => (),
Bytecode { op, cost } => insert_or_add(
&mut ops,
format!("{:?}", op).to_ascii_lowercase().to_string(),
*cost,
),
CallNative {
module_id,
fn_name,
ty_args,
cost,
} => insert_or_add(
&mut ops,
format!(
"{}",
Render(&(module_id, fn_name.as_ident_str(), ty_args.as_slice())),
),
*cost,
),
LoadResource {
addr: _addr,
ty,
cost,
} => insert_or_add(&mut storage_reads, format!("{}", ty), *cost),
CreateTy { cost } => insert_or_add(&mut ops, "create_ty".to_string(), *cost),
}
}

AggregatedExecutionGasEvents {
ops: into_sorted_vec(ops),
}
}
}
Loading

0 comments on commit 1a93d61

Please sign in to comment.