# Gas statistics for your test runs

Description: How to get gas statistics from your test runs

Note: This document was authored using MDX

  Source: https://github.com/NomicFoundation/hardhat-website/tree/main/src/content/docs/docs/guides/testing/gas-statistics.mdx

  Components used in this page:
    - <Run cmd="..."/>: Runs a command in the terminal with npm/pnpm/yarn.

import Run from "@hh/Run.astro";

Hardhat can optionally show statistics on the gas consumed by your contracts' public functions during a test run. Use the `--gas-stats` flag when running your tests to display this information.

## Getting gas statistics from your tests

You can pass the `--gas-stats` flag to either the `test` task or to one of its subtasks (e.g., `test solidity`):

<Run
  command={[
    "hardhat test --gas-stats",
    "hardhat test solidity --gas-stats",
    "hardhat test nodejs --gas-stats",
  ]}
/>

This prints a table like the following:

```
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║                                  Gas Usage Statistics                                 ║
╚═══════════════════════════════════════════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ contracts/Calculator.sol:Calculator                                                   ║
╟───────────────────────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name                     │ Min    │ Average │ Median │ Max    │ #calls       ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ divide                            │ 44316  │ 44316   │ 44316  │ 44316  │ 1            ║
║ multiply(uint256,uint256)         │ 44254  │ 44254   │ 44254  │ 44254  │ 2            ║
║ multiply(uint256,uint256,uint256) │ 44875  │ 44875   │ 44875  │ 44875  │ 1            ║
║ reset                             │ 21485  │ 21485   │ 21485  │ 21485  │ 1            ║
║ result                            │ 23510  │ 23510   │ 23510  │ 23510  │ 6            ║
║ subtract                          │ 44213  │ 44213   │ 44213  │ 44213  │ 1            ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment                        │ Min    │ Average │ Median │ Max    │ #deployments ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║                                   │ 288115 │ 288115  │ 288115 │ 288115 │ 1            ║
╟───────────────────────────────────┼────────┼─────────┴────────┴────────┴──────────────╢
║ Bytecode size                     │ 2294   │                                          ║
╚═══════════════════════════════════╧════════╧══════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ contracts/Counter.sol:Counter                                                         ║
╟───────────────────────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name                     │ Min    │ Average │ Median │ Max    │ #calls       ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ add(uint256)                      │ 43915  │ 43915   │ 43915  │ 43915  │ 1            ║
║ add(uint256,bool)                 │ 44284  │ 44419   │ 44419  │ 44554  │ 2            ║
║ inc                               │ 43482  │ 43482   │ 43482  │ 43482  │ 1            ║
║ x                                 │ 23466  │ 23466   │ 23466  │ 23466  │ 5            ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment                        │ Min    │ Average │ Median │ Max    │ #deployments ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║                                   │ 234940 │ 234940  │ 234940 │ 234940 │ 1            ║
╟───────────────────────────────────┼────────┼─────────┴────────┴────────┴──────────────╢
║ Bytecode size                     │ 1462   │                                          ║
╚═══════════════════════════════════╧════════╧══════════════════════════════════════════╝
```

The statistics are collected from the functions called by the tests you executed. This means that running `test solidity --gas-stats` will produce a different result than running `test nodejs --gas-stats`, because different tests will have been run.

## Exporting gas statistics to a JSON file

To save gas statistics to a JSON file, pass the `--gas-stats-json <path>` flag:

<Run
  command={[
    "hardhat test --gas-stats-json gas-stats.json",
    "hardhat test solidity --gas-stats-json gas-stats.json",
    "hardhat test nodejs --gas-stats-json gas-stats.json",
  ]}
/>

This flag works independently of `--gas-stats`, so either or both can be used together. For example, to print the table to the terminal and also save the results to a file:

<Run command="hardhat test --gas-stats --gas-stats-json gas-stats.json" />

The JSON file has the following structure:

