Skip to content

Commit

Permalink
[gas] add gas charges for dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
vgao1996 committed Feb 22, 2024
1 parent d4fdb8f commit d61b6bf
Show file tree
Hide file tree
Showing 32 changed files with 683 additions and 118 deletions.
7 changes: 6 additions & 1 deletion aptos-move/aptos-abstract-gas-usage/src/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

use aptos_gas_algebra::{
DynamicExpression, Fee, FeePerGasUnit, GasExpression, InternalGas, InternalGasUnit, Octa,
DynamicExpression, Fee, FeePerGasUnit, GasExpression, InternalGas, InternalGasUnit, NumBytes,
Octa,
};
use aptos_gas_meter::GasAlgebra;
use aptos_gas_schedule::VMGasParameters;
Expand Down Expand Up @@ -80,6 +81,10 @@ impl<A: GasAlgebra> GasAlgebra for CalibrationAlgebra<A> {
.charge_storage_fee(abstract_amount, gas_unit_price)
}

fn count_dependency(&mut self, size: NumBytes) -> PartialVMResult<()> {
self.base.count_dependency(size)
}

Check warning on line 86 in aptos-move/aptos-abstract-gas-usage/src/algebra.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-abstract-gas-usage/src/algebra.rs#L84-L86

Added lines #L84 - L86 were not covered by tests

fn execution_gas_used(&self) -> InternalGas {
self.base.execution_gas_used()
}
Expand Down
5 changes: 5 additions & 0 deletions aptos-move/aptos-gas-algebra/src/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ pub type FeePerSlot = GasQuantity<UnitDiv<Octa, Slot>>;

pub type FeePerByte = GasQuantity<UnitDiv<Octa, Byte>>;

/// Unit of module
pub enum Module {}

pub type NumModules = GasQuantity<Module>;

