diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 440d549af1a3568db0884bdf77ec1c2a49c7c30f..2fa738118247e8b93c449376e11f9be3319c724a 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -4998,6 +4998,7 @@ dependencies = [
  "pallet-conviction-voting",
  "pallet-democracy",
  "pallet-election-provider-multi-phase",
+ "pallet-election-provider-support-benchmarking",
  "pallet-elections-phragmen",
  "pallet-gilt",
  "pallet-grandpa",
@@ -5851,6 +5852,7 @@ dependencies = [
  "frame-system",
  "log 0.4.14",
  "pallet-balances",
+ "pallet-election-provider-support-benchmarking",
  "parity-scale-codec",
  "parking_lot 0.12.0",
  "rand 0.7.3",
@@ -5866,6 +5868,18 @@ dependencies = [
  "strum",
 ]
 
+[[package]]
+name = "pallet-election-provider-support-benchmarking"
+version = "4.0.0-dev"
+dependencies = [
+ "frame-benchmarking",
+ "frame-election-provider-support",
+ "frame-system",
+ "parity-scale-codec",
+ "sp-npos-elections",
+ "sp-runtime",
+]
+
 [[package]]
 name = "pallet-elections-phragmen"
 version = "5.0.0-dev"
diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml
index 45df7258ef253db6c804848780bd04436353b1c2..c281913cd55edc34df6e59fe74d94c42dbc33ef8 100644
--- a/substrate/Cargo.toml
+++ b/substrate/Cargo.toml
@@ -87,6 +87,7 @@ members = [
 	"frame/try-runtime",
 	"frame/election-provider-multi-phase",
 	"frame/election-provider-support",
+	"frame/election-provider-support/benchmarking",
 	"frame/election-provider-support/solution-type",
 	"frame/election-provider-support/solution-type/fuzzer",
 	"frame/examples/basic",
diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml
index 686508b47dba14343f49e1a852c3ede7e7e52d22..41b2402d33a536793481ff5f363a20e00a9f8e3e 100644
--- a/substrate/bin/node/runtime/Cargo.toml
+++ b/substrate/bin/node/runtime/Cargo.toml
@@ -65,6 +65,7 @@ pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = f
 pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" }
 pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" }
 pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" }
+pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true }
 pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" }
 pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" }
 pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" }
@@ -196,6 +197,7 @@ runtime-benchmarks = [
 	"pallet-conviction-voting/runtime-benchmarks",
 	"pallet-democracy/runtime-benchmarks",
 	"pallet-election-provider-multi-phase/runtime-benchmarks",
+	"pallet-election-provider-support-benchmarking/runtime-benchmarks",
 	"pallet-elections-phragmen/runtime-benchmarks",
 	"pallet-gilt/runtime-benchmarks",
 	"pallet-grandpa/runtime-benchmarks",
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index f422d1ffc45b8e1835a744b88d5f2e251cd79372..f37345014f3a15a2f2bbf0d232ca0c86ef1e87cf 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -643,17 +643,18 @@ impl Get<Option<(usize, ExtendedBalance)>> for OffchainRandomBalancing {
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Runtime;
 	type Solver = SequentialPhragmen<
 		AccountId,
 		pallet_election_provider_multi_phase::SolutionAccuracyOf<Runtime>,
 	>;
 	type DataProvider = <Runtime as pallet_election_provider_multi_phase::Config>::DataProvider;
+	type WeightInfo = frame_election_provider_support::weights::SubstrateWeight<Runtime>;
 }
 
-impl onchain::BoundedExecutionConfig for OnChainSeqPhragmen {
-	type VotersBound = ConstU32<20_000>;
+impl onchain::BoundedConfig for OnChainSeqPhragmen {
+	type VotersBound = MaxElectingVoters;
 	type TargetsBound = ConstU32<2_000>;
 }
 
@@ -1531,6 +1532,7 @@ mod benches {
 		[pallet_contracts, Contracts]
 		[pallet_democracy, Democracy]
 		[pallet_election_provider_multi_phase, ElectionProviderMultiPhase]
+		[pallet_election_provider_support_benchmarking, EPSBench::<Runtime>]
 		[pallet_elections_phragmen, Elections]
 		[pallet_gilt, Gilt]
 		[pallet_grandpa, Grandpa]
@@ -1851,6 +1853,7 @@ impl_runtime_apis! {
 			// which is why we need these two lines below.
 			use pallet_session_benchmarking::Pallet as SessionBench;
 			use pallet_offences_benchmarking::Pallet as OffencesBench;
+			use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
 			use frame_system_benchmarking::Pallet as SystemBench;
 			use baseline::Pallet as BaselineBench;
 
@@ -1872,11 +1875,13 @@ impl_runtime_apis! {
 			// which is why we need these two lines below.
 			use pallet_session_benchmarking::Pallet as SessionBench;
 			use pallet_offences_benchmarking::Pallet as OffencesBench;
+			use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
 			use frame_system_benchmarking::Pallet as SystemBench;
 			use baseline::Pallet as BaselineBench;
 
 			impl pallet_session_benchmarking::Config for Runtime {}
 			impl pallet_offences_benchmarking::Config for Runtime {}
+			impl pallet_election_provider_support_benchmarking::Config for Runtime {}
 			impl frame_system_benchmarking::Config for Runtime {}
 			impl baseline::Config for Runtime {}
 
diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs
index 37d8e9e37a5f490b10cc88216e60ad5f5e0aef4a..15f53e7da08239924ee9e4ce92ca7417ee7de444 100644
--- a/substrate/frame/babe/src/mock.rs
+++ b/substrate/frame/babe/src/mock.rs
@@ -173,10 +173,11 @@ parameter_types! {
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Test;
 	type Solver = SequentialPhragmen<DummyValidatorId, Perbill>;
 	type DataProvider = Staking;
+	type WeightInfo = ();
 }
 
 impl pallet_staking::Config for Test {
diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml
index 25f98d965d86b7f14e3327a4d2a711c31459b643..48134966a925319d61bdd84ec219e3417749310c 100644
--- a/substrate/frame/election-provider-multi-phase/Cargo.toml
+++ b/substrate/frame/election-provider-multi-phase/Cargo.toml
@@ -17,7 +17,9 @@ static_assertions = "1.1.0"
 codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [
 	"derive",
 ] }
-scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = [
+	"derive",
+] }
 log = { version = "0.4.14", default-features = false }
 
 frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
@@ -33,11 +35,14 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa
 
 # Optional imports for benchmarking
 frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true }
+pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support/benchmarking", optional = true }
 rand = { version = "0.7.3", default-features = false, optional = true, features = [
 	"alloc",
 	"small_rng",
 ] }
-strum = { optional = true, default-features = false, version = "0.23.0", features = ["derive"] }
+strum = { optional = true, default-features = false, version = "0.23.0", features = [
+	"derive",
+] }
 
 [dev-dependencies]
 parking_lot = "0.12.0"
@@ -46,7 +51,6 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive
 sp-io = { version = "6.0.0", path = "../../primitives/io" }
 sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" }
 sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" }
-frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" }
 pallet-balances = { version = "4.0.0-dev", path = "../balances" }
 frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" }
 
diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs
index d6f040363dba0b82cd7f3d4c982aae39787304b6..7c06ff6bee546932bab74ba675fd4aa90494f848 100644
--- a/substrate/frame/election-provider-multi-phase/src/mock.rs
+++ b/substrate/frame/election-provider-multi-phase/src/mock.rs
@@ -276,10 +276,11 @@ parameter_types! {
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Runtime;
 	type Solver = SequentialPhragmen<AccountId, SolutionAccuracyOf<Runtime>, Balancing>;
 	type DataProvider = StakingMock;
+	type WeightInfo = ();
 }
 
 pub struct MockFallback;
@@ -304,7 +305,7 @@ impl InstantElectionProvider for MockFallback {
 				max_voters,
 				max_targets,
 			)
-			.map_err(|_| "UnboundedExecution failed")
+			.map_err(|_| "onchain::UnboundedExecution failed.")
 		} else {
 			super::NoFallback::<Runtime>::elect_with_bounds(max_voters, max_targets)
 		}
diff --git a/substrate/frame/election-provider-support/benchmarking/Cargo.toml b/substrate/frame/election-provider-support/benchmarking/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e9719be139a6d21fa194facdce4dd9a66f2143ce
--- /dev/null
+++ b/substrate/frame/election-provider-support/benchmarking/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "pallet-election-provider-support-benchmarking"
+version = "4.0.0-dev"
+authors = ["Parity Technologies <admin@parity.io>"]
+edition = "2021"
+license = "Apache-2.0"
+homepage = "https://substrate.io"
+repository = "https://github.com/paritytech/substrate/"
+description = "Benchmarking for election provider support onchain config trait"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [
+	"derive",
+] }
+sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" }
+sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" }
+frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" }
+frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." }
+frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true }
+
+
+[features]
+default = ["std"]
+std = [
+	"codec/std",
+	"sp-npos-elections/std",
+	"sp-runtime/std",
+	"frame-benchmarking/std",
+	"frame-system/std",
+]
+
+runtime-benchmarks = [
+	"frame-benchmarking/runtime-benchmarks",
+	"frame-election-provider-support/runtime-benchmarks",
+]
diff --git a/substrate/frame/election-provider-support/benchmarking/src/lib.rs b/substrate/frame/election-provider-support/benchmarking/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..547e35bed36e8e6adfeef40e90e3863ddae38463
--- /dev/null
+++ b/substrate/frame/election-provider-support/benchmarking/src/lib.rs
@@ -0,0 +1,91 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Election provider support pallet benchmarking.
+//! This is separated into its own crate to avoid bloating the size of the runtime.
+
+#![cfg(feature = "runtime-benchmarks")]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use codec::Decode;
+use frame_benchmarking::{benchmarks, Vec};
+use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen};
+
+pub struct Pallet<T: Config>(frame_system::Pallet<T>);
+pub trait Config: frame_system::Config {}
+
+const VOTERS: [u32; 2] = [1_000, 2_000];
+const TARGETS: [u32; 2] = [500, 1_000];
+const VOTES_PER_VOTER: [u32; 2] = [5, 16];
+
+const SEED: u32 = 999;
+fn set_up_voters_targets<AccountId: Decode + Clone>(
+	voters_len: u32,
+	targets_len: u32,
+	degree: usize,
+) -> (Vec<(AccountId, u64, impl IntoIterator<Item = AccountId>)>, Vec<AccountId>) {
+	// fill targets.
+	let mut targets = (0..targets_len)
+		.map(|i| frame_benchmarking::account::<AccountId>("Target", i, SEED))
+		.collect::<Vec<_>>();
+	assert!(targets.len() > degree, "we should always have enough voters to fill");
+	targets.truncate(degree);
+
+	// fill voters.
+	let voters = (0..voters_len)
+		.map(|i| {
+			let voter = frame_benchmarking::account::<AccountId>("Voter", i, SEED);
+			(voter, 1_000, targets.clone())
+		})
+		.collect::<Vec<_>>();
+
+	(voters, targets)
+}
+
+benchmarks! {
+	phragmen {
+		// number of votes in snapshot.
+		let v in (VOTERS[0]) .. VOTERS[1];
+		// number of targets in snapshot.
+		let t in (TARGETS[0]) .. TARGETS[1];
+		// number of votes per voter (ie the degree).
+		let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1];
+
+		let (voters, targets) = set_up_voters_targets::<T::AccountId>(v, t, d as usize);
+	}: {
+		assert!(
+			SequentialPhragmen::<T::AccountId, sp_runtime::Perbill>
+				::solve(d as usize, targets, voters).is_ok()
+		);
+	}
+
+	phragmms {
+		// number of votes in snapshot.
+		let v in (VOTERS[0]) .. VOTERS[1];
+		// number of targets in snapshot.
+		let t in (TARGETS[0]) .. TARGETS[1];
+		// number of votes per voter (ie the degree).
+		let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1];
+
+		let (voters, targets) = set_up_voters_targets::<T::AccountId>(v, t, d as usize);
+	}: {
+		assert!(
+			PhragMMS::<T::AccountId, sp_runtime::Perbill>
+				::solve(d as usize, targets, voters).is_ok()
+		);
+	}
+}
diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs
index 19735cf6035ac7af848870b8dec0685d5a6bc130..37ea2fcc59091eb50bc884098dc5cc060186a374 100644
--- a/substrate/frame/election-provider-support/src/lib.rs
+++ b/substrate/frame/election-provider-support/src/lib.rs
@@ -170,7 +170,7 @@ pub mod onchain;
 pub mod traits;
 #[cfg(feature = "std")]
 use codec::{Decode, Encode};
-use frame_support::{BoundedVec, RuntimeDebug};
+use frame_support::{weights::Weight, BoundedVec, RuntimeDebug};
 use sp_runtime::traits::Bounded;
 use sp_std::{fmt::Debug, prelude::*};
 
@@ -195,6 +195,9 @@ pub use sp_arithmetic;
 #[doc(hidden)]
 pub use sp_std;
 
+pub mod weights;
+pub use weights::WeightInfo;
+
 #[cfg(test)]
 mod mock;
 #[cfg(test)]
@@ -523,6 +526,12 @@ pub trait NposSolver {
 		targets: Vec<Self::AccountId>,
 		voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator<Item = Self::AccountId>)>,
 	) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error>;
+
+	/// Measure the weight used in the calculation of the solver.
+	/// - `voters` is the number of voters.
+	/// - `targets` is the number of targets.
+	/// - `vote_degree` is the degree ie the maximum numbers of votes per voter.
+	fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight;
 }
 
 /// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the
@@ -547,6 +556,10 @@ impl<
 	) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
 		sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get())
 	}
+
+	fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
+		T::phragmen(voters, targets, vote_degree)
+	}
 }
 
 /// A wrapper for [`sp_npos_elections::phragmms()`] that implements [`NposSolver`]. See the
@@ -571,6 +584,10 @@ impl<
 	) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
 		sp_npos_elections::phragmms(winners, targets, voters, Balancing::get())
 	}
+
+	fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
+		T::phragmms(voters, targets, vote_degree)
+	}
 }
 
 /// A voter, at the level of abstraction of this crate.
diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs
index 57fd931a467d16813eba165077454b6c12f50a85..62e76c3888822ea32d79d0bb0bbd436a050e5f5d 100644
--- a/substrate/frame/election-provider-support/src/onchain.rs
+++ b/substrate/frame/election-provider-support/src/onchain.rs
@@ -15,9 +15,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election.
+//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. As the
+//! name suggests, this is meant to be used onchain. Given how heavy the calculations are, please be
+//! careful when using it onchain.
 
-use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver};
+use crate::{
+	Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo,
+};
 use frame_support::{traits::Get, weights::DispatchClass};
 use sp_npos_elections::*;
 use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*};
@@ -41,39 +45,32 @@ impl From<sp_npos_elections::Error> for Error {
 ///
 /// This will accept voting data on the fly and produce the results immediately.
 ///
-/// Finally, the [`ElectionProvider`] implementation of this type does not impose any limits on the
+/// The [`ElectionProvider`] implementation of this type does not impose any dynamic limits on the
 /// number of voters and targets that are fetched. This could potentially make this unsuitable for
-/// execution onchain. One could, however, impose bounds on it by using for example
-/// `BoundedExecution` which will the bounds provided in the configuration.
+/// execution onchain. One could, however, impose bounds on it by using `BoundedExecution` using the
+/// `MaxVoters` and `MaxTargets` bonds in the `BoundedConfig` trait.
 ///
-/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs,
-/// either via using `BoundedExecution` and imposing the bounds there, or dynamically via calling
-/// `elect_with_bounds` providing these bounds. If you use `elect_with_bounds` along with
-/// `InstantElectionProvider`, the bound that would be used is the minimum of the 2 bounds.
-///
-/// It is advisable to use the former ([`ElectionProvider::elect`]) only at genesis, or for testing,
-/// the latter [`InstantElectionProvider::elect_with_bounds`] for onchain operations, with
-/// thoughtful bounds.
+/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs
+/// dynamically. If you use `elect_with_bounds` along with `InstantElectionProvider`, the bound that
+/// would be used is the minimum of the dynamic bounds given as arguments to `elect_with_bounds` and
+/// the trait bounds (`MaxVoters` and `MaxTargets`).
 ///
 /// Please use `BoundedExecution` at all times except at genesis or for testing, with thoughtful
 /// bounds in order to bound the potential execution time. Limit the use `UnboundedExecution` at
 /// genesis or for testing, as it does not bound the inputs. However, this can be used with
 /// `[InstantElectionProvider::elect_with_bounds`] that dynamically imposes limits.
-pub struct BoundedExecution<T: BoundedExecutionConfig>(PhantomData<T>);
+pub struct BoundedExecution<T: BoundedConfig>(PhantomData<T>);
 
 /// An unbounded variant of [`BoundedExecution`].
 ///
 /// ### Warning
 ///
-/// This can be very expensive to run frequently on-chain. Use with care. Moreover, this
-/// implementation ignores the additional data of the election data provider and gives no insight on
-/// how much weight was consumed.
-pub struct UnboundedExecution<T: ExecutionConfig>(PhantomData<T>);
-
-/// Configuration trait of [`UnboundedExecution`].
-pub trait ExecutionConfig {
-	/// Something that implements the system pallet configs. This is to enable to register extra
-	/// weight.
+/// This can be very expensive to run frequently on-chain. Use with care.
+pub struct UnboundedExecution<T: Config>(PhantomData<T>);
+
+/// Configuration trait for an onchain election execution.
+pub trait Config {
+	/// Needed for weight registration.
 	type System: frame_system::Config;
 	/// `NposSolver` that should be used, an example would be `PhragMMS`.
 	type Solver: NposSolver<
@@ -85,17 +82,18 @@ pub trait ExecutionConfig {
 		AccountId = <Self::System as frame_system::Config>::AccountId,
 		BlockNumber = <Self::System as frame_system::Config>::BlockNumber,
 	>;
+	/// Weight information for extrinsics in this pallet.
+	type WeightInfo: WeightInfo;
 }
 
-/// Configuration trait of [`BoundedExecution`].
-pub trait BoundedExecutionConfig: ExecutionConfig {
+pub trait BoundedConfig: Config {
 	/// Bounds the number of voters.
 	type VotersBound: Get<u32>;
 	/// Bounds the number of targets.
 	type TargetsBound: Get<u32>;
 }
 
-fn elect_with<T: ExecutionConfig>(
+fn elect_with<T: Config>(
 	maybe_max_voters: Option<usize>,
 	maybe_max_targets: Option<usize>,
 ) -> Result<Supports<<T::System as frame_system::Config>::AccountId>, Error> {
@@ -104,6 +102,9 @@ fn elect_with<T: ExecutionConfig>(
 		T::DataProvider::electable_targets(maybe_max_targets).map_err(Error::DataProvider)?;
 	let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?;
 
+	let voters_len = voters.len() as u32;
+	let targets_len = targets.len() as u32;
+
 	let stake_map: BTreeMap<_, _> = voters
 		.iter()
 		.map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight))
@@ -118,7 +119,11 @@ fn elect_with<T: ExecutionConfig>(
 
 	let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?;
 
-	let weight = <T::System as frame_system::Config>::BlockWeights::get().max_block;
+	let weight = T::Solver::weight::<T::WeightInfo>(
+		voters_len,
+		targets_len,
+		<T::DataProvider as ElectionDataProvider>::MaxVotesPerVoter::get(),
+	);
 	frame_system::Pallet::<T::System>::register_extra_weight_unchecked(
 		weight,
 		DispatchClass::Mandatory,
@@ -127,13 +132,13 @@ fn elect_with<T: ExecutionConfig>(
 	Ok(to_supports(&staked))
 }
 
-impl<T: ExecutionConfig> ElectionProvider for UnboundedExecution<T> {
+impl<T: Config> ElectionProvider for UnboundedExecution<T> {
 	type AccountId = <T::System as frame_system::Config>::AccountId;
 	type BlockNumber = <T::System as frame_system::Config>::BlockNumber;
 	type Error = Error;
 	type DataProvider = T::DataProvider;
 
-	fn elect() -> Result<Supports<<T::System as frame_system::Config>::AccountId>, Self::Error> {
+	fn elect() -> Result<Supports<Self::AccountId>, Self::Error> {
 		// This should not be called if not in `std` mode (and therefore neither in genesis nor in
 		// testing)
 		if cfg!(not(feature = "std")) {
@@ -147,7 +152,7 @@ impl<T: ExecutionConfig> ElectionProvider for UnboundedExecution<T> {
 	}
 }
 
-impl<T: ExecutionConfig> InstantElectionProvider for UnboundedExecution<T> {
+impl<T: Config> InstantElectionProvider for UnboundedExecution<T> {
 	fn elect_with_bounds(
 		max_voters: usize,
 		max_targets: usize,
@@ -156,18 +161,18 @@ impl<T: ExecutionConfig> InstantElectionProvider for UnboundedExecution<T> {
 	}
 }
 
-impl<T: BoundedExecutionConfig> ElectionProvider for BoundedExecution<T> {
+impl<T: BoundedConfig> ElectionProvider for BoundedExecution<T> {
 	type AccountId = <T::System as frame_system::Config>::AccountId;
 	type BlockNumber = <T::System as frame_system::Config>::BlockNumber;
 	type Error = Error;
 	type DataProvider = T::DataProvider;
 
-	fn elect() -> Result<Supports<<T::System as frame_system::Config>::AccountId>, Self::Error> {
+	fn elect() -> Result<Supports<Self::AccountId>, Self::Error> {
 		elect_with::<T>(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize))
 	}
 }
 
-impl<T: BoundedExecutionConfig> InstantElectionProvider for BoundedExecution<T> {
+impl<T: BoundedConfig> InstantElectionProvider for BoundedExecution<T> {
 	fn elect_with_bounds(
 		max_voters: usize,
 		max_targets: usize,
@@ -182,6 +187,8 @@ impl<T: BoundedExecutionConfig> InstantElectionProvider for BoundedExecution<T>
 #[cfg(test)]
 mod tests {
 	use super::*;
+	use crate::{PhragMMS, SequentialPhragmen};
+	use frame_support::traits::ConstU32;
 	use sp_npos_elections::Support;
 	use sp_runtime::Perbill;
 	type AccountId = u64;
@@ -228,13 +235,32 @@ mod tests {
 		type MaxConsumers = frame_support::traits::ConstU32<16>;
 	}
 
-	impl ExecutionConfig for Runtime {
-		type System = Self;
-		type Solver = crate::SequentialPhragmen<AccountId, Perbill>;
+	struct PhragmenParams;
+	struct PhragMMSParams;
+
+	impl Config for PhragmenParams {
+		type System = Runtime;
+		type Solver = SequentialPhragmen<AccountId, Perbill>;
 		type DataProvider = mock_data_provider::DataProvider;
+		type WeightInfo = ();
 	}
 
-	type OnChainPhragmen = UnboundedExecution<Runtime>;
+	impl BoundedConfig for PhragmenParams {
+		type VotersBound = ConstU32<600>;
+		type TargetsBound = ConstU32<400>;
+	}
+
+	impl Config for PhragMMSParams {
+		type System = Runtime;
+		type Solver = PhragMMS<AccountId, Perbill>;
+		type DataProvider = mock_data_provider::DataProvider;
+		type WeightInfo = ();
+	}
+
+	impl BoundedConfig for PhragMMSParams {
+		type VotersBound = ConstU32<600>;
+		type TargetsBound = ConstU32<400>;
+	}
 
 	mod mock_data_provider {
 		use frame_support::{bounded_vec, traits::ConstU32};
@@ -273,7 +299,20 @@ mod tests {
 	fn onchain_seq_phragmen_works() {
 		sp_io::TestExternalities::new_empty().execute_with(|| {
 			assert_eq!(
-				OnChainPhragmen::elect().unwrap(),
+				BoundedExecution::<PhragmenParams>::elect().unwrap(),
+				vec![
+					(10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }),
+					(30, Support { total: 35, voters: vec![(2, 20), (3, 15)] })
+				]
+			);
+		})
+	}
+
+	#[test]
+	fn onchain_phragmms_works() {
+		sp_io::TestExternalities::new_empty().execute_with(|| {
+			assert_eq!(
+				BoundedExecution::<PhragMMSParams>::elect().unwrap(),
 				vec![
 					(10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }),
 					(30, Support { total: 35, voters: vec![(2, 20), (3, 15)] })
diff --git a/substrate/frame/election-provider-support/src/weights.rs b/substrate/frame/election-provider-support/src/weights.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f288ae63bb5dab9de0bc9c0f64046d7ae55a21be
--- /dev/null
+++ b/substrate/frame/election-provider-support/src/weights.rs
@@ -0,0 +1,94 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Autogenerated weights for pallet_election_provider_support_onchain_benchmarking
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-04-04, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
+
+// Executed Command:
+// target/release/substrate
+// benchmark
+// --chain=dev
+// --steps=1
+// --repeat=1
+// --pallet=pallet_election_provider_support_benchmarking
+// --extrinsic=*
+// --execution=wasm
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=frame/election-provider-support/src/weights.rs
+// --template=./.maintain/frame-weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+/// Weight functions needed for pallet_election_provider_support_benchmarking.
+pub trait WeightInfo {
+	fn phragmen(v: u32, t: u32, d: u32, ) -> Weight;
+	fn phragmms(v: u32, t: u32, d: u32, ) -> Weight;
+}
+
+/// Weights for pallet_election_provider_support_benchmarking using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+	fn phragmen(v: u32, t: u32, d: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 667_000
+			.saturating_add((32_973_000 as Weight).saturating_mul(v as Weight))
+			// Standard Error: 1_334_000
+			.saturating_add((1_334_000 as Weight).saturating_mul(t as Weight))
+			// Standard Error: 60_644_000
+			.saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight))
+	}
+	fn phragmms(v: u32, t: u32, d: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 73_000
+			.saturating_add((21_073_000 as Weight).saturating_mul(v as Weight))
+			// Standard Error: 146_000
+			.saturating_add((65_000 as Weight).saturating_mul(t as Weight))
+			// Standard Error: 6_649_000
+			.saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight))
+	}
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+	fn phragmen(v: u32, t: u32, d: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 667_000
+			.saturating_add((32_973_000 as Weight).saturating_mul(v as Weight))
+			// Standard Error: 1_334_000
+			.saturating_add((1_334_000 as Weight).saturating_mul(t as Weight))
+			// Standard Error: 60_644_000
+			.saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight))
+	}
+	fn phragmms(v: u32, t: u32, d: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 73_000
+			.saturating_add((21_073_000 as Weight).saturating_mul(v as Weight))
+			// Standard Error: 146_000
+			.saturating_add((65_000 as Weight).saturating_mul(t as Weight))
+			// Standard Error: 6_649_000
+			.saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight))
+	}
+}
diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs
index 0296cd2e28d887e04d09e757a6f1ab497fbfca0c..67d5a3d7fd3737e379ef330043260a43faa266f6 100644
--- a/substrate/frame/grandpa/src/mock.rs
+++ b/substrate/frame/grandpa/src/mock.rs
@@ -181,10 +181,11 @@ parameter_types! {
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Test;
-	type Solver = SequentialPhragmen<<Test as frame_system::Config>::AccountId, Perbill>;
+	type Solver = SequentialPhragmen<u64, Perbill>;
 	type DataProvider = Staking;
+	type WeightInfo = ();
 }
 
 impl pallet_staking::Config for Test {
diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs
index 1a4414de0b0b0601988c9e4804fed4f1d70261f4..74cc29586920dd94f718a5fa4dad43a70f3deffb 100644
--- a/substrate/frame/offences/benchmarking/src/mock.rs
+++ b/substrate/frame/offences/benchmarking/src/mock.rs
@@ -151,10 +151,11 @@ parameter_types! {
 pub type Extrinsic = sp_runtime::testing::TestXt<Call, ()>;
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Test;
 	type Solver = SequentialPhragmen<AccountId, Perbill>;
 	type DataProvider = Staking;
+	type WeightInfo = ();
 }
 
 impl pallet_staking::Config for Test {
diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs
index 24b42b3e9f4b587e56acbb962d1f47dbfdf8aceb..5acc484f9ba622dfff4fac9a0b909cf453a857df 100644
--- a/substrate/frame/session/benchmarking/src/mock.rs
+++ b/substrate/frame/session/benchmarking/src/mock.rs
@@ -157,10 +157,11 @@ where
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Test;
 	type Solver = SequentialPhragmen<AccountId, sp_runtime::Perbill>;
 	type DataProvider = Staking;
+	type WeightInfo = ();
 }
 
 impl pallet_staking::Config for Test {
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index bb90aded852eee88241658d1404acae59fad16b3..09809483ec155a50e8021651253b4a7a4d35d7e6 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -248,10 +248,11 @@ impl pallet_bags_list::Config for Test {
 }
 
 pub struct OnChainSeqPhragmen;
-impl onchain::ExecutionConfig for OnChainSeqPhragmen {
+impl onchain::Config for OnChainSeqPhragmen {
 	type System = Test;
 	type Solver = SequentialPhragmen<AccountId, Perbill>;
 	type DataProvider = Staking;
+	type WeightInfo = ();
 }
 
 impl crate::pallet::pallet::Config for Test {
diff --git a/substrate/primitives/npos-elections/src/balancing.rs b/substrate/primitives/npos-elections/src/balancing.rs
index 98f193e9e61167534472c104b6b40a994cae8476..54b8ee4bf243edd5c7755c159c4fe27954a22de8 100644
--- a/substrate/primitives/npos-elections/src/balancing.rs
+++ b/substrate/primitives/npos-elections/src/balancing.rs
@@ -37,7 +37,7 @@ use sp_std::prelude::*;
 ///
 /// In almost all cases, a balanced solution will have a better score than an unbalanced solution,
 /// yet this is not 100% guaranteed because the first element of a [`crate::ElectionScore`] does not
-/// directly related to balancing.
+/// directly relate to balancing.
 ///
 /// Note that some reference implementation adopt an approach in which voters are balanced randomly
 /// per round. To advocate determinism, we don't do this. In each round, all voters are exactly
diff --git a/substrate/primitives/npos-elections/src/phragmms.rs b/substrate/primitives/npos-elections/src/phragmms.rs
index 6220cacd157b2baefa9f4a643a8e860da221ce78..aa4c558bea1da9842e51a9342ccab423856d3b2f 100644
--- a/substrate/primitives/npos-elections/src/phragmms.rs
+++ b/substrate/primitives/npos-elections/src/phragmms.rs
@@ -37,7 +37,7 @@ use sp_std::{prelude::*, rc::Rc};
 /// - The algorithm is a _best-effort_ to elect `to_elect`. If less candidates are provided, less
 ///   winners are returned, without an error.
 ///
-/// This can only fail of the normalization fails. This can happen if for any of the resulting
+/// This can only fail if the normalization fails. This can happen if for any of the resulting
 /// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside
 /// `UpperOf<P>`. A user of this crate may statically assert that this can never happen and safely
 /// `expect` this to return `Ok`.