Skip to content

Collections benchmarks rewrite - #92

Merged
adamsitnik merged 32 commits into
dotnet:masterfrom
adamsitnik:collectionsRewrite
Jul 20, 2018
Merged

Collections benchmarks rewrite#92
adamsitnik merged 32 commits into
dotnet:masterfrom
adamsitnik:collectionsRewrite

Conversation

@adamsitnik

Copy link
Copy Markdown
Member

I was supposed to port collections benchmarks.

After digging more into the existing benchmarks I decided to rewrite them instead. Porting them would take a similar amount of time, whereas they would not benefit from all BDN advantages and it would be hard to compare them. Also, many collections (Immutable ones for example) did not have benchmarks at all.

@adamsitnik
adamsitnik requested review from ViktorHofer and jorive July 13, 2018 19:43
# Conflicts:
#	src/benchmarks/Benchmarks.csproj
<DebugSymbols>true</DebugSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>7.3</LangVersion>
<LangVersion>latest</LangVersion>

@jorive jorive Jul 13, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good call! 👍 #Closed

namespace System.Collections
{
[BenchmarkCategory(Categories.CoreFX, Categories.Collections, Categories.GenericCollections)]
[GenericTypeArguments(typeof(int))] // value type

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@jorive @ViktorHofer GenericTypeArguments is the way to tell BDN what T is for generic classes with benchmarks

{
private T[] _uniqueValues;

[Params(Utils.DefaultCollectionSize)]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@jorive @ViktorHofer Params is the way to parametrize benchmarks per given type, Params can have multiple values like [Params(1, 2, 3)] but we don't have enough time to run all the benchmarks for more test cases so I am using single, same value everywhere

</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.14.667" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.14.683" />

@adamsitnik adamsitnik Jul 13, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@jorive I needed to update BDN to have glob filtering support #Closed

@adamsitnik

Copy link
Copy Markdown
Member Author

I have just pushed the remaining benchmarks for concurrent collections. The PR is ready for final review.

@jorive

jorive commented Jul 17, 2018

Copy link
Copy Markdown

@adamsitnik How are you selecting the scenarios to benchmark for the generic collections? For example, are we covering the basic ICollection<T> interface?

@adamsitnik

Copy link
Copy Markdown
Member Author

@jorive I am using concrete types everywhere, not abstractions.

I could add ICollection<T> , IReadOnlyCollection<T>, IDictionary<T> , IReadOnlyDictionary<T> cases but I would be benchmarking more or less the used collection type + virtual method dispatch overhead.

I think that we should have such benchmarks, but I am not sure if they should be part of the System.Collections benchmarks or CoreClr.Virtualization

@jorive what do you think?

@jorive

jorive commented Jul 18, 2018

Copy link
Copy Markdown

@adamsitnik That's a good point, and I think that with categories, we could add them to both :)
I just wanted to understand the cases that we are covering and make sure we have the basics too, for example: insert, remove, find?

public class CtorDefaultSize<T>
{
[Benchmark]
public T[] Array() => new T[4]; // array has no default size, List has = 4 so I decided to use 4 here

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I am inclined to remove this test as Array does not have default Ctor. #ByDesign

@adamsitnik adamsitnik Jul 19, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I believe that we can keep it, the value that it provides to me is comparing the cost of array creation vs the cost of creating array wrappers (list, stack, queue). If the latter is much bigger it means we have a problem #Closed

[Benchmark]
public List<T> List() => new List<T>(Size);

#if !NET461 // API added in .NET Core 2.0

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think we should start using #if !NETFRAMEWORK instead. I can see us adding newer Desktop versions to out matrix. Thoughts? #Closed

@adamsitnik adamsitnik Jul 19, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good idea! #Closed

{
internal static T[] GenerateArray<T>(int count)
{
var random = new Random(12345); // we always use the same seed to have repeatable results!

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

// we always use the same seed to have repeatable results! [](start = 44, length = 58)

👍 #Closed


internal static Dictionary<TKey, TValue> GenerateDictionary<TKey, TValue>(int count)
{
var random = new Random(12345); // we always use the same seed to have repeatable results!

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

12345 [](start = 36, length = 5)

nit: Can we make the seed a const variable used in both methods? #Closed

public int Count;

[GlobalSetup]
public void Setup() => _uniqueValues = UniqueValuesGenerator.GenerateArray<T>(Count);

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: Feels like Count here should be replaced with Utils.DefaultCollectionSize, and Count on the benchmarks with _uniqueValues.Length #ByDesign

@adamsitnik adamsitnik Jul 19, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am using the value of Param everywhere (not Utils.DefaultCollectionSize) because in the future somebody might like to run this benchmark for more values and then it will require just adding the values to [Param]

[Params(10, 2000, 100000)]
public int Size;

BDN will then run the same benchmark for all provided values (10, 2000, 100000) #Closed

[Benchmark]
public bool Array()
{
bool result = default;

@jorive jorive Jul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could you please make this loop dependent? #Closed

@adamsitnik adamsitnik Jul 19, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Another good point! Done #Closed

@jorive

jorive commented Jul 19, 2018

Copy link
Copy Markdown

@adamsitnik We should open an issue about the loop independent variable assignments.

@adamsitnik
adamsitnik merged commit 2b3bd56 into dotnet:master Jul 20, 2018
@adamsitnik

Copy link
Copy Markdown
Member Author

We should open an issue about the loop independent variable assignments.

@jorive it's on my TODO list, I will start the discussion right after my holidays. (I don;t want to start a discussion and disappear)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants