Skip to content
Snippets Groups Projects
redundant_meter.rs 2.84 KiB
Newer Older
Ermal Kaleci's avatar
Ermal Kaleci committed
use codec::{Decode, Encode};
use rand::{distributions::Alphanumeric, thread_rng, Rng};

#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)]
struct RedundantResult {
	identifier: Vec<u8>,
	timestamp: u128,
	reads: u32,
	repeat_reads: u32,
	writes: u32,
	repeat_writes: u32,
}

/// RedundantMeter is used to measure resources been used by methods that
/// already been benchmarked and have `[orml_weight_meter::weight(..)] macro
/// defined. First method with that macro will be skipped and after that every
/// method with macro defined will be measured as redundant result.
#[derive(Default)]
pub struct RedundantMeter {
	started: bool,
	results: Vec<RedundantResult>,
	current: Option<RedundantResult>,
}

impl RedundantMeter {
	/// Entering method with `[orml_weight_meter::weight(..)]` macro
	pub fn entering_method(&mut self) -> Vec<u8> {
		if !self.started {
			self.started = true;
			return Vec::new();
		}

		if self.current.is_some() {
			return Vec::new();
		}

		let timestamp = frame_benchmarking::benchmarking::current_time();
		let (reads, repeat_reads, writes, repeat_writes) = frame_benchmarking::benchmarking::read_write_count();

		let identifier: Vec<u8> = thread_rng()
			.sample_iter(&Alphanumeric)
			.take(10)
			.map(char::from)
			.collect::<String>()
			.encode();

		self.current = Some(RedundantResult {
			identifier: identifier.to_owned(),
			timestamp,
			reads,
			repeat_reads,
			writes,
			repeat_writes,
		});

		identifier
	}

	/// Leaving method with `[orml_weight_meter::weight(..)]` macro
	pub fn leaving_method(&mut self, identifier: Vec<u8>) {
		if let Some(current) = &self.current {
			if current.identifier.eq(&identifier) {
				let (reads, repeat_reads, writes, repeat_writes) = frame_benchmarking::benchmarking::read_write_count();
				let timestamp = frame_benchmarking::benchmarking::current_time();

				self.results.push(RedundantResult {
					identifier,
					timestamp: timestamp - current.timestamp,
					reads: reads - current.reads,
					repeat_reads: repeat_reads - current.repeat_reads,
					writes: writes - current.writes,
					repeat_writes: repeat_writes - current.repeat_writes,
				});

				// reset current
				self.current = None;
			}
		}
	}

	/// Take bench results and reset for next measurement
	pub fn take_results(&mut self) -> (u128, u32, u32, u32, u32) {
		assert!(self.current == None, "benchmark in progress");

		let mut elapsed = 0u128;
		let mut reads = 0u32;
		let mut repeat_reads = 0u32;
		let mut writes = 0u32;
		let mut repeat_writes = 0u32;

		self.results.iter().for_each(|x| {
			elapsed += x.timestamp;
			reads += x.reads;
			repeat_reads += x.repeat_reads;
			writes += x.writes;
			repeat_writes += x.repeat_writes;
		});

		self.reset();

		(elapsed, reads, repeat_reads, writes, repeat_writes)
	}

	pub fn reset(&mut self) {
		self.started = false;
		self.results = Vec::new();
		self.current = None;
	}
}