Profiling a Transaction’s Gas
Gas profiling needs a Supra CLI and an RPC node from v12.0.0 on. It is available on Devnet only.
It is not yet on Testnet or Mainnet.
--profile-gas reports where a Move transaction’s gas goes, without submitting it. The RPC node
simulates the transaction under a gas profiler, and the CLI writes an HTML report of the gas each
call, operation and storage write took.
Profile a transaction
supra move tool run, supra move tool run-script and supra move tool publish take
--profile-gas. Add it to the command that would send the transaction:
supra move tool run --function-id '<ADDRESS>::<MODULE>::<FUNCTION>' --args <ARGS> --profile-gassupra move tool publish --package-dir <PACKAGE_DIR> --profile-gasThe transaction is never submitted, and nothing on chain changes. The CLI signs it as
--simulate does, with a signature that does not verify, so it does not read the profile’s private
key. --profile-gas cannot be combined with --simulate.
Gas is chosen as for --simulate: --gas-unit-price and --max-gas if given, otherwise the node’s
gas price estimate and the most gas the sender’s balance pays for. The sender’s account must exist
on chain, so fund it first, for example from the faucet.
The command prints the height of the state the node simulated against, the gas used and how the transaction ended, then the report’s directory:
Profiled on the RPC node against the state at height <HEIGHT>: gas_used=<GAS>, status=success
Gas report saved to gas-profiling/txn-<SENDER>-<SEQUENCE_NUMBER>-<PAYLOAD>-<NANOS>With supra --stdout json, the result is
{"GasProfile": {"state_height": …, "outcome": …, "gas_used": …, "report_dir": …}}.
The report
The report is written to gas-profiling/txn-<SENDER>-<SEQUENCE_NUMBER>-<PAYLOAD>-<NANOS>/ under the
directory the command runs in. <PAYLOAD> names the entry function’s address, module and function,
or is script. In the Supra CLI’s Docker container, run the command from
/supra/move_workspace, which is bind mounted from the host, to open the report on the host.
The directory holds:
| File | Contents |
|---|---|
index.html | The report. Open it in a browser. It has a Summary of the totals, the flame graphs, and the tables Execution and IO by operation, Execution and IO by call and Storage. |
execution-and-io.svg | A flame graph of execution and IO gas by call. Written when the transaction used execution or IO gas. |
storage.svg | A flame graph of the storage fee by write. Written when the transaction paid a storage fee. |
Execution and IO gas is counted in internal gas units, which the tables show converted to gas units. The flame graphs count internal gas units, and the report states how many make one gas unit. Storage fees and refunds are in quants.
Calls with the same name under the same parent are shown as one entry. The node bounds the size of a profile, so a large transaction’s report can contain:
(other)entries, which hold the gas of calls, operations or writes that did not fit in the profile. Totals are the same with or without them.- names cut short and ending with
…; (unnamed type)in place of a type the VM could not name.
A transaction that does not succeed
A transaction that would abort, run out of gas or be discarded is still profiled, and its report is written. The command then exits with a failure status, and its error says how the transaction ended and where the report is:
Command Aborted Reason(The transaction did not succeed when the RPC node simulated it against the state at height <HEIGHT>. Status: failed: Move abort with code <CODE> in <ADDRESS>::<MODULE>. Gas used: <GAS>), Action(Read the gas report saved to gas-profiling/txn-<SENDER>-<SEQUENCE_NUMBER>-<PAYLOAD>-<NANOS>)The status is failed: out of gas, failed: Move abort with code <CODE> in <LOCATION>,
failed: execution failure at code offset <OFFSET> of function <FUNCTION> in <LOCATION>,
discarded: <STATUS_CODE> or retry.
When the command fails without a report
| Cause | What the CLI reports |
|---|---|
The RPC node does not serve gas profiles: it answered 404 or 405. | <NODE> answered <STATUS> for POST <PATH>: the node does not serve gas profiles. It runs a release without the gas-profile endpoint, or its operator has not enabled it (rest_limits.gas_profile.enabled) |
| The transaction is a multisig transaction. Nothing is sent. | --profile-gas cannot profile a multisig payload; it profiles entry functions, scripts and automation registrations |
The node answered 400 or 413, or a proxy in front of it answered 503. | <NODE> did not profile the transaction (<STATUS>): <REASON> |
413 means the transaction is over the node’s request body size limit.
Serving gas profiles from an RPC node
An RPC node serves gas profiles at POST /rpc/v4/transactions/simulate/gas-profile only when its
config.toml enables them. The endpoint is off by default; while it is off, the route is not
registered, a request is answered 404, and the node’s OpenAPI document leaves it out.
# config.toml
[rest_limits.gas_profile]
enabled = true
max_tree_nodes = 4096
max_operation_rows = 1024
max_name_bytes = 256| Setting | Default | Accepted | Bounds |
|---|---|---|---|
enabled | false | Whether the route is registered. | |
max_tree_nodes | 4096 | 19 to 4294967295 | Nodes the two cost trees of one profile hold together. A call or write that does not fit is counted in an (other) node. |
max_operation_rows | 1024 | 5 to 4294967295 | Rows of one profile’s operation table. An operation that does not fit is counted in its kind’s (other) row. |
max_name_bytes | 256 | 17 to 16777216 | Length of one name in a profile, as JSON. A longer name is cut. |
A node started with a value outside its accepted range refuses the configuration and names the field. The three limits together bound the memory one profile holds, and a node whose limits would let one profile hold more than 64 MiB does not start. The defaults allow about 5.4 MiB.
A profile runs on the blocking workers that simulation, views and transaction lookups share, under
their permits, and its work is bounded by the gas limits its simulation runs under. The node counts
requests in the metric rpc.gas_profile_requests, by outcome (served, refused or failed),
and measures the profiles it serves with rpc.gas_profile_duration and
rpc.gas_profile_response_bytes.
The request and response are described under the endpoint on the node’s API page, for Devnet https://rpc-devnet.supra.com/docs .