Gas profiling with snapshots
Learn how to profile gas and fees of transaction chains with --snapshot and baseline comparison
Gas profiling records gas and fee metrics for message opcodes and transaction chains. Performance regressions show up in the --snapshot and --baseline-snapshot outputs.
What gets profiled
When profiling is enabled, Acton prints:
- Opcode gas usage table: min, max, and avg gas per opcode or message opcode name.
- Per test gas and fees summary.
- Per trace gas and fees details inside each test.
For chain-level metrics, Acton tracks: transaction count, gas used, gas fee, forward fee, and the total fee.
Profiling is collected after the selected tests pass. If any selected test fails, Acton skips snapshot writing and comparison tables for that run.
Quick start
Create a baseline snapshot
acton test --snapshot gas-baseline.jsonThis runs tests and writes a JSON snapshot of opcode and trace-chain statistics:
GAS USAGE
───────────────────────────────────────────────
Opcode Min Gas Max Gas Avg Gas
───────────────────────────────────────────────
IncreaseCounter 1536 1536 1536
ResetCounter 1349 1349 1349
0x00000999 680 680 680
CHAIN GAS & FEES SUMMARY
──────────────────────────────────────────────────────────────────────────────────────────────────
Test Traces Tx Gas Used Gas Fee Forward Fee Total Fee
──────────────────────────────────────────────────────────────────────────────────────────────────
test increase counter 4 4 2789 0.0011156 TON 0.002000284 TON 0.0011156 TON
test reset counter 5 5 4138 0.0016552 TON 0.002266953 TON 0.0016552 TON
test unknown message 5 5 2568 0.0010272 TON 0.002266953 TON 0.0010272 TONCompare current run with baseline
acton test --baseline-snapshot gas-baseline.jsonThis prints comparison tables with diffs for opcode gas and chain metrics.
GAS USAGE COMPARISON
Baseline: gas-baseline.json (3 opcodes, captured 2026-02-28 14:49:39 UTC)
────────────────────────────────────────────────────────
Opcode Baseline Current Diff % Change
────────────────────────────────────────────────────────
IncreaseCounter 1536 1398 -138 -9.0%
ResetCounter 1349 1349 +0 +0.0%
0x00000999 680 680 +0 +0.0%
CHAIN GAS & FEES SUMMARY COMPARISON
Baseline: gas-baseline.json (14 traces, captured 2026-02-28 14:49:39 UTC)
──────────────────────────────────────────────────────────────────────────────────
Test Traces Tx Gas Used Gas Fee Total Fee
──────────────────────────────────────────────────────────────────────────────────
test increase counter 4 4 2789 0.0011156 TON 0.0011156 TON
4 4 2651 0.0010604 TON 0.0010604 TON
-138 -0.0000552 TON -0.0000552 TON
test reset counter 5 5 4138 0.0016552 TON 0.0016552 TON
5 5 4000 0.0016 TON 0.0016 TON
-138 -0.0000552 TON -0.0000552 TON
test unknown message 5 5 2568 0.0010272 TON 0.0010272 TON CHAIN GAS & FEES · test increase counter
────────────────────────────────────────────────────────────────────────────────────────────
Trace Tx Count Gas Used Gas Fee Fwd Fee Total Fee
────────────────────────────────────────────────────────────────────────────────────────────
Trace 1 1 309 0.0001236 TON 0.000539205 TON 0.0001236 TON
Trace 2 1 309 0.0001236 TON 0.000547738 TON 0.0001236 TON
Trace 3 1 635 0.000254 TON 0.000646672 TON 0.000254 TON
1 635 0.000254 TON 0.000629605 TON 0.000254 TON
-0.000017067 TON
increase counter 1 1536 0.0006144 TON 0.000266669 TON 0.0006144 TON
1 1398 0.0005592 TON 0.000266669 TON 0.0005592 TON
-138 -0.0000552 TON -0.0000552 TONHow to read row groups
In comparison tables, changed chains are shown as baseline row, current row, and diff row.
Fail CI on drift
Use strict mode to return non-zero exit code when baseline and current profile differ:
acton test --baseline-snapshot gas-baseline.json --fail-on-diffTo enable it by default, set the fail-on-diff to true in the Acton.toml:
[test]
fail-on-diff = trueUpdate the baseline on purpose
If changes are expected, recreate baseline:
acton test --snapshot gas-baseline.jsonCompare mode does not overwrite snapshot
With both --snapshot and --baseline-snapshot, Acton runs in compare mode and does not rewrite the snapshot file.
Name trace chains for readable reports
Chain reports are much easier to read when traces have explicit names.
Use SendResultList.giveName(...) after net.send(...):
import "@acton/emulation/network"
get fun `test transfer flow`() {
// ...
val txs = net.send(sender.address, msg);
txs.giveName("transfer-wallet-to-wallet");
expect(txs).toHaveAllSuccessfulTxs();
}Without custom names, traces are shown as Trace 1, Trace 2, and so on.
How baseline matching works
Baseline comparison is key-based rather than fuzzy. Opcode rows are keyed by the resolved opcode label.
If ABI metadata resolves the opcode, the key is the message name such as IncreaseCounter. Otherwise, the key falls back to the raw hex opcode such as 0x00000999.
Trace-chain rows are keyed by a stable internal snapshot key:
<test-name>::trace#<1-based trace index>That key comes from the test name plus the 1-based position of the trace in that test's execution order. trace_name is stored only for display. Renaming a trace with giveName(...) makes reports easier to read, but it does not change how baseline matching works.
Read comparison output
In baseline comparison mode:
- New opcodes and traces are shown as
NEW - Higher usage is highlighted as regression
- Lower usage is highlighted as improvement
- Unchanged rows are dimmed
Stabilize test data first
For meaningful diffs, keep tests deterministic: use fixed inputs, stable send order, and no random or time-dependent behavior unless controlled explicitly.
Snapshot file format
Gas snapshot is stored as JSON with this high-level structure:
{
"timestamp": 1772290179,
"opcodes": {
"IncreaseCounter": {
"min_gas": 1536,
"max_gas": 1536,
"avg_gas": 1536,
"samples": 2,
"all_values": [1536, 1536]
}
},
"trace_chains": {
"test reset counter::trace#3": {
"test_name": "test reset counter",
"trace_name": "Trace 3",
"tx_count": 1,
"total_gas_used": 635,
"total_gas_fees": 254000,
"total_forward_fees": 646672,
"total_fees": 254000
}
}
}
Flags that pair well with profiling
# Profile only selected tests
acton test --filter "transfer.*" --snapshot gas-baseline.json
# Profile one suite/file
acton test tests/wallet.test.tolk --baseline-snapshot gas-baseline.jsonTroubleshooting
Snapshot file was not created
Snapshot is written only when:
--snapshotis set;--baseline-snapshotis not set;- selected tests passed;
- profiling collected at least one opcode or trace-chain metric.
Trace names changed but diff mapping is still stable
Trace comparison is matched by stable snapshot key, while trace_name is used for display: <test-name>::trace#<index>.
--fail-on-diff is stricter than the tables
The comparison tables mainly show aggregated numbers such as averages and fee totals. Strict drift detection compares the full snapshot content except for the top-level timestamp.
That means --fail-on-diff treats these as real drift:
- opcode sample-count changes
min_gas,max_gas, oravg_gaschanges- differences in per-opcode
all_values - per-trace
tx_countor fee changes - changed
trace_namefor the same snapshot key
For stable CI baselines, keep both the execution order and the profiled test data deterministic.
Last updated on