Skip to content

Commit

Permalink
System.Memory (#94)
Browse files Browse the repository at this point in the history
* Span, ReadOnlySpan, Memory, ReadOnlyMemory constructors benchmarks

* Span indexer benchmarks

* move Clear Span and Array benchmarks to Clear benchmarks of all collections

* move CopyTo Span and Array benchmarks to CopyTo benchmarks of all collections, add List and ImmutableArray CopyTo

* make sure we always have the same random data to compare apples to apples

* cleanup Sorting benchmarks

* reorganize Span benchmarks

* add For loop benchmark for ReadOnlySpan

* we can't generate an array of more than 255 unique bytes so for some benchmarks we generate just random bytes

* port MemoryMarshal benchmark from CoreFX

* port more Span benchmarks

* port more ROS Benchmarks

* add benchmarks for creating Span from Memory

* implement Slice benchmarks

* implement foreach benchmarks for Span and ROS

* add missing license header

* add CopyTo benchmarks for ROS and Memory

* and Memory.Pin benchmarks

* simplify the slicing benchmark code

* add memory.ToArray benchmarks

* add GetPinnableReference benchmarks
  • Loading branch information
adamsitnik authored Sep 18, 2018
1 parent b978644 commit 4b34c30
Show file tree
Hide file tree
Showing 38 changed files with 1,286 additions and 518 deletions.
2 changes: 2 additions & 0 deletions src/benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="img\**" />
<Compile Remove="Tests\**" />
<EmbeddedResource Remove="img\**" />
<None Remove="img\**" />
<None Remove="Tests\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.1.737" />
Expand Down
8 changes: 7 additions & 1 deletion src/benchmarks/Benchmarks.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2011
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks.csproj", "{D99F63AE-3154-4F13-9424-FA5F9D032D1D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Benchmarks.csproj", "{D99F63AE-3154-4F13-9424-FA5F9D032D1D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{A40E51E2-99EB-4F64-ADCC-94FEA3FF1399}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -15,6 +17,10 @@ Global
{D99F63AE-3154-4F13-9424-FA5F9D032D1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99F63AE-3154-4F13-9424-FA5F9D032D1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99F63AE-3154-4F13-9424-FA5F9D032D1D}.Release|Any CPU.Build.0 = Release|Any CPU
{A40E51E2-99EB-4F64-ADCC-94FEA3FF1399}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A40E51E2-99EB-4F64-ADCC-94FEA3FF1399}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A40E51E2-99EB-4F64-ADCC-94FEA3FF1399}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A40E51E2-99EB-4F64-ADCC-94FEA3FF1399}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
15 changes: 15 additions & 0 deletions src/benchmarks/Tests/Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Benchmarks.csproj" />
</ItemGroup>
</Project>
49 changes: 49 additions & 0 deletions src/benchmarks/Tests/UniqueValuesGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Linq;
using Benchmarks;
using Xunit;

namespace Tests
{
public class UniqueValuesGeneratorTests
{
[Fact]
public void UnsupportedTypesThrow()
=> Assert.Throws<NotImplementedException>(() => ValuesGenerator.ArrayOfUniqueValues<UniqueValuesGeneratorTests>(1));

[Fact]
public void GeneratedArraysContainOnlyUniqueValues()
{
AssertGeneratedArraysContainOnlyUniqueValues<int>(1024);
AssertGeneratedArraysContainOnlyUniqueValues<string>(1024);
}

private void AssertGeneratedArraysContainOnlyUniqueValues<T>(int size)
{
var generatedArray = ValuesGenerator.ArrayOfUniqueValues<T>(size);

var distinct = generatedArray.Distinct().ToArray();

Assert.Equal(distinct, generatedArray);
}

[Fact]
public void GeneratedArraysContainAlwaysSameValues()
{
AssertGeneratedArraysContainAlwaysSameValues<int>(1024);
AssertGeneratedArraysContainAlwaysSameValues<string>(1024);
}

private void AssertGeneratedArraysContainAlwaysSameValues<T>(int size)
{
var generatedArray = ValuesGenerator.ArrayOfUniqueValues<T>(size);

for (int i = 0; i < 10; i++)
{
var anotherGeneratedArray = ValuesGenerator.ArrayOfUniqueValues<T>(size);

Assert.Equal(generatedArray, anotherGeneratedArray);
}
}
}
}
94 changes: 94 additions & 0 deletions src/benchmarks/ValuesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Benchmarks
{
public static class ValuesGenerator
{
private const int Seed = 12345; // we always use the same seed to have repeatable results!

public static T GetNonDefaultValue<T>() => ArrayOfUniqueValues<T>(2).First(value => !value.Equals(default));

public static T[] ArrayOfUniqueValues<T>(int count)
{
var random = new Random(Seed);

var uniqueValues = new HashSet<T>();

while (uniqueValues.Count != count)
{
T value = GenerateValue<T>(random);

if (!uniqueValues.Contains(value))
uniqueValues.Add(value);
}

return uniqueValues.ToArray();
}

public static T[] Array<T>(int count)
{
var random = new Random(Seed);

var result = new T[count];

if (typeof(T) == typeof(byte))
{
random.NextBytes((byte[])(object)result);
}
else
{
for (int i = 0; i < result.Length; i++)
{
result[i] = GenerateValue<T>(random);
}
}

return result;
}

public static Dictionary<TKey, TValue> Dictionary<TKey, TValue>(int count)
{
var random = new Random(Seed);

var dictionary = new Dictionary<TKey, TValue>();

while (dictionary.Count != count)
{
TKey key = GenerateValue<TKey>(random);

if (!dictionary.ContainsKey(key))
dictionary.Add(key, GenerateValue<TValue>(random));
}

return dictionary;
}

private static T GenerateValue<T>(Random random)
{
if (typeof(T) == typeof(char))
return (T)(object)(char)random.Next(char.MinValue, char.MaxValue);
if (typeof(T) == typeof(int))
return (T)(object)random.Next();
if (typeof(T) == typeof(double))
return (T)(object)random.NextDouble();
if (typeof(T) == typeof(string))
return (T) (object) GenerateRandomString(random, 1, 50);

throw new NotImplementedException($"{typeof(T).Name} is not implemented");
}

private static string GenerateRandomString(Random random, int minLength, int maxLength)
{
var length = random.Next(minLength, maxLength);

var builder = new StringBuilder(length);
for (int i = 0; i < length; i++)
builder.Append((char) random.Next(char.MinValue, char.MaxValue));

return builder.ToString();
}
}
}
176 changes: 176 additions & 0 deletions src/benchmarks/coreclr/Span/Sorting.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using Benchmarks;

