Skip to content

Solve MinIterationTime warning #2600

@swtrse

Description

@swtrse

Hello,

I have a Benchmark that looks like

namespace Cobra.Exoda.Matching.Benchmarks.Base;

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using JetBrains.Annotations;

[CategoriesColumn]
[MinColumn]
[MaxColumn]
[MemoryDiagnoser(false)]
[HideColumns("Job", "Type")]
[ShortRunJob(RuntimeMoniker.Net80)]
[ShortRunJob(RuntimeMoniker.Net90)]
//[ShortRunJob(RuntimeMoniker.NativeAot80)] // Bug
//[ShortRunJob(RuntimeMoniker.NativeAot90)] // Bug
public class BenchmarkBase
{
	[Params(0, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000)]
	public int Prefill { get; [UsedImplicitly] set; }

	[Params(10)]
	public int Inserts { get; [UsedImplicitly] set; }

	[Params(1_00, 2_000, 5_000, 10_000)] public int PriceRange { get; [UsedImplicitly] set; }
}
namespace Cobra.Exoda.Matching.Benchmarks;

using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Numerics;
using Base;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNetVisualizer;
using JetBrains.Annotations;
using Nethermind.Int256;
using SortedDictionary.BigInteger;
using SortedDictionary.UInt256;
using Utils;

[PublicAPI]
[RichHtmlExporter("Benchmark of Collection Performance",
                  ["Prefill", "Inserts", "PriceRange"],
                  ["Mean", "Allocated"],
                  ["Mean", "Min", "Max", "Allocated"],
                  dividerMode: RenderTableDividerMode.SeparateTables,
                  htmlWrapMode: HtmlDocumentWrapMode.RichDataTables)]
[GenericTypeArguments(typeof(OrderDataBigIntegerKey), typeof(OrderDataBigInteger))]
[GenericTypeArguments(typeof(OrderDataUInt256Key), typeof(OrderDataUInt256))]
[Display(Name = "Benchmark of Flat Dictionary Item Insert for IDictionary<{0}, {1}>", GroupName = "Benchmark of Dictionaries Item Insert")]

