Gas Profiling
Understanding gas consumption helps optimize your Move code and estimate transaction costs. The Move testing framework provides built-in tools to measure gas usage during test execution. In addition to that, a special utility sui analyze-trace is available for more thorough analysis of gas usage.
The statistics shown by -s only reflect computation units - they do not include storage costs. Additionally, compiler computation units don't map directly to actual onchain gas charges; they show relative computational complexity, useful for comparing implementations against each other. To get actual gas costs, publish your package to testnet and measure real transactions.
Simple Measurement: Test Statistics
Use the -s or --statistics flag with sui move test to see execution time and gas consumption for each test:
sui move test -s
The output shows a table with three columns:
Test Statistics:
┌────────────────────────────────────────────────────────┬────────────┬───────────────────────────┐
│ Test Name │ Time │ Gas Used │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_simple_operation │ 0.006 │ 998001 │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_complex_operation │ 0.007 │ 998068 │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_with_objects │ 0.006 │ 998001 │
└────────────────────────────────────────────────────────┴────────────┴───────────────────────────┘
Test result: OK. Total tests: 3; passed: 3; failed: 0
- Test Name: Fully qualified name of the test function
- Time: Execution time in seconds
- Gas Used: Gas units consumed by the test
Every test's total includes a large fixed base cost - even an empty test reports roughly 998000 gas units. When comparing tests, look at the difference between their totals rather than the absolute values.
CSV Output
For programmatic analysis or importing into spreadsheets, use the csv option:
sui move test -s csv
This produces comma-separated output:
name,nanos,gas
book::my_module::test_simple_operation,5992125,998001
book::my_module::test_complex_operation,6870583,998068
book::my_module::test_with_objects,6022917,998001
The time is in nanoseconds, which allows for more precise measurements when comparing similar operations.
Gas Limits
Use the -i or --gas-limit flag to set a maximum gas budget for tests. Tests exceeding this limit will timeout:
sui move test -i 1000
The limit is measured in internal execution gas units, which do not map one-to-one to the values in the Gas Used column - a trivial test that reports ~998000 gas passes comfortably with a limit of 1000.
Output when a test exceeds the gas limit:
[ TIMEOUT ] book::my_module::test_complex_operation
[ PASS ] book::my_module::test_simple_operation
[ PASS ] book::my_module::test_with_objects
Test failures:
Failures in book::my_module:
┌── test_complex_operation ──────
│ Test timed out
└──────────────────
Test result: FAILED. Total tests: 3; passed: 2; failed: 1
This is useful for:
- Identifying expensive operations: Find tests that consume unexpected amounts of gas
- Enforcing gas budgets: Ensure critical paths stay within acceptable limits
- Testing gas exhaustion: Verify your code handles out-of-gas scenarios correctly (see Expected Failures)
Comparing Implementations
Use statistics to compare gas consumption between different implementations:
module book::comparison;
use std::unit_test::assert_eq;
public fun sum_loop(n: u64): u64 {
let mut sum = 0;
n.do!(|i| sum = sum + i);
sum
}
public fun sum_formula(n: u64): u64 {
n * (n - 1) / 2
}
#[test]
fun test_sum_loop() {
let result = sum_loop(1000);
assert_eq!(result, 499500);
}
#[test]
fun test_sum_formula() {
let result = sum_formula(1000);
assert_eq!(result, 499500);
}
Running with statistics reveals the difference:
sui move test comparison -s
┌────────────────────────────────────┬────────────┬───────────────────────────┐
│ Test Name │ Time │ Gas Used │
├────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::comparison::test_sum_loop │ 0.003 │ 998078 │
├────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::comparison::test_sum_formula │ 0.001 │ 998001 │
└────────────────────────────────────┴────────────┴───────────────────────────┘
The loop costs 77 gas units on top of the base cost, while the formula adds nothing measurable.
Trace Analysis
For deeper profiling, you can generate execution traces from tests and visualize them with speedscope. This shows a flamegraph of gas consumption broken down by function calls, making it easy to spot exactly where gas is being spent.
Step 1: Generate Traces
Run tests with the --trace flag to produce trace files:
sui move test --trace
Trace files are written to the traces/ directory in the package root (next to Move.toml).
Step 2: Generate a Gas Profile
Use sui analyze-trace with the gas-profile subcommand to convert a trace into a profile:
sui analyze-trace -p traces/<TRACE_FILE> gas-profile
This outputs a gas_profile_<TRACE_FILE>.json file in the current directory. You can specify a different output directory with the -o flag, which goes before the gas-profile subcommand:
sui analyze-trace -p traces/<TRACE_FILE> -o ./profiles gas-profile
Step 3: Visualize with Speedscope
Install speedscope and open the profile:
npm install -g speedscope
speedscope gas_profile_<TRACE_FILE>.json
Speedscope provides three views:
- Time Order: Shows the call stack from left to right in invocation order. Bar width corresponds to gas consumption.
- Left Heavy: Groups repeated calls together, ordered by total gas consumption - useful for finding the most expensive code paths.
- Sandwich: Lists gas consumption per function with Total (including called functions) and Self (function only) columns.
Further Reading
- Running Tests - Basic test execution and expected failures
- Test Utilities - Assertion macros and test helpers
- Collections - Choosing efficient data structures
- Trace Analysis - Sui CLI trace analysis reference