namespace Span
{
[BenchmarkCategory(Categories.CoreCLR)]
[InvocationCount(InvocationsPerIteration)]
public class Sorting
{
private const int InvocationsPerIteration = 1000;

[Params(Utils.DefaultCollectionSize)]
public int Size;

private int _iterationIndex = 0;
private int[] _values;

private int[][] _arrays;

[GlobalSetup]
public void Setup() => _values = ValuesGenerator.ArrayOfUniqueValues<int>(Size);

[IterationSetup]
public void SetupIteration() => Utils.FillArrays(ref _arrays, InvocationsPerIteration, _values);

[IterationCleanup]
public void CleanupIteration() => _iterationIndex = 0; // after every iteration end we set the index to 0

[BenchmarkCategory(Categories.Span)]
[Benchmark]
public void QuickSortSpan() => TestQuickSortSpan(new Span<int>(_arrays[_iterationIndex++]));

[BenchmarkCategory(Categories.Span)]
[Benchmark]
public void BubbleSortSpan() => TestBubbleSortSpan(new Span<int>(_arrays[_iterationIndex++]));

[Benchmark]
public void QuickSortArray() => TestQuickSortArray(_arrays[_iterationIndex++], 0, Size);

[Benchmark]
public void BubbleSortArray() => TestBubbleSortArray(_arrays[_iterationIndex++]);

[MethodImpl(MethodImplOptions.NoInlining)]
static void TestQuickSortArray(int[] data, int lo, int hi)
{
if (lo >= hi)
{
return;
}

int i, j;
int pivot, temp;
for (i = lo, j = hi, pivot = data[hi]; i < j;)
{
while (i < j && data[i] <= pivot)
{
++i;
}
while (j > i && data[j] >= pivot)
{
--j;
}
if (i < j)
{
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
if (i != hi)
{
temp = data[i];
data[i] = pivot;
data[hi] = temp;
}

TestQuickSortArray(data, lo, i - 1);
TestQuickSortArray(data, i + 1, hi);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void TestQuickSortSpan(Span<int> data)
{
if (data.Length <= 1)
{
return;
}

int lo = 0;
int hi = data.Length - 1;
int i, j;
int pivot, temp;
for (i = lo, j = hi, pivot = data[hi]; i < j;)
{
while (i < j && data[i] <= pivot)
{
++i;
}
while (j > i && data[j] >= pivot)
{
--j;
}
if (i < j)
{
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
if (i != hi)
{
temp = data[i];
data[i] = pivot;
data[hi] = temp;
}

TestQuickSortSpan(data.Slice(0, i));
TestQuickSortSpan(data.Slice(i + 1));
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void TestBubbleSortArray(int[] data)
{
bool swap;
int temp;
int n = data.Length - 1;
do
{
swap = false;
for (int i = 0; i < n; i++)
{
if (data[i] > data[i + 1])
{
temp = data[i];
data[i] = data[i + 1];
data[i + 1] = temp;
swap = true;
}
}
--n;
}
while (swap);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void TestBubbleSortSpan(Span<int> span)
{
bool swap;
int temp;
int n = span.Length - 1;
do
{
swap = false;
for (int i = 0; i < n; i++)
{
if (span[i] > span[i + 1])
{
temp = span[i];
span[i] = span[i + 1];
span[i + 1] = temp;
swap = true;
}
}
--n;
}
while (swap);
}
}
}
Loading

0 comments on commit 4b34c30

Please sign in to comment.