// ReSharper disable once ClassCanBeSealed.Global
public class AddItemBenchmarkFlat<TKey, TData> : BenchmarkBase
	where TKey : notnull
	where TData : notnull
{
	[GlobalSetup]
	public void A_Global_Setup()
	{
		_orderDataKeys = new TKey[Inserts];
		_orderDataArray = new TData[Inserts];
		_prefillArray = new TData[Prefill];
		var rnd = new Random();
		if (typeof(TData) == typeof(OrderDataBigInteger))
		{
			Parallel.For(0,
			             Inserts,
			             i =>
			             {
				             var price = new BigInteger(rnd.NextInt64(0, PriceRange));
				             var orderId = new Guid(i + Prefill, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0]);
				             _orderDataKeys[i] = (dynamic)new OrderDataBigIntegerKey(price, orderId);
				             _orderDataArray[i] = (dynamic)new OrderDataBigInteger(price, orderId, 1);
			             });
			Parallel.For(0,
			             Prefill,
			             i =>
			             {
				             var price = new BigInteger(rnd.NextInt64(0, PriceRange));
				             var orderId = new Guid(i, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0]);
				             _prefillArray[i] = (dynamic)new OrderDataBigInteger(price, orderId, 1);
			             });
		}
		else if (typeof(TData) == typeof(OrderDataUInt256))
		{
			Parallel.For(0,
			             Inserts,
			             i =>
			             {
				             var price = new UInt256((ulong)rnd.NextInt64(0, PriceRange));
				             var orderId = new Guid(i + Prefill, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0]);
				             _orderDataKeys[i] = (dynamic)new OrderDataUInt256Key(price, orderId);
				             _orderDataArray[i] = (dynamic)new OrderDataUInt256(price, orderId, 1);
			             });
			Parallel.For(0,
			             Prefill,
			             i =>
			             {
				             var price = new UInt256((ulong)rnd.NextInt64(0, PriceRange));
				             var orderId = new Guid(i, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0]);
				             _prefillArray[i] = (dynamic)new OrderDataUInt256(price, orderId, 1);
			             });
		}
		else { throw new Exception("Unsupported Type"); }
	}

	[IterationSetup(Target = "SortedDictionary_AddItem")]
	public void A_Iteration_Setup_SortedDictionary()
	{
		if (typeof(TData) == typeof(OrderDataBigInteger))
		{
			_collection =
				(dynamic)new SortedDictionary<OrderDataBigIntegerKey, OrderDataBigInteger>(((OrderDataBigInteger[])(dynamic)_prefillArray).ToDictionary(static pair =>
						                                                                           new OrderDataBigIntegerKey(pair.Price, pair.OrderId),
					                                                                           static pair => pair));
		}
		else
		{
			_collection =
				(dynamic)new SortedDictionary<OrderDataUInt256Key, OrderDataUInt256>(((OrderDataUInt256[])(dynamic)_prefillArray).ToDictionary(static pair =>
						                                                                     new OrderDataUInt256Key(pair.Price, pair.OrderId),
					                                                                     static pair => pair));
		}
	}

	[IterationSetup(Target = "SortedImmutableDictionary_AddItem")]
	public void A_Iteration_Setup_SortedImmutableDictionary()
	{
		if (typeof(TData) == typeof(OrderDataBigInteger))
		{
			_collection =
				(dynamic)((OrderDataBigInteger[])(dynamic)_prefillArray).ToImmutableSortedDictionary(static p => new OrderDataBigIntegerKey(p.Price, p.OrderId), static p => p);
		}
		else
		{
			_collection = (dynamic)((OrderDataUInt256[])(dynamic)_prefillArray).ToImmutableSortedDictionary(static p => new OrderDataUInt256Key(p.Price, p.OrderId), static p => p);
		}
	}

	[IterationSetup(Target = "SortedList_AddItem")]
	public void A_Iteration_Setup_SortedList()
	{
		if (typeof(TData) == typeof(OrderDataBigInteger))
		{
			_collection =
				(dynamic)new SortedList<OrderDataBigIntegerKey, OrderDataBigInteger>(((OrderDataBigInteger[])(dynamic)_prefillArray).ToDictionary(static pair =>
						                                                                     new OrderDataBigIntegerKey(pair.Price, pair.OrderId),
					                                                                     static pair => pair));
		}
		else
		{
			_collection =
				(dynamic)new SortedList<OrderDataUInt256Key, OrderDataUInt256>(((OrderDataUInt256[])(dynamic)_prefillArray).ToDictionary(static pair =>
						                                                               new OrderDataUInt256Key(pair.Price, pair.OrderId),
					                                                               static pair => pair));
		}
	}

	[Benchmark(Baseline = true)]
	[BenchmarkCategory("AddItem")]
	public void SortedDictionary_AddItem()
	{
		BenchmarkHelper.FlatCollection(_orderDataKeys, _orderDataArray, ref _collection);
	}

	[Benchmark]
	[BenchmarkCategory("AddItem")]
	public void SortedImmutableDictionary_AddItem()
	{
		var immutable = (IImmutableDictionary<TKey, TData>)_collection;
		BenchmarkHelper.FlatImmutableCollection(_orderDataKeys, _orderDataArray, ref immutable);
	}

	[Benchmark]
	[BenchmarkCategory("AddItem")]
	public void SortedList_AddItem()
	{
		BenchmarkHelper.FlatCollection(_orderDataKeys, _orderDataArray, ref _collection);
	}

	// ReSharper disable NullableWarningSuppressionIsUsed
	private IDictionary<TKey, TData> _collection = default!;

	private TData[] _prefillArray = default!;

	public string[] GetDataTypeName { get; } = [typeof(TData) == typeof(OrderDataBigInteger) ? "BigInteger" : "UInt256"];

	[ParamsSource(nameof(GetDataTypeName), Priority = -1)]
	public string DataType { get; set; } = default!;
	// ReSharper restore NullableWarningSuppressionIsUsed

	// ReSharper disable NullableWarningSuppressionIsUsed
	private TData[] _orderDataArray = default!;

	private TKey[] _orderDataKeys = default!;
	// ReSharper restore NullableWarningSuppressionIsUsed
}

What I want to compare is the performance between the different variants.
However I get the MinIterationTime warning. Since my time is far away from the needed minimum iteration time I think I need to rewrite the tests but I have absolutely no idea how to do that and achieve the same tests. What I do not want is to add the time to prepare the collection to the performance benchmark time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions