Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utils & tests & recursion benchmark #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Benchmarks/BasicConstructions/BasicConstructions.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\_BenchmarkUtils\_BenchmarkUtils.csproj" />
</ItemGroup>

</Project>
13 changes: 13 additions & 0 deletions Benchmarks/BasicConstructions/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using BenchmarkDotNet.Running;
using System;

namespace BasicConstructions
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<Recursion>();
}
}
}
90 changes: 90 additions & 0 deletions Benchmarks/BasicConstructions/Recursion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using BenchmarkDotNet;
using BenchmarkDotNet.Attributes;
using BenchmarkUtils;

namespace BasicConstructions
{
public class Recursion
{
[GlobalSetup]
public void Setup()
{

}

private const int NumberCount = 10; // shouldn't be too high to avoid benching RAM
private const int IterCount = 10;
private const int RandomSeed = 10;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FromIterToNumber(int id) => id + 100;

public static int GCDRec(int a, int b)
{
if (a == 0)
return b;
if (b == 0)
return a;
if (a > b)
return GCDRec(a % b, b);
else
return GCDRec(a, b % a);
}

[Benchmark]
public void BenchRecursion()
{

var sm = new SequentialRandom(new Random(RandomSeed), NumberCount);
for (int i = 0; i < IterCount; i++)
{
for (int x = 0; x < NumberCount; x++)
{
GCDRec(FromIterToNumber(sm.Next()), FromIterToNumber(sm.Next()));
}
}
}

public static int GCDLoop(int a, int b)
{
while (b > 0)
{
(a, b) = (b, a % b);
}
return a == 0 ? b : a;
}

[Benchmark]
public void BenchWhile()
{
var sm = new SequentialRandom(new Random(RandomSeed), NumberCount);
for (int i = 0; i < IterCount; i++)
{
for (int x = 0; x < NumberCount; x++)
{
GCDLoop(FromIterToNumber(sm.Next()), FromIterToNumber(sm.Next()));
}
}
}
}
}

