# Benchmarks and weights (/docs/internals/benchmarks-and-weights)

Every extrinsic in the runtime has a **weight** — a measure of the computational
resources it consumes. Weights are used to calculate transaction fees and to
prevent blocks from being overloaded.

Weights are defined in `weights.rs` files inside each pallet and are generated
by running benchmarks on reference hardware.

## Tools [#tools]

| Tool                       | Purpose                                                             |
| -------------------------- | ------------------------------------------------------------------- |
| `scripts/benchmark_all.sh` | Generate `weights.rs` for one or all pallets (runs real benchmarks) |
| `weight-compare`           | Compare two `weights.rs` files and report drift (used by CI)        |

`weight-compare` lives in `support/weight-tools/` and has no heavy dependencies
(no runtime build required).

## Adding a new pallet [#adding-a-new-pallet]

1. Write your benchmarks in `pallets/<name>/src/benchmarking.rs` using
   `#[benchmarks]` and `#[benchmark]` macros.

2. Create `pallets/<name>/src/weights.rs` manually. Copy the structure from
   any existing pallet (e.g. `pallets/drand/src/weights.rs`) and replace the
   function signatures with yours, using `Weight::from_parts(0, 0)` as the
   body so the pallet compiles immediately:

   ```rust
   pub trait WeightInfo {
       fn my_extrinsic() -> Weight;
   }

   pub struct SubstrateWeight<T>(PhantomData<T>);
   impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
       fn my_extrinsic() -> Weight {
           Weight::from_parts(0, 0)
       }
   }

   impl WeightInfo for () {
       fn my_extrinsic() -> Weight {
           Weight::from_parts(0, 0)
       }
   }
   ```

3. Add `pub mod weights;` to your pallet's `lib.rs`.

4. Add `type WeightInfo: crate::weights::WeightInfo;` to your pallet's
   `Config` trait.

5. Use `T::WeightInfo::extrinsic_name()` in `#[pallet::weight(...)]`
   annotations instead of hardcoded `Weight::from_parts(...)`.

6. Wire up in `runtime/src/lib.rs`:
   ```rust
   type WeightInfo = pallet_<name>::weights::SubstrateWeight<Runtime>;
   ```

7. Add `type WeightInfo = ();` to all test mocks implementing your pallet's
   `Config`.

8. Register the pallet in the `define_benchmarks!` macro in
   `runtime/src/lib.rs` so the benchmark runner can discover it:
   ```rust
   define_benchmarks!(
       // ...existing pallets...
       [pallet_<name>, PalletInstance]
   );
   ```

The benchmark scripts auto-discover pallets by scanning for directories under
`pallets/` that have `src/weights.rs` plus `src/benchmarking.rs` (or
`src/benchmarks.rs`), and that are registered in `define_benchmarks!`. No
manual registration in scripts is needed. Careful with step 8
(`define_benchmarks!`): an unregistered pallet is filtered out by discovery
and **silently skipped** in all-pallets mode and in CI; only the single-pallet
invocation (`./scripts/benchmark_all.sh pallet_<name>`) fails, with an
"unknown pallet" error.

CI will generate real weights automatically when the PR is opened.

## Adding a new extrinsic to an existing pallet [#adding-a-new-extrinsic-to-an-existing-pallet]

1. Write the benchmark in `benchmarking.rs`.

2. Add the function signature to the `WeightInfo` trait in `weights.rs`, and
   a `Weight::from_parts(0, 0)` body to both the `SubstrateWeight<T>` and
   `()` impls so the pallet continues to compile:

   ```rust
   // in trait WeightInfo:
   fn new_extrinsic() -> Weight;

   // in both impls:
   fn new_extrinsic() -> Weight {
       Weight::from_parts(0, 0)
   }
   ```

3. Add `#[pallet::weight(T::WeightInfo::new_extrinsic())]` to the extrinsic.

CI will generate real weights automatically when the PR is opened.

## Parameterized weights [#parameterized-weights]

For extrinsics whose cost scales with an input, use `Linear<min, max>`
parameters in the benchmark. You can use one or more parameters:

```rust
// Single parameter
#[benchmark]
fn refund(k: Linear<1, 100>) {
    // setup with k contributors...
    #[extrinsic_call]
    _(origin, crowdloan_id);
}

// Multiple parameters
#[benchmark]
fn transfer_batch(n: Linear<1, 256>, m: Linear<1, 64>) {
    // setup with n recipients and m tokens each...
    #[extrinsic_call]
    _(origin, recipients, amounts);
}
```

This generates weight functions with matching signatures:

```rust
fn refund(k: u32) -> Weight;
fn transfer_batch(n: u32, m: u32) -> Weight;
```

The generated weight includes base values plus per-parameter slope terms
(e.g., `base + slope_k * k` for single parameter, or
`base + slope_n * n + slope_m * m` for multiple). Reference them as:

```rust
#[pallet::weight(T::WeightInfo::refund(T::MaxContributors::get()))]
#[pallet::weight(T::WeightInfo::transfer_batch(recipients.len() as u32, max_tokens))]
```

## CI workflow [#ci-workflow]

The `Validate-Benchmarks` workflow (`.github/workflows/run-benchmarks.yml`)
runs on every PR:

1. Builds the node with `--features runtime-benchmarks`
2. Runs benchmarks for every pallet, generating new `weights.rs` to temp files
3. Uses `weight-compare` to compare old vs new values with a **40% threshold**
   * Base weight: threshold-based (allows measurement noise)
   * Reads/writes: exact match (these are deterministic)
   * Component slopes: threshold-based for weights, exact for reads/writes
4. If drift is detected, prepares a patch in `.bench_patch/`
5. Adding the `apply-benchmark-patch` label auto-applies the patch

To skip benchmarks on a PR, add the `skip-validate-benchmarks` label. This can
be added at any point during the job — it's checked between expensive steps.

## Running benchmarks locally [#running-benchmarks-locally]

```sh
# Build + generate weights for all pallets
./scripts/benchmark_all.sh

# Build + generate weights for a single pallet
./scripts/benchmark_all.sh pallet_subtensor

# Run benchmark unit tests (fast, no real measurements — just checks setup)
cargo test -p pallet-subtensor --features runtime-benchmarks benchmarks

# Compare two weight files
cargo run -p subtensor-weight-tools --bin weight-compare -- \
  --old pallets/foo/src/weights.rs \
  --new /tmp/new_weights.rs \
  --threshold 40
```

## Weight file structure [#weight-file-structure]

Generated `weights.rs` files contain:

* `WeightInfo` trait — one function per benchmarked extrinsic
* `SubstrateWeight<T>` impl — used in the runtime, references `T::DbWeight`
* `()` impl — used in tests, references `RocksDbWeight`

The `()` fallback uses `RocksDbWeight` constants directly. The production
runtime uses `T::DbWeight::get()`, which `runtime/src/lib.rs` also configures
as `type DbWeight = RocksDbWeight` (matching the node's default RocksDb
backend), so in this repo both impls resolve to the same constants.

The files are generated by the `frame-benchmarking-cli` using the Handlebars
template at `.maintain/frame-weight-template.hbs`.
