Skip to content

Bags-list on_idle: per-item weight consumption via WeightMeter#11594

Merged
sigurpol merged 18 commits intomasterfrom
sigurpol-bag-list-better-on-idle-benchmark
Apr 3, 2026
Merged

Bags-list on_idle: per-item weight consumption via WeightMeter#11594
sigurpol merged 18 commits intomasterfrom
sigurpol-bag-list-better-on-idle-benchmark

Conversation

@sigurpol
Copy link
Copy Markdown
Contributor

@sigurpol sigurpol commented Apr 1, 2026

The benchmark failed depending on MaxAutoRebagPerBlock (e.g. it passes with 10 as configured in Westend, Polkadot and Kusama AH runtime but it failed with 5, as it was configured before, see runtime PR).

Replace the bulk on_idle benchmark with a per-item on_idle_rebag benchmark that measures the worst-case cost of a single rebag. on_idle now consumes weight per iteration via WeightMeter instead of reserving a single bulk weight upfront.
This decouples the benchmark from MaxAutoRebagPerBlock. Changing the config no longer requires re-running benchmarks.

… values

The benchmark failed with MaxAutoRebagPerBlock=5 because:
- pending_count = 5/3 = 1, and the i%7 score skip hit the only pending node
- the scoreless node took the cheapest rebag_internal path (early error return)
  while still consuming budget, leaving fewer successful rebags than expected
- the exact-count assertion broke since it also counted pre-existing nodes in
  higher bags, making the result depend on the budget-to-distribution ratio

Fix by placing all regular nodes in the lowest bag and setting scores for all
pending nodes. This makes the count deterministic (only on_idle moves nodes into
higher bags) and exercises worst-case weight (every node triggers a full rebag).

Tested with MaxAutoRebagPerBlock = 3, 5, and 10.
@sigurpol sigurpol requested a review from a team as a code owner April 1, 2026 08:36
@sigurpol sigurpol added the T12-benchmarks This PR/Issue is related to benchmarking and weights. label Apr 1, 2026
@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 1, 2026

/cmd prdoc --audience runtime_dev --bump none

@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 1, 2026

/cmd bench --pallet pallet_bags_list --runtime asset-hub-westend

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

Command "bench --pallet pallet_bags_list --runtime asset-hub-westend" has started 🚀 See logs here

github-actions Bot and others added 3 commits April 1, 2026 08:40
Exercises the benchmark setup with MaxAutoRebagPerBlock = 1, 2, 3, 5, 7,
10, 15, 20 to ensure deterministic results regardless of budget value.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

Command "bench --pallet pallet_bags_list --runtime asset-hub-westend" has finished ✅ See logs here

Details

Subweight results:
File Extrinsic Old New Change [%]
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_terminal 884.98us 1.10ms +24.53
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_non_terminal 886.55us 1.10ms +23.95
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs on_idle 9.22ms 11.04ms +19.75
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs put_in_front_of 1.08ms 1.27ms +17.60
Command output:

✅ Successful benchmarks of runtimes/pallets:
-- asset-hub-westend: ['pallet_bags_list']