```json
{
  "contracts": {
    "contracts/Calculator.sol:Calculator": {
      "sourceName": "contracts/Calculator.sol",
      "contractName": "Calculator",
      "proxyChain": [],
      "deployment": {
        "min": 288115,
        "max": 288115,
        "avg": 288115,
        "median": 288115,
        "count": 1,
        "runtimeSize": 2294
      },
      "functions": {
        "divide": {
          "min": 44316,
          "max": 44316,
          "avg": 44316,
          "median": 44316,
          "count": 1
        },
        "multiply(uint256,uint256)": {
          "min": 44254,
          "max": 44254,
          "avg": 44254,
          "median": 44254,
          "count": 2
        }
        // ...
      }
    },
    "contracts/Counter.sol:Counter": {
      "sourceName": "contracts/Counter.sol",
      "contractName": "Counter",
      "proxyChain": [],
      "deployment": {
        "min": 234940,
        "max": 234940,
        "avg": 234940,
        "median": 234940,
        "count": 1,
        "runtimeSize": 1462
      },
      "functions": {
        "add(uint256)": {
          "min": 43915,
          "max": 43915,
          "avg": 43915,
          "median": 43915,
          "count": 1
        },
        "add(uint256,bool)": {
          "min": 44284,
          "max": 44554,
          "avg": 44419,
          "median": 44419,
          "count": 2
        }
        // ...
      }
    },
    "contracts/Counter.sol:Counter (via contracts/Proxy.sol:Proxy)": {
      "sourceName": "contracts/Counter.sol",
      "contractName": "Counter",
      "proxyChain": [
        "contracts/Proxy.sol:Proxy",
        "contracts/Counter.sol:Counter"
      ],
      "deployment": null,
      "functions": {
        "add(uint256)": {
          "min": 45100,
          "max": 45100,
          "avg": 45100,
          "median": 45100,
          "count": 1
        }
        // ...
      }
    }
  }
}
```

### Understanding the JSON structure

Each key in the `contracts` object is a display label. For direct calls, the label is `sourceName:contractName` (e.g. `contracts/Counter.sol:Counter`). For proxied calls, it is suffixed with the proxy chain: `contracts/Counter.sol:Counter (via contracts/Proxy.sol:Proxy)`. These labels are meant for display; for programmatic use, rely on `sourceName`, `contractName`, and `proxyChain` instead.

Each contract entry contains:

- **`sourceName`** and **`contractName`**: the source file path and the contract name of the implementation contract.
- **`proxyChain`**: an empty array `[]` for direct calls. For proxied calls, it lists each contract the call passed through, with proxies first and the implementation contract last.
- **`deployment`**: gas statistics for deploying the contract, including `runtimeSize` (the deployed bytecode size in bytes). This is `null` when the contract was not directly deployed during the test run.
- **`functions`**: a map of function signatures to their gas statistics, or `null` if no functions were called.

When a contract is called both directly and through a proxy, it appears as separate entries, one without a proxy suffix (for the direct call) and one with it (for the proxied call).

## Understanding the gas statistics

The gas statistics table shows the following information for each function and deployment:

- **count**: Number of times the function was called or the contract was deployed
- **min**: Minimum gas consumed in a single call
- **max**: Maximum gas consumed in a single call
- **avg**: Average gas consumed across all calls
- **median**: Median gas consumed across all calls

The deployment section also includes a **Bytecode size** row showing the contract's runtime bytecode size in bytes. This is the size of the code stored on-chain after deployment.

### Functions included in gas statistics

Gas statistics only include public functions that are called directly by your tests. If a public function is called by another function but not directly by a test, it won't be included in the statistics.

For example, consider this contract:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Counter {
  uint256 public count;

  function inc() public {
    _incInternal();
  }

  function _incInternal() private {
    count++;
  }

  function incBy(uint256 value) public {
    count += value;
  }

  function reset() public {
    count = 0;
  }
}
```

And this test:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Counter.sol";

contract CounterTest {
  Counter counter;

  function setUp() public {
    counter = new Counter();
  }

  function testInc() public {
    counter.inc();
  }

  function testIncBy() public {
    counter.incBy(5);
  }
}
```

The output will be:

```
╔═════════════════════════════════════════════════════════════════════╗
║                        Gas Usage Statistics                         ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ contracts/Counter.sol:Counter                                       ║
╟─────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name   │ Min    │ Average │ Median │ Max    │ #calls       ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ inc             │ 43484  │ 43484   │ 43484  │ 43484  │ 1            ║
║ incBy           │ 43937  │ 43937   │ 43937  │ 43937  │ 1            ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment      │ Min    │ Average │ Median │ Max    │ #deployments ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║                 │ 179915 │ 179915  │ 179915 │ 179915 │ 1            ║
╟─────────────────┼────────┼─────────┴────────┴────────┴──────────────╢
║ Bytecode size   │ 1462   │                                          ║
╚═════════════════╧════════╧══════════════════════════════════════════╝
```

The statistics include `inc` and `incBy` because they're called directly by the tests. The `reset()` function doesn't appear because it's never called by the tests. The `_incInternal()` function doesn't appear because it's private and only called by `inc()`, not directly by the tests.
