-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from chrisg32/ModernPerformance
NaturalComparer performance improvements
- Loading branch information
Showing
15 changed files
with
558 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Collections.ObjectModel; | ||
using System.Reflection; | ||
using Xunit; | ||
|
||
namespace Commons.Benchmark; | ||
|
||
internal static class BenchmarkHelper | ||
{ | ||
public static List<object?[]> GetInlineData<TType>(string methodName) | ||
{ | ||
var type = typeof(TType); | ||
var member = type.GetMethod(methodName); | ||
if (member == null) throw new Exception($"Could not find a method named '{methodName}' on type '{type}'."); | ||
return member.CustomAttributes.Where(a => a.AttributeType == typeof(InlineDataAttribute)) | ||
.Select(a => (a.ConstructorArguments[0].Value as ReadOnlyCollection<CustomAttributeTypedArgument>)?.Select(v => v.Value).ToArray()).ToList()!; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" /> | ||
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.1" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Commons.Test\Commons.Test.csproj" /> | ||
<ProjectReference Include="..\Commons\Commons.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
using BenchmarkDotNet.Running; | ||
using Commons.Benchmark.Util; | ||
|
||
BenchmarkRunner.Run<NaturalComparerLargeSimilarStringBenchmarks>(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
### NaturalComparer | ||
|
||
#### Benchmark | ||
|
||
| Method | Mean | Error | StdDev | Allocated | | ||
|--------------------------------- |-----------:|---------:|---------:|----------:| | ||
| Compare | 222.8 ns | 4.30 ns | 5.12 ns | 360 B | | ||
| CompareIgnoreCase | 350.6 ns | 7.04 ns | 10.32 ns | 536 B | | ||
| CompareIgnoreWhiteSpace | 3,831.2 ns | 46.87 ns | 46.04 ns | 3,464 B | | ||
| CompareIgnoreCaseWhiteSpace | 3,982.3 ns | 37.84 ns | 31.59 ns | 3,640 B | | ||
| Compare_Span | 101.3 ns | 1.82 ns | 1.70 ns | - | | ||
| CompareIgnoreCase_Span | 137.6 ns | 2.49 ns | 2.33 ns | - | | ||
| CompareIgnoreWhiteSpace_Span | 1,632.6 ns | 12.74 ns | 9.95 ns | 376 B | | ||
| CompareIgnoreCaseWhiteSpace_Span | 1,756.9 ns | 29.59 ns | 27.68 ns | 376 B | | ||
|
||
#### Large Random String | ||
|
||
| Method | Mean | Error | StdDev | Allocated | | ||
|--------------------------------- |-------------:|-----------:|-----------:|----------:| | ||
| Compare | 541.04 ns | 5.690 ns | 5.322 ns | 2,360 B | | ||
| CompareIgnoreCase | 1,917.42 ns | 35.455 ns | 34.822 ns | 4,720 B | | ||
| CompareIgnoreWhiteSpace | 9,676.14 ns | 190.178 ns | 177.892 ns | 7,328 B | | ||
| CompareIgnoreCaseWhiteSpace | 10,953.94 ns | 147.037 ns | 137.539 ns | 10,816 B | | ||
| Compare_Span | 32.67 ns | 0.689 ns | 1.052 ns | - | | ||
| CompareIgnoreCase_Span | 24.55 ns | 0.416 ns | 0.369 ns | - | | ||
| CompareIgnoreWhiteSpace_Span | 3,440.01 ns | 66.125 ns | 73.498 ns | 4,704 B | | ||
| CompareIgnoreCaseWhiteSpace_Span | 3,797.10 ns | 49.217 ns | 41.098 ns | 4,688 B | | ||
|
||
#### Large Similar String | ||
|
||
| Method | Mean | Error | StdDev | Allocated | | ||
|--------------------------------- |---------:|----------:|----------:|----------:| | ||
| Compare | 4.988 us | 0.0638 us | 0.0597 us | 2,736 B | | ||
| CompareIgnoreCase | 5.421 us | 0.0992 us | 0.0928 us | 2,736 B | | ||
| CompareIgnoreWhiteSpace | 8.286 us | 0.1003 us | 0.0938 us | 4,712 B | | ||
| CompareIgnoreCaseWhiteSpace | 8.806 us | 0.1670 us | 0.1787 us | 4,712 B | | ||
| Compare_Span | 2.336 us | 0.0234 us | 0.0183 us | - | | ||
| CompareIgnoreCase_Span | 2.905 us | 0.0336 us | 0.0314 us | - | | ||
| CompareIgnoreWhiteSpace_Span | 3.189 us | 0.0609 us | 0.0570 us | 928 B | | ||
| CompareIgnoreCaseWhiteSpace_Span | 3.757 us | 0.0733 us | 0.0612 us | 928 B | | ||
|
||
##### Test Machine | ||
``` | ||
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1645 (21H2) | ||
Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores | ||
.NET SDK=6.0.202 | ||
[Host] : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT | ||
DefaultJob : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using CG.Commons.Util; | ||
#pragma warning disable CS0612 | ||
|
||
namespace Commons.Benchmark.Util; | ||
|
||
[MemoryDiagnoser(false)] | ||
public class NaturalComparerBenchmarks | ||
{ | ||
private NaturalComparerObsolete _comparerObsolete = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCase = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreWhitespace = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCaseWhitespace = null!; | ||
private NaturalComparer _comparer = null!; | ||
private NaturalComparer _comparerIgnoreCase = null!; | ||
private NaturalComparer _comparerIgnoreWhitespace = null!; | ||
private NaturalComparer _comparerIgnoreCaseWhitespace = null!; | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
_comparerObsolete = new NaturalComparerObsolete(); | ||
_comparerObsoleteIgnoreCase = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase); | ||
_comparerObsoleteIgnoreWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerObsoleteIgnoreCaseWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
|
||
_comparer = new NaturalComparer(); | ||
_comparerIgnoreCase = new NaturalComparer(NaturalComparerOptions.IgnoreCase); | ||
_comparerIgnoreWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerIgnoreCaseWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
} | ||
|
||
private const string Left = " ThisIsA StringWithANumber00201.3 "; | ||
private const string Right = " ThisIsA StringWithANumber00100.6 "; | ||
|
||
[Benchmark] | ||
public void Compare() => _ = _comparerObsolete.Compare(Left , Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase() => _ = _comparerObsoleteIgnoreCase.Compare(Left, Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace() => _ = _comparerObsoleteIgnoreWhitespace.Compare(Left, Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace() => _ = _comparerObsoleteIgnoreCaseWhitespace.Compare(Left, Right); | ||
|
||
|
||
|
||
[Benchmark] | ||
public void Compare_Span() => _ = _comparer.Compare(Left , Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase_Span() => _ = _comparerIgnoreCase.Compare(Left, Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace_Span() => _ = _comparerIgnoreWhitespace.Compare(Left, Right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace_Span() => _ = _comparerIgnoreCaseWhitespace.Compare(Left, Right); | ||
} |
76 changes: 76 additions & 0 deletions
76
Commons.Benchmark/Util/NaturalComparerLargeRandomStringBenchmarks.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using CG.Commons.Util; | ||
#pragma warning disable CS0612 | ||
|
||
namespace Commons.Benchmark.Util; | ||
|
||
[MemoryDiagnoser(false)] | ||
public class NaturalComparerLargeRandomStringBenchmarks | ||
{ | ||
private NaturalComparerObsolete _comparerObsolete = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCase = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreWhitespace = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCaseWhitespace = null!; | ||
private NaturalComparer _comparer = null!; | ||
private NaturalComparer _comparerIgnoreCase = null!; | ||
private NaturalComparer _comparerIgnoreWhitespace = null!; | ||
private NaturalComparer _comparerIgnoreCaseWhitespace = null!; | ||
|
||
private string _left = null!; | ||
private string _right = null!; | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
_comparerObsolete = new NaturalComparerObsolete(); | ||
_comparerObsoleteIgnoreCase = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase); | ||
_comparerObsoleteIgnoreWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerObsoleteIgnoreCaseWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
|
||
_comparer = new NaturalComparer(); | ||
_comparerIgnoreCase = new NaturalComparer(NaturalComparerOptions.IgnoreCase); | ||
_comparerIgnoreWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerIgnoreCaseWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
|
||
_left = GenerateString(600); | ||
_right = GenerateString(555); | ||
} | ||
|
||
private static string GenerateString(int i) | ||
{ | ||
var random = new Random(); | ||
var array = new char[i--]; | ||
for (; i >= 0; i--) | ||
{ | ||
array[i] = (char)random.Next(32, 122); | ||
} | ||
return new string(array); | ||
} | ||
|
||
|
||
[Benchmark] | ||
public void Compare() => _ = _comparerObsolete.Compare(_left , _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase() => _ = _comparerObsoleteIgnoreCase.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace() => _ = _comparerObsoleteIgnoreWhitespace.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace() => _ = _comparerObsoleteIgnoreCaseWhitespace.Compare(_left, _right); | ||
|
||
|
||
|
||
[Benchmark] | ||
public void Compare_Span() => _ = _comparer.Compare(_left , _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase_Span() => _ = _comparerIgnoreCase.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace_Span() => _ = _comparerIgnoreWhitespace.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace_Span() => _ = _comparerIgnoreCaseWhitespace.Compare(_left, _right); | ||
} |
87 changes: 87 additions & 0 deletions
87
Commons.Benchmark/Util/NaturalComparerLargeSimilarStringBenchmarks.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using CG.Commons.Util; | ||
#pragma warning disable CS0612 | ||
|
||
namespace Commons.Benchmark.Util; | ||
|
||
[MemoryDiagnoser(false)] | ||
public class NaturalComparerLargeSimilarStringBenchmarks | ||
{ | ||
private NaturalComparerObsolete _comparerObsolete = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCase = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreWhitespace = null!; | ||
private NaturalComparerObsolete _comparerObsoleteIgnoreCaseWhitespace = null!; | ||
private NaturalComparer _comparer = null!; | ||
private NaturalComparer _comparerIgnoreCase = null!; | ||
private NaturalComparer _comparerIgnoreWhitespace = null!; | ||
private NaturalComparer _comparerIgnoreCaseWhitespace = null!; | ||
|
||
private string _left = null!; | ||
private string _right = null!; | ||
|
||
[GlobalSetup] | ||
public void Setup() | ||
{ | ||
_comparerObsolete = new NaturalComparerObsolete(); | ||
_comparerObsoleteIgnoreCase = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase); | ||
_comparerObsoleteIgnoreWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerObsoleteIgnoreCaseWhitespace = new NaturalComparerObsolete(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
|
||
_comparer = new NaturalComparer(); | ||
_comparerIgnoreCase = new NaturalComparer(NaturalComparerOptions.IgnoreCase); | ||
_comparerIgnoreWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreWhiteSpace); | ||
_comparerIgnoreCaseWhitespace = new NaturalComparer(NaturalComparerOptions.IgnoreCase | NaturalComparerOptions.IgnoreWhiteSpace); | ||
|
||
_left = GenerateString(20, "abcdefg01.01"); | ||
_right = GenerateString(20, "abcdefg01.02"); | ||
} | ||
|
||
public static string GenerateString(int times, string seed) | ||
{ | ||
var decimals = seed.Count(c => c == '.'); | ||
var array = new char[times * (seed.Length - decimals) + decimals]; | ||
var i = 0; | ||
foreach (var c in seed) | ||
{ | ||
if (c == '.') | ||
{ | ||
array[i++] = c; | ||
} | ||
else | ||
{ | ||
for (var j = 0; j < times; j++, i++) | ||
{ | ||
array[i] = c; | ||
} | ||
} | ||
} | ||
return new string(array); | ||
} | ||
|
||
|
||
[Benchmark] | ||
public void Compare() => _ = _comparerObsolete.Compare(_left , _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase() => _ = _comparerObsoleteIgnoreCase.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace() => _ = _comparerObsoleteIgnoreWhitespace.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace() => _ = _comparerObsoleteIgnoreCaseWhitespace.Compare(_left, _right); | ||
|
||
|
||
|
||
[Benchmark] | ||
public void Compare_Span() => _ = _comparer.Compare(_left , _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCase_Span() => _ = _comparerIgnoreCase.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreWhiteSpace_Span() => _ = _comparerIgnoreWhitespace.Compare(_left, _right); | ||
|
||
[Benchmark] | ||
public void CompareIgnoreCaseWhiteSpace_Span() => _ = _comparerIgnoreCaseWhitespace.Compare(_left, _right); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.