/*

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.1139 (1909/November2018Update/19H2)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.100-rc.2.20479.15
[Host] : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
DefaultJob : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT


| Method | Mean | Error | StdDev |
|--------------- |---------:|----------:|----------:|
| BenchRecursion | 3.142 us | 0.0587 us | 0.0628 us |
| BenchWhile | 3.057 us | 0.0564 us | 0.0528 us |

*/
47 changes: 47 additions & 0 deletions Benchmarks/_BenchmarkUtils/SequentialRandom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace BenchmarkUtils
{
/// <summary>
/// Used to go over a permutations of numbers from 0 to arrayLength - 1 inclusive,
/// that is, if you need to go over all elements from 0 to 99 without order,
/// you should pass 100 as the only ctor's argument
/// </summary>
public unsafe struct SequentialRandom
{
private Random random;
private int arrayLength;
private int[] array;
private int currentState;

public SequentialRandom(Random random, int arrayLength)
{
this.random = random;
this.arrayLength = arrayLength;

// that's just a permutation
var loop = Enumerable.Range(0, arrayLength).OrderBy(_ => random.Next(0, arrayLength * 100)).ToArray();

// here we create an array such that we will guaranteedly go over the whole array
array = new int[arrayLength];
for (int i = 0; i < arrayLength - 1; i++)
array[loop[i]] = loop[i + 1];
array[loop[loop.Length - 1]] = loop[0];


currentState = 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Next()
{
fixed (int* arrayPointer = array)
{
currentState = arrayPointer[currentState];
}
return currentState;
}
}
}
15 changes: 15 additions & 0 deletions Benchmarks/_BenchmarkUtils/_BenchmarkUtils.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

</Project>
6 changes: 6 additions & 0 deletions Benchmarks/_BenchmarkUtils/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Benchmark utils

It's not a benchmark! It's a class library for shared code between benchmarks.

### Functional

18 changes: 18 additions & 0 deletions Benchmarks/_Tests/GCDTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using BasicConstructions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace _Tests
{
[TestClass]
public class GCDTest
{
[TestMethod] public void TestRecGCD1() => Assert.AreEqual(5, Recursion.GCDRec(15, 5));
[TestMethod] public void TestRecGCD2() => Assert.AreEqual(1, Recursion.GCDRec(15, 4));
[TestMethod] public void TestRecGCD3() => Assert.AreEqual(5, Recursion.GCDRec(5, 15));
[TestMethod] public void TestRecGCD4() => Assert.AreEqual(1, Recursion.GCDRec(4, 15));
[TestMethod] public void TestLoopGCD1() => Assert.AreEqual(5, Recursion.GCDLoop(15, 5));
[TestMethod] public void TestLoopGCD2() => Assert.AreEqual(1, Recursion.GCDLoop(15, 4));
[TestMethod] public void TestLoopGCD3() => Assert.AreEqual(5, Recursion.GCDLoop(5, 15));
[TestMethod] public void TestLoopGCD4() => Assert.AreEqual(1, Recursion.GCDLoop(4, 15));
}
}
3 changes: 3 additions & 0 deletions Benchmarks/_Tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Tests

Tests for utils and benchmarks
36 changes: 36 additions & 0 deletions Benchmarks/_Tests/SequentialRandomTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BenchmarkUtils;
using System.Linq;

namespace _Tests
{
[TestClass]
public class SequentialRandomTest
{
private void TestShortWithSeed(int seed, int skipped)
{
SequentialRandom r = new(new(seed), 10);

for (int _ = 0; _ < skipped; _++)
r.Next(); // since it's circular, we can skip a few

var b = new bool[10];
for (int _ = 0; _ < 10; _++)
b[r.Next()] = true;
Assert.IsTrue(b.All(c => c), string.Join(", ", b));
}

[TestMethod] public void TestShort0() => TestShortWithSeed(10, 0);
[TestMethod] public void TestShort1() => TestShortWithSeed(20, 0);
[TestMethod] public void TestShort2() => TestShortWithSeed(30, 0);
[TestMethod] public void TestShort3() => TestShortWithSeed(40, 0);
[TestMethod] public void TestShort4() => TestShortWithSeed(50, 0);
[TestMethod] public void TestShort5() => TestShortWithSeed(60, 0);
[TestMethod] public void TestShort0WithSkipped() => TestShortWithSeed(10, 3);
[TestMethod] public void TestShort1WithSkipped() => TestShortWithSeed(20, 3);
[TestMethod] public void TestShort2WithSkipped() => TestShortWithSeed(30, 3);
[TestMethod] public void TestShort3WithSkipped() => TestShortWithSeed(40, 3);
[TestMethod] public void TestShort4WithSkipped() => TestShortWithSeed(50, 3);
[TestMethod] public void TestShort5WithSkipped() => TestShortWithSeed(60, 3);
}
}
21 changes: 21 additions & 0 deletions Benchmarks/_Tests/_Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BasicConstructions\BasicConstructions.csproj" />
<ProjectReference Include="..\_BenchmarkUtils\_BenchmarkUtils.csproj" />
</ItemGroup>

</Project>
20 changes: 19 additions & 1 deletion Benchmarks/dotnet-benchmarks.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExceptionHandlingTechniques
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReflectionTechniques", "ReflectionTechniques\ReflectionTechniques.csproj", "{4320629B-EB16-405E-AF83-49DA499043E9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Boxing", "Boxing\Boxing\Boxing.csproj", "{E6C9254E-3E6A-4073-9486-C55286521575}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Boxing", "Boxing\Boxing\Boxing.csproj", "{E6C9254E-3E6A-4073-9486-C55286521575}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicConstructions", "BasicConstructions\BasicConstructions.csproj", "{B327DD0F-3E2D-4D4C-A9BA-EA6D4D9AAB05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_BenchmarkUtils", "_BenchmarkUtils\_BenchmarkUtils.csproj", "{A92C94E8-9140-4733-9DB9-6377DB58627C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_Tests", "_Tests\_Tests.csproj", "{043BB8EF-FE8F-4E40-B7A3-8943F9438CF7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -63,6 +69,18 @@ Global
{E6C9254E-3E6A-4073-9486-C55286521575}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6C9254E-3E6A-4073-9486-C55286521575}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6C9254E-3E6A-4073-9486-C55286521575}.Release|Any CPU.Build.0 = Release|Any CPU
{B327DD0F-3E2D-4D4C-A9BA-EA6D4D9AAB05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B327DD0F-3E2D-4D4C-A9BA-EA6D4D9AAB05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B327DD0F-3E2D-4D4C-A9BA-EA6D4D9AAB05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B327DD0F-3E2D-4D4C-A9BA-EA6D4D9AAB05}.Release|Any CPU.Build.0 = Release|Any CPU
{A92C94E8-9140-4733-9DB9-6377DB58627C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A92C94E8-9140-4733-9DB9-6377DB58627C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A92C94E8-9140-4733-9DB9-6377DB58627C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A92C94E8-9140-4733-9DB9-6377DB58627C}.Release|Any CPU.Build.0 = Release|Any CPU
{043BB8EF-FE8F-4E40-B7A3-8943F9438CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{043BB8EF-FE8F-4E40-B7A3-8943F9438CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{043BB8EF-FE8F-4E40-B7A3-8943F9438CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{043BB8EF-FE8F-4E40-B7A3-8943F9438CF7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down