This page documents the gas cost collection system in fuel-core, which processes VM benchmark results and generates gas cost tables used by the consensus layer. The system takes raw timing measurements from Criterion benchmarks and converts them into normalized gas costs that represent the computational expense of VM operations.
For information about the benchmark execution system that generates the input data, see VM Benchmarking System. For details on how these gas costs are used in consensus, see Consensus Parameters and Gas Costs.
The gas cost collection system is a post-processing utility that transforms benchmark timing data into consensus-layer gas cost configurations. Every VM operation in the Fuel VM has an associated gas cost that determines how much "gas" is consumed when executing that operation. These costs must:
The collection system achieves this by:
noop) as the unit of measurementKey Terminology:
noop) used to normalize all measurementsSources: benches/src/bin/collect.rs1-250
collect.rs CLI Tool Architecture
The system is implemented as a command-line binary at benches/src/bin/collect.rs that processes benchmark results through several stages:
Sources: benches/src/bin/collect.rs32-58 benches/src/bin/collect.rs142-249
State Data Structure
The State struct maintains all collected benchmark data during processing:
| Field | Type | Purpose |
|---|---|---|
baseline | String | ID of baseline operation (e.g., "noop/noop") |
all | bool | Whether to include all sample values |
ids | HashMap<String, Duration> | Map of benchmark ID to mean execution time |
throughput | HashMap<String, u64> | Map of benchmark ID to throughput (bytes/iteration) |
groups | HashMap<String, Vec<String>> | Map of group name to member benchmark IDs |
Sources: benches/src/bin/collect.rs100-124
The collection tool parses two types of JSON messages from Criterion:
This message contains:
id: Unique benchmark identifier (format: group/name or group/name/size)mean.estimate: Average execution timemean.unit: Time unit (ns, us, ms, s)throughput: Optional array with bytes/iterations processedThis message indicates:
The decode_input function parses these messages and returns Output::Mean or Output::Group variants.
Sources: benches/src/bin/collect.rs277-325
Cost Enum Structure
The system models VM operation costs using a two-level enum:
Cost enum (benches/src/bin/collect.rs136-140):
Relative(u64): Fixed cost expressed as multiple of baselineDependent(DependentCost): Variable cost that depends on input sizeDependentCost enum (benches/src/bin/collect.rs130-133):
LightOperation { base: u64, units_per_gas: u64 }: When cost grows slowly
aloc (memory allocation) - 300 units per gas unitcost = base + (size / units_per_gas)HeavyOperation { base: u64, gas_per_unit: u64 }: When cost grows quickly
scwq (state clear word queue) - 515 gas per unitcost = base + (size * gas_per_unit)Sources: benches/src/bin/collect.rs129-140
Two-Stage Processing
The into_costs method (benches/src/bin/collect.rs513-516) processes benchmark data in two stages:
The into_dependent_costs method (benches/src/bin/collect.rs533-580) processes operations with variable costs:
mcp/10000, mcp/100000)ids mapThe into_relative_costs method (benches/src/bin/collect.rs582-599) processes remaining operations:
map_to_ratioCosts hashmapThe map_to_ratio function (benches/src/bin/collect.rs327-333) performs ceiling division to ensure minimum cost of 1.
Sources: benches/src/bin/collect.rs513-599 benches/src/bin/collect.rs327-333
The linear regression analysis determines how operation cost scales with input size:
dependent_cost Function
The dependent_cost function (benches/src/bin/collect.rs640-758) analyzes the relationship between input size and execution cost:
The linear_regression function (benches/src/bin/collect.rs608-638) computes the slope:
Given points (x_i, y_i):
avg_x = Σx_i / n
avg_y = Σy_i / n
B = Σ((x_i - avg_x) * (y_i - avg_y)) / Σ((x_i - avg_x)²)
slope = 1/B (inverted to get units per cost)
Operations are classified by comparing first and last data points:
| Type | Condition | Meaning |
|---|---|---|
| Linear | abs(first.amount() - slope) < 20% AND abs(last.amount() - slope) < 20% | Cost scales linearly with size |
| Logarithm | first.price() > last.price() | Cost per unit decreases (sublinear growth) |
| Exp | first.price() < last.price() | Cost per unit increases (superlinear growth) |
Where:
point.price() = cost per element = y / xpoint.amount() = elements per cost = x / yFor Linear operations:
amount()For Logarithm/Exp operations:
if amount > 1.0:
→ LightOperation { base, units_per_gas: amount }
else:
→ HeavyOperation { base, gas_per_unit: 1.0 / amount }
Sources: benches/src/bin/collect.rs608-758
The to_yaml (benches/src/bin/collect.rs498-507) and to_json (benches/src/bin/collect.rs509-511) methods serialize the Costs hashmap:
The to_rust_code method (benches/src/bin/collect.rs375-492) generates a Rust source file:
Remapping and Cleanup:
mod → mod_op, move → move_opret_script, rvrt_script, retd_scriptret_contract → retTemplate Structure (benches/src/bin/collect.rs360-372):
Missing Key Detection:
The generator compares generated keys against GasCostsValuesV6 structure and warns about any missing fields.
The ConsensusParameters output format (benches/src/bin/collect.rs240-246) wraps the gas costs in a full consensus configuration:
Sources: benches/src/bin/collect.rs232-246 benches/src/bin/collect.rs375-492 benches/src/bin/collect.rs498-511
CLI Arguments (benches/src/bin/collect.rs32-58):
| Argument | Short | Type | Default | Description |
|---|---|---|---|---|
--baseline | -b | String | "noop/noop" | Benchmark ID to use as baseline |
--output | -o | PathBuf | Current dir | Output file path (directory or file) |
--input | -i | PathBuf | stdin | Input file or directory |
--debug | -d | Flag | false | Print input/output for debugging |
--all | -a | Flag | false | Include all sample values |
--format | -f | Enum | Yaml | Output format (Yaml/Json/Rust/ConsensusParameters) |
Step 1: Run Benchmarks
Step 2: Process Results
Step 3: Integration The generated Rust code is typically copied to benches/src/default_gas_costs.rs and used to update the consensus parameters.
The tool supports reading from stdin with Ctrl-C handling (benches/src/bin/collect.rs157-159):
The tool accumulates data until interrupted, allowing real-time processing of benchmark runs.
Sources: benches/src/bin/collect.rs32-58 benches/src/bin/collect.rs142-249
The gas cost collection tool is designed to work with the VM benchmarking system:
VM benchmarks use the VmBench struct (benches/src/lib.rs110-187) to configure test scenarios:
BenchDb (benches/benches/vm_set/blockchain.rs73-188) with RocksDB and contract stateThe run_group_ref function (benches/benches/vm.rs28-76) executes benchmarks:
VmBenchPrepared containing initial statequanta::Clockdiff to enable repeated measurementsFor an operation like mcp (memory copy):
This generates multiple data points that collect.rs uses for linear regression.
Sources: benches/benches/vm.rs28-76 benches/src/lib.rs110-187 benches/benches/vm_set/blockchain.rs73-188
This example traces how the mcp (memory copy) operation is processed:
ids: {
"mcp/10000" → 141.6ns,
"mcp/100000" → 1416.0ns
}
throughput: {
"mcp/10000" → 10000,
"mcp/100000" → 100000
}
groups: {
"mcp" → ["mcp/10000", "mcp/100000"]
}
141.6 / 20 = 7, 1416.0 / 20 = 71[(10000, 7), (100000, 71)]LightOperation { base: 7, units_per_gas: 1408 }Note: Actual values differ due to multiple sample points and statistical analysis.
Sources: benches/src/bin/collect.rs533-758
Refresh this wiki