/***************************************************************************************************
* Unit Conversion
*
Expand Down
24 changes: 23 additions & 1 deletion aptos-move/aptos-gas-meter/src/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

use crate::traits::GasAlgebra;
use aptos_gas_algebra::{Fee, FeePerGasUnit, Gas, GasExpression, Octa};
use aptos_gas_algebra::{Fee, FeePerGasUnit, Gas, GasExpression, NumBytes, NumModules, Octa};
use aptos_gas_schedule::VMGasParameters;
use aptos_logger::error;
use aptos_vm_types::storage::{
Expand Down Expand Up @@ -32,6 +32,9 @@ pub struct StandardGasAlgebra {
storage_fee_in_internal_units: InternalGas,
// The storage fee consumed by the storage operations.
storage_fee_used: Fee,

num_dependencies: NumModules,
total_dependency_size: NumBytes,
}

impl StandardGasAlgebra {
Expand All @@ -53,6 +56,8 @@ impl StandardGasAlgebra {
io_gas_used: 0.into(),
storage_fee_in_internal_units: 0.into(),
storage_fee_used: 0.into(),
num_dependencies: 0.into(),
total_dependency_size: 0.into(),
}
}
}
Expand Down Expand Up @@ -234,6 +239,23 @@ impl GasAlgebra for StandardGasAlgebra {
Ok(())
}

fn count_dependency(&mut self, size: NumBytes) -> PartialVMResult<()> {
if self.feature_version >= 14 {
self.num_dependencies += 1.into();
self.total_dependency_size += size;

if self.num_dependencies > self.vm_gas_params.txn.max_num_dependencies {
return Err(PartialVMError::new(StatusCode::TOO_MANY_DEPENDENCIES));

Check warning on line 248 in aptos-move/aptos-gas-meter/src/algebra.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-meter/src/algebra.rs#L248

Added line #L248 was not covered by tests
}
if self.total_dependency_size > self.vm_gas_params.txn.max_total_dependency_size {
return Err(PartialVMError::new(
StatusCode::TOTAL_DEPENDENCY_SIZE_TOO_BIG,
));

Check warning on line 253 in aptos-move/aptos-gas-meter/src/algebra.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-meter/src/algebra.rs#L251-L253

Added lines #L251 - L253 were not covered by tests
}
}

Check warning on line 255 in aptos-move/aptos-gas-meter/src/algebra.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-meter/src/algebra.rs#L255

Added line #L255 was not covered by tests
Ok(())
}

fn execution_gas_used(&self) -> InternalGas {
self.execution_gas_used
}
Expand Down
11 changes: 11 additions & 0 deletions aptos-move/aptos-gas-meter/src/meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,17 @@ where

self.algebra.charge_execution(cost)
}

#[inline]
fn charge_dependency(&mut self, module_id: &ModuleId, size: NumBytes) -> PartialVMResult<()> {
// TODO: How about 0xA550C18?
if self.feature_version() >= 14 && !module_id.address().is_special() {
self.algebra
.charge_execution(DEPENDENCY_PER_MODULE + DEPENDENCY_PER_BYTE * size)?;
self.algebra.count_dependency(size)?;
}
Ok(())
}
}

impl<A> AptosGasMeter for StandardGasMeter<A>
Expand Down
3 changes: 3 additions & 0 deletions aptos-move/aptos-gas-meter/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ pub trait GasAlgebra {
gas_unit_price: FeePerGasUnit,
) -> PartialVMResult<()>;

/// Counts a dependency against the limits.
fn count_dependency(&mut self, size: NumBytes) -> PartialVMResult<()>;

/// Returns the amount of gas used under the execution category.
fn execution_gas_used(&self) -> InternalGas;

Expand Down
20 changes: 18 additions & 2 deletions aptos-move/aptos-gas-profiling/src/erased.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use crate::{
log::{
CallFrame, EventStorage, ExecutionAndIOCosts, ExecutionGasEvent, StorageFees, WriteStorage,
WriteTransient,
CallFrame, Dependency, EventStorage, ExecutionAndIOCosts, ExecutionGasEvent, StorageFees,
WriteStorage, WriteTransient,
},
render::Render,
FrameName, TransactionGasLog,
Expand Down Expand Up @@ -191,12 +191,28 @@ impl WriteTransient {
}
}

impl Dependency {
fn to_erased(&self) -> Node<InternalGas> {
Node::new(format!("{}", Render(&self.id)), self.cost)
}
}

impl ExecutionAndIOCosts {
/// Convert the gas log into a type-erased representation.
pub fn to_erased(&self) -> TypeErasedExecutionAndIoCosts {
let mut nodes = vec![];

nodes.push(Node::new("intrinsic", self.intrinsic_cost));

if !self.dependencies.is_empty() {
let deps = Node::new_with_children(
"dependencies",
0,
self.dependencies.iter().map(|dep| dep.to_erased()),
);
nodes.push(deps);
}

nodes.push(self.call_graph.to_erased());

let writes = Node::new_with_children(
Expand Down
4 changes: 4 additions & 0 deletions aptos-move/aptos-gas-profiling/src/flamegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ impl ExecutionAndIOCosts {
path: &'a mut Vec<String>,
}

for dep in &self.dependencies {
lines.push(format!("dependencies;{}", Render(&dep.id)), dep.cost)
}

impl<'a> Rec<'a> {
fn visit(&mut self, frame: &CallFrame) {
self.path.push(format!("{}", frame.name));
Expand Down
18 changes: 16 additions & 2 deletions aptos-move/aptos-gas-profiling/src/log.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use aptos_gas_algebra::{Fee, GasScalingFactor, InternalGas};
use aptos_gas_algebra::{Fee, GasScalingFactor, InternalGas, NumBytes};
use aptos_types::state_store::state_key::StateKey;
use move_binary_format::{file_format::CodeOffset, file_format_common::Opcodes};
use move_core_types::{
Expand Down Expand Up @@ -94,18 +94,28 @@ pub struct EventStorage {
pub cost: Fee,
}

#[derive(Debug, Clone)]
/// Struct representing the cost of a dependency.
pub struct Dependency {
pub id: ModuleId,
pub size: NumBytes,
pub cost: InternalGas,
}

/// Struct containing all execution and io costs.
#[derive(Debug)]
pub struct ExecutionAndIOCosts {
pub gas_scaling_factor: GasScalingFactor,
pub total: InternalGas,

pub intrinsic_cost: InternalGas,
pub dependencies: Vec<Dependency>,
pub call_graph: CallFrame,
pub write_set_transient: Vec<WriteTransient>,
}

#[derive(Debug)]
// Struct containing all types of storage fees.
/// Struct containing all types of storage fees.
pub struct StorageFees {
pub total: Fee,
pub total_refund: Fee,
Expand Down Expand Up @@ -219,6 +229,10 @@ impl ExecutionAndIOCosts {

total += self.intrinsic_cost;

for dep in &self.dependencies {
total += dep.cost;
}

for op in self.gas_events() {
match op {
Loc(..) | Call(..) => (),
Expand Down
22 changes: 20 additions & 2 deletions aptos-move/aptos-gas-profiling/src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

use crate::log::{
CallFrame, EventStorage, ExecutionAndIOCosts, ExecutionGasEvent, FrameName, StorageFees,
TransactionGasLog, WriteOpType, WriteStorage, WriteTransient,
CallFrame, Dependency, EventStorage, ExecutionAndIOCosts, ExecutionGasEvent, FrameName,
StorageFees, TransactionGasLog, WriteOpType, WriteStorage, WriteTransient,
};
use aptos_gas_algebra::{Fee, FeePerGasUnit, InternalGas, NumArgs, NumBytes, NumTypeNodes};
use aptos_gas_meter::{AptosGasMeter, GasAlgebra};
Expand Down Expand Up @@ -32,6 +32,7 @@ pub struct GasProfiler<G> {
base: G,

intrinsic_cost: Option<InternalGas>,
dependencies: Vec<Dependency>,
frames: Vec<CallFrame>,
write_set_transient: Vec<WriteTransient>,
storage_fees: Option<StorageFees>,
Expand Down Expand Up @@ -85,6 +86,7 @@ impl<G> GasProfiler<G> {
base,

intrinsic_cost: None,
dependencies: vec![],

Check warning on line 89 in aptos-move/aptos-gas-profiling/src/profiler.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-profiling/src/profiler.rs#L89

Added line #L89 was not covered by tests
frames: vec![CallFrame::new_script()],
write_set_transient: vec![],
storage_fees: None,
Expand All @@ -101,6 +103,7 @@ impl<G> GasProfiler<G> {
base,

intrinsic_cost: None,
dependencies: vec![],
frames: vec![CallFrame::new_function(module_id, func_name, ty_args)],
write_set_transient: vec![],
storage_fees: None,
Expand Down Expand Up @@ -466,6 +469,20 @@ where

res
}

fn charge_dependency(&mut self, module_id: &ModuleId, size: NumBytes) -> PartialVMResult<()> {
let (cost, res) = self.delegate_charge(|base| base.charge_dependency(module_id, size));

if !cost.is_zero() {
self.dependencies.push(Dependency {
id: module_id.clone(),
size,
cost,
});
}

res
}
}

fn write_op_type(op: &WriteOpSize) -> WriteOpType {
Expand Down Expand Up @@ -615,6 +632,7 @@ where
gas_scaling_factor: self.base.gas_unit_scaling_factor(),
total: self.algebra().execution_gas_used() + self.algebra().io_gas_used(),
intrinsic_cost: self.intrinsic_cost.unwrap_or_else(|| 0.into()),
dependencies: self.dependencies,
call_graph: self.frames.pop().expect("frame must exist"),
write_set_transient: self.write_set_transient,
};
Expand Down
26 changes: 26 additions & 0 deletions aptos-move/aptos-gas-profiling/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ impl TransactionGasLog {
data.insert("intrinsic-percentage".to_string(), json!(percentage));
}

let mut deps = self.exec_io.dependencies.clone();
deps.sort_by(|lhs, rhs| rhs.cost.cmp(&lhs.cost));
data.insert(
"deps".to_string(),
Value::Array(
deps.iter()
.map(|dep| {
let name = format!("{}", Render(&dep.id));
let cost_scaled =
format!("{:.8}", (u64::from(dep.cost) as f64 / scaling_factor));
let cost_scaled =
crate::misc::strip_trailing_zeros_and_decimal_point(&cost_scaled);
let percentage =
format!("{:.2}%", u64::from(dep.cost) as f64 / total_exec_io * 100.0);

json!({
"name": name,
"size": u64::from(dep.size),
"cost": cost_scaled,
"percentage": percentage,
})
})
.collect(),
),
);

// Execution & IO (aggregated)
let aggregated: crate::aggregate::AggregatedExecutionGasEvents =
self.exec_io.aggregate_gas_events();
Expand Down
21 changes: 21 additions & 0 deletions aptos-move/aptos-gas-profiling/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ <h4>Intrinsic Cost</h4>
{{#if intrinsic-percentage}}
, {{intrinsic-percentage}} of the total cost for execution & IO.
{{/if}}
<h4>Dependencies</h4>
{{#if deps}}
<table>
<tr>
<th><b>Name</b></th>
<th style="text-align: right"><b>Size in Bytes</th>
<th style="text-align: right"><b>Cost in Gas Units</b></th>
<th style="text-align: right"><b>Percentage</b></th>
</tr>
{{#each deps}}
<tr>
<td>{{name}}</td>
<td style="text-align: right">{{size}}</td>
<td style="text-align: right">{{cost}}</td>
<td style="text-align: right">{{percentage}}</td>
</tr>
{{/each}}
</table>
{{else}}
(No dependencies to show. System dependencies are excluded.)
{{/if}}
<h4>Execution</h4>
{{#if ops}}
<table>
Expand Down
22 changes: 21 additions & 1 deletion aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::gas_schedule::VMGasParameters;
use aptos_gas_algebra::{
AbstractValueSize, Fee, FeePerByte, FeePerGasUnit, FeePerSlot, Gas, GasExpression,
GasScalingFactor, GasUnit, NumSlots,
GasScalingFactor, GasUnit, NumModules, NumSlots,
};
use move_core_types::gas_algebra::{
InternalGas, InternalGasPerArg, InternalGasPerByte, InternalGasUnit, NumBytes, ToUnitWithParams,
Expand Down Expand Up @@ -200,6 +200,26 @@ crate::gas_schedule::macros::define_gas_parameters!(
{ 7.. => "max_storage_fee" },
2_0000_0000, // 2 APT
],
[
dependency_per_module: InternalGas,
{ 14.. => "dependency_per_module" },
4_000,
],
[
dependency_per_byte: InternalGasPerByte,
{ 14.. => "dependency_per_byte" },
100,
],
[
max_num_dependencies: NumModules,
{ 14.. => "max_num_dependencies" },
420,
],
[
max_total_dependency_size: NumBytes,
{ 14.. => "max_total_dependency_size" },
1024 * 1024 * 12 / 10, // 1.2 MB
],

Check warning on line 222 in aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs#L203-L222

Added lines #L203 - L222 were not covered by tests
]
);

Expand Down
3 changes: 3 additions & 0 deletions aptos-move/aptos-gas-schedule/src/ver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
///
/// Change log:
/// - V14
/// - Gas & limits for dependencies
/// - Gas for type creation
/// - V13
/// - Storage Fee: Make state bytes refundable and remove the per slot free quota, gated by flag REFUNDABLE_BYTES
/// - V13
/// (skipped due to testnet mis-operation)
Expand Down
2 changes: 2 additions & 0 deletions aptos-move/aptos-memory-usage-tracker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ where
fn charge_vec_swap(&mut self, ty: impl TypeView) -> PartialVMResult<()>;

fn charge_create_ty(&mut self, num_nodes: NumTypeNodes) -> PartialVMResult<()>;

fn charge_dependency(&mut self, module_id: &ModuleId, size: NumBytes) -> PartialVMResult<()>;
}

#[inline]
Expand Down
Loading

0 comments on commit d61b6bf

Please sign in to comment.