// Ensure we have at least three bags populated before rebag
assert!(List::<T, _>::get_bags().len() >= 2);
// All regular nodes are in the lowest bag; pending nodes are not yet in the list.
assert_eq!(List::<T, _>::get_bags().len(), 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems correct, but wondering why was the old test set up that way? Is having multiple bags worse than having one bag for this benchmark? Same question about simulating the cleanup scenario.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting all nodes in a single (lowest) bag is actually the worst case for rebag_internal when it hits the (true, Some(current_score)) path at https://github.com/paritytech/polkadot-sdk/blob/sigurpol-bag-list-better-on-idle-benchmark/substrate/frame/bags-list/src/lib.rs#L639-L639 and do_rebag has to:

  1. Nuke the node from the old bag (update prev/next pointers, possibly
    update bag head/tail)
  2. Insert it into a new, possibly not-yet-existing destination bag

If nodes were already spread across multiple bags, some would already be in their correct bag and do_rebag would be a no-op (score matches current bag).

The point here is to have a worst case scenario but also something robust meaning not depending by MaxAutoRebagPerBlock value and something where we can exact assertion and not >= as before

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the former cleanup scenarios, I think it was not an accurate comment either - the benchmark doesn't simulate one or any corruption in the (unchanged) lines of code https://github.com/paritytech/polkadot-sdk/blob/sigurpol-bag-list-better-on-idle-benchmark/substrate/frame/bags-list/src/benchmarks.rs#L380-L382
List::remove fully removes the node from both the bag and ListNodes. After removal, these nodes won't appear in Self::iter() (which iterates the linked list via bags) , in ListNodes storage or in PendingRebag - but it's just a proper cleanup. There is no orphan. I think we can just remove these cleanup lines imho

let regular_count = rebag_budget + 5;

// Insert regular nodes with varying scores
// Insert all regular nodes into the lowest bag. This is worst-case: every node
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dumb question: wouldn't it be better if this was benching weight of one worse case rebag, and then on_idle can consume items * weight_one_rebag? So we only need to bench for one item and it does not change based on MaxAutoRebagPerBlock?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a dumb question at all - I think it's actually a better design 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and I could get rid of rebags_exactly_budget_nodes_regardless_of_budget_size - lemme

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 2, 2026

/cmd bench --pallet pallet_bags_list --runtime asset-hub-westend

@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 2, 2026

/cmd bench --pallet pallet_bags_list --runtime dev

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime asset-hub-westend" has started 🚀 See logs here

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime dev" has started 🚀 See logs here

@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 2, 2026

/cmd bench --pallet pallet_bags_list --runtime pallet-staking-async-parachain-runtime

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime pallet-staking-async-parachain-runtime" has started 🚀 See logs here

@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 2, 2026

/cmd bench --pallet pallet_bags_list --runtime westend

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime westend" has started 🚀 See logs here

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime pallet-staking-async-parachain-runtime" has failed ❌! See logs here

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime asset-hub-westend" has finished ✅ See logs here

Details

Subweight results:
File Extrinsic Old New Change [%]
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_terminal 884.98us 1.10ms +24.75
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_non_terminal 886.55us 1.10ms +24.57
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs put_in_front_of 1.08ms 1.27ms +17.29
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs on_idle_rebag 1.24ms Added
substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
substrate/frame/bags-list/src/weights.rs on_idle_rebag 0ps Added
polkadot/runtime/westend/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
Command output:

✅ Successful benchmarks of runtimes/pallets:
-- asset-hub-westend: ['pallet_bags_list']

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime westend" has finished ✅ See logs here

Details

Subweight results:
File Extrinsic Old New Change [%]
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_terminal 884.98us 1.10ms +24.53
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_non_terminal 886.55us 1.10ms +23.95
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs put_in_front_of 1.08ms 1.27ms +17.60
polkadot/runtime/westend/src/weights/pallet_bags_list.rs rebag_non_terminal 773.74us 904.91us +16.95
polkadot/runtime/westend/src/weights/pallet_bags_list.rs rebag_terminal 771.83us 902.50us +16.93
polkadot/runtime/westend/src/weights/pallet_bags_list.rs on_idle_rebag 1.03ms Added
substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
substrate/frame/bags-list/src/weights.rs on_idle_rebag 0ps Added
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
Command output:

✅ Successful benchmarks of runtimes/pallets:
-- westend: ['pallet_bags_list']

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Command "bench --pallet pallet_bags_list --runtime dev" has finished ✅ See logs here

Details

Subweight results:
File Extrinsic Old New Change [%]
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_terminal 884.98us 1.10ms +24.53
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs rebag_non_terminal 886.55us 1.10ms +23.95
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs put_in_front_of 1.08ms 1.27ms +17.60
substrate/frame/bags-list/src/weights.rs rebag_terminal 800.02us 905.04us +13.13
substrate/frame/bags-list/src/weights.rs rebag_non_terminal 802.68us 906.00us +12.87
substrate/frame/bags-list/src/weights.rs on_idle_rebag 1.03ms Added
substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
polkadot/runtime/westend/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_bags_list.rs on_idle_rebag 0ps Added
Command output:

✅ Successful benchmarks of runtimes/pallets:
-- dev: ['pallet_bags_list']

@andreitrand
Copy link
Copy Markdown
Contributor

I suggest also updating the PR's description to include the fact that you now benchmark only a single worst-case rebag and the weight no longer depends on MaxAutoRebagPerBlock.

@sigurpol sigurpol changed the title Fix bags-list on_idle benchmark fragility across MaxAutoRebagPerBlock values Bags-list on_idle: per-item weight consumption via WeightMeter Apr 2, 2026
@sigurpol
Copy link
Copy Markdown
Contributor Author

sigurpol commented Apr 2, 2026

I suggest also updating the PR's description to include the fact that you now benchmark only a single worst-case rebag and the weight no longer depends on MaxAutoRebagPerBlock.

Good point, done

assert_ok!(List::<T, _>::insert(node.clone(), score));
}
let origin_bag_thresh = T::BagThresholds::get()[0];
let dest_bag_thresh = T::BagThresholds::get()[1];
Copy link
Copy Markdown
Contributor

@andreitrand andreitrand Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: While I understand that in practice all tested runtimes have at least 2 bags, the documentation from substrate/frame/bags-list/src/lib.rs:220 indicates that it is possible for T::BagThresholds::get() to be empty. I suggest guarding against this scenario here (like asserting the size to be at least 2 etc.).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an assertion

@sigurpol sigurpol enabled auto-merge April 3, 2026 07:36
@sigurpol sigurpol added this pull request to the merge queue Apr 3, 2026
Merged via the queue into master with commit ba06ae6 Apr 3, 2026
326 of 349 checks passed
@sigurpol sigurpol deleted the sigurpol-bag-list-better-on-idle-benchmark branch April 3, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T12-benchmarks This PR/Issue is related to benchmarking and weights.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants