From 347b5d641c3bdadc0430f7dda1bbffd85470ed23 Mon Sep 17 00:00:00 2001
From: Marcio Diaz <marcio.diaz@gmail.com>
Date: Fri, 28 Feb 2020 15:40:42 +0100
Subject: [PATCH] Add options to overwrite range bounds in benchmark command.
 (#5072)

* Add --mins --maxs to benchmark command.

* Apply review suggestions.
---
 substrate/bin/node/runtime/src/lib.rs         | 26 +++++++++++--
 substrate/frame/benchmarking/src/lib.rs       | 38 ++++++++++++++-----
 substrate/frame/benchmarking/src/utils.rs     | 12 +++++-
 .../utils/frame/benchmarking-cli/src/lib.rs   | 21 +++++++++-
 4 files changed, 81 insertions(+), 16 deletions(-)

diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 9e4496f1e9d..ae8251f6209 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -820,15 +820,35 @@ impl_runtime_apis! {
 		fn dispatch_benchmark(
 			module: Vec<u8>,
 			extrinsic: Vec<u8>,
+			lowest_range_values: Vec<u32>,
+			highest_range_values: Vec<u32>,
 			steps: Vec<u32>,
 			repeat: u32,
 		) -> Result<Vec<frame_benchmarking::BenchmarkResults>, RuntimeString> {
 			use frame_benchmarking::Benchmarking;
 
 			let result = match module.as_slice() {
-				b"pallet-balances" | b"balances" => Balances::run_benchmark(extrinsic, steps, repeat),
-				b"pallet-identity" | b"identity" => Identity::run_benchmark(extrinsic, steps, repeat),
-				b"pallet-timestamp" | b"timestamp" => Timestamp::run_benchmark(extrinsic, steps, repeat),
+				b"pallet-balances" | b"balances" => Balances::run_benchmark(
+					extrinsic,
+					lowest_range_values,
+					highest_range_values,
+					steps,
+					repeat,
+				),
+				b"pallet-identity" | b"identity" => Identity::run_benchmark(
+					extrinsic,
+					lowest_range_values,
+					highest_range_values,
+					steps,
+					repeat,
+				),
+				b"pallet-timestamp" | b"timestamp" => Timestamp::run_benchmark(
+					extrinsic,
+					lowest_range_values,
+					highest_range_values,
+					steps,
+					repeat,
+				),
 				_ => Err("Benchmark not found for this pallet."),
 			};
 
diff --git a/substrate/frame/benchmarking/src/lib.rs b/substrate/frame/benchmarking/src/lib.rs
index e6b6a4f3f59..d979000432c 100644
--- a/substrate/frame/benchmarking/src/lib.rs
+++ b/substrate/frame/benchmarking/src/lib.rs
@@ -140,7 +140,13 @@ macro_rules! impl_benchmark {
 		$( $name:ident ),*
 	) => {
 		impl<T: Trait> $crate::Benchmarking<$crate::BenchmarkResults> for Module<T> {
-			fn run_benchmark(extrinsic: Vec<u8>, steps: Vec<u32>, repeat: u32) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
+			fn run_benchmark(
+				extrinsic: Vec<u8>,
+				lowest_range_values: Vec<u32>,
+				highest_range_values: Vec<u32>,
+				steps: Vec<u32>,
+				repeat: u32,
+			) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
 				// Map the input to the selected benchmark.
 				let extrinsic = sp_std::str::from_utf8(extrinsic.as_slice())
 					.map_err(|_| "Could not find extrinsic")?;
@@ -157,26 +163,38 @@ macro_rules! impl_benchmark {
 				let mut results: Vec<$crate::BenchmarkResults> = Vec::new();
 
 				// Default number of steps for a component.
-				let mut prev_steps = &10;
+				let mut prev_steps = 10;
 
 				// Select the component we will be benchmarking. Each component will be benchmarked.
 				for (idx, (name, low, high)) in components.iter().enumerate() {
 					// Get the number of steps for this component.
-					let steps = steps.get(idx).unwrap_or(&prev_steps);
+					let steps = steps.get(idx).cloned().unwrap_or(prev_steps);
 					prev_steps = steps;
 
+					let lowest = lowest_range_values.get(idx).cloned().unwrap_or(*low);
+					let highest = highest_range_values.get(idx).cloned().unwrap_or(*high);
+
+					let diff = highest - lowest;
+
 					// Create up to `STEPS` steps for that component between high and low.
-					let step_size = ((high - low) / steps).max(1);
-					let num_of_steps = (high - low) / step_size + 1;
+					let step_size = (diff / steps).max(1);
+					let num_of_steps = diff / step_size + 1;
+
 					for s in 0..num_of_steps {
 						// This is the value we will be testing for component `name`
-						let component_value = low + step_size * s;
+						let component_value = lowest + step_size * s;
 
-						// Select the mid value for all the other components.
+						// Select the max value for all the other components.
 						let c: Vec<($crate::BenchmarkParameter, u32)> = components.iter()
-							.map(|(n, l, h)|
-								(*n, if n == name { component_value } else { *h })
-							).collect();
+							.enumerate()
+							.map(|(idx, (n, l, h))|
+								if n == name {
+									(*n, component_value)
+								} else {
+									(*n, *highest_range_values.get(idx).unwrap_or(h))
+								}
+							)
+							.collect();
 
 						// Run the benchmark `repeat` times.
 						for _ in 0..repeat {
diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs
index f9d1ecf8cd3..87996c3f574 100644
--- a/substrate/frame/benchmarking/src/utils.rs
+++ b/substrate/frame/benchmarking/src/utils.rs
@@ -41,6 +41,8 @@ sp_api::decl_runtime_apis! {
 		fn dispatch_benchmark(
 			module: Vec<u8>,
 			extrinsic: Vec<u8>,
+			lowest_range_values: Vec<u32>,
+			highest_range_values: Vec<u32>,
 			steps: Vec<u32>,
 			repeat: u32,
 		) -> Result<Vec<BenchmarkResults>, RuntimeString>;
@@ -78,8 +80,16 @@ pub trait Benchmarking<T> {
 	/// Parameters
 	/// - `extrinsic`: The name of extrinsic function you want to benchmark encoded as bytes.
 	/// - `steps`: The number of sample points you want to take across the range of parameters.
+	/// - `lowest_range_values`: The lowest number for each range of parameters.
+	/// - `highest_range_values`: The highest number for each range of parameters.
 	/// - `repeat`: The number of times you want to repeat a benchmark.
-	fn run_benchmark(extrinsic: Vec<u8>, steps: Vec<u32>, repeat: u32) -> Result<Vec<T>, &'static str>;
+	fn run_benchmark(
+		extrinsic: Vec<u8>,
+		lowest_range_values: Vec<u32>,
+		highest_range_values: Vec<u32>,
+		steps: Vec<u32>,
+		repeat: u32,
+	) -> Result<Vec<T>, &'static str>;
 }
 
 /// The required setup for creating a benchmark.
diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs
index b09b1bad627..899419e5de5 100644
--- a/substrate/utils/frame/benchmarking-cli/src/lib.rs
+++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs
@@ -39,6 +39,14 @@ pub struct BenchmarkCmd {
 	#[structopt(short, long, use_delimiter = true)]
 	pub steps: Vec<u32>,
 
+	/// Indicates lowest values for each of the component ranges.
+	#[structopt(long, use_delimiter = true)]
+	pub lowest_range_values: Vec<u32>,
+
+	/// Indicates highest values for each of the component ranges.
+	#[structopt(long, use_delimiter = true)]
+	pub highest_range_values: Vec<u32>,
+
 	/// Select how many repetitions of this benchmark should run.
 	#[structopt(short, long, default_value = "1")]
 	pub repeat: u32,
@@ -104,7 +112,14 @@ impl BenchmarkCmd {
 			&mut changes,
 			&executor,
 			"Benchmark_dispatch_benchmark",
-			&(&self.pallet, &self.extrinsic, self.steps.clone(), self.repeat).encode(),
+			&(
+				&self.pallet,
+				&self.extrinsic,
+				self.lowest_range_values.clone(),
+				self.highest_range_values.clone(),
+				self.steps.clone(),
+				self.repeat,
+			).encode(),
 			Default::default(),
 		)
 		.execute(strategy.into())
@@ -117,9 +132,11 @@ impl BenchmarkCmd {
 			Ok(results) => {
 				// Print benchmark metadata
 				println!(
-					"Pallet: {:?}, Extrinsic: {:?}, Steps: {:?}, Repeat: {:?}",
+					"Pallet: {:?}, Extrinsic: {:?}, Lowest values: {:?}, Highest values: {:?}, Steps: {:?}, Repeat: {:?}",
 					self.pallet,
 					self.extrinsic,
+					self.lowest_range_values,
+					self.highest_range_values,
 					self.steps,
 					self.repeat,
 				);
-- 
GitLab