Skip to content

Commit f2464ae

Browse files
committed
added benchmarking
1 parent e9fdc1f commit f2464ae

8 files changed

+261
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
12+
</ItemGroup>
13+
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\src\SpanExtensions.csproj" />
17+
</ItemGroup>
18+
19+
</Project>

PerformanceTests/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using BenchmarkDotNet.Running;
2+
3+
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Any_Benchmark
7+
{
8+
9+
[Benchmark]
10+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
11+
public int Split_Any_ReadOnlySpan(ReadOnlySpan<char> value, char[] delimiters)
12+
{
13+
int count = 0;
14+
foreach(ReadOnlySpan<char> part in value.SplitAny(delimiters))
15+
{
16+
count += part.Length;
17+
}
18+
return count;
19+
}
20+
21+
[Benchmark(Baseline = true)]
22+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
23+
public int Split_Any_String(string value, char[] delimiters)
24+
{
25+
return value.Split(delimiters).Length;
26+
}
27+
28+
public IEnumerable<object[]> GetArgsWithDelimiter()
29+
{
30+
yield return new object[] { "abcde", new object[] { 'b', 'd' } };
31+
yield return new object[] { "abcdefg", new object[] { 'b', 'd', 'f' } };
32+
yield return new object[] { "abba", new object[] { 'b', 'a' } };
33+
yield return new object[] { "1234567890", new object[] { '1', '5', '7' } };
34+
}
35+
}
36+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Benchmark
7+
{
8+
9+
[Benchmark]
10+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
11+
public int Split_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter)
12+
{
13+
int count = 0;
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter))
15+
{
16+
count += part.Length;
17+
}
18+
return count;
19+
}
20+
21+
[Benchmark(Baseline = true)]
22+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
23+
public int Split_String(string value, char delimiter)
24+
{
25+
return value.Split(delimiter).Length;
26+
}
27+
28+
public IEnumerable<object[]> GetArgsWithDelimiter()
29+
{
30+
yield return new object[] { "xyz", 'y' };
31+
yield return new object[] { "abcde", 'c' };
32+
yield return new object[] { "abcdefg", 'd' };
33+
yield return new object[] { "abba", 'b' };
34+
yield return new object[] { "aaa", 'a' };
35+
yield return new object[] { "aba", 'a' };
36+
yield return new object[] { "12131415161718190", '1' };
37+
}
38+
}
39+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Count_Benchmark
7+
{
8+
9+
[Benchmark]
10+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
11+
public int Split_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count)
12+
{
13+
int length = 0;
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count))
15+
{
16+
length += part.Length;
17+
}
18+
return length;
19+
}
20+
21+
[Benchmark(Baseline = true)]
22+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
23+
public int Split_String(string value, char delimiter, int count)
24+
{
25+
return value.Split(delimiter, count).Length;
26+
}
27+
28+
[Benchmark]
29+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
30+
public int Split_CutLastElements_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count)
31+
{
32+
int length = 0;
33+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, CountExceedingBehaviour.CutLastElements))
34+
{
35+
length += part.Length;
36+
}
37+
return length;
38+
}
39+
40+
public IEnumerable<object[]> GetArgsWithDelimiterAndCount()
41+
{
42+
yield return ["xyz", 'y', 1];
43+
yield return ["aba", 'a', 2];
44+
yield return ["12131415161718190", '1', 3];
45+
yield return ["12131415161718190", '1', 2];
46+
yield return ["12131415161718190", '1', 7];
47+
}
48+
}
49+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Count_StringSplitOptions_Benchmark
7+
{
8+
9+
[Benchmark]
10+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
11+
public int Split_Count_StringSplitOptions_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count, StringSplitOptions options)
12+
{
13+
int length = 0;
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, options))
15+
{
16+
length += part.Length;
17+
}
18+
return length;
19+
}
20+
21+
[Benchmark(Baseline = true)]
22+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
23+
public int Split_Count_StringSplitOptions_String(string value, char delimiter, int count, StringSplitOptions options)
24+
{
25+
return value.Split(delimiter, count, options).Length;
26+
}
27+
28+
[Benchmark]
29+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
30+
public int Split_Count_StringSplitOptions_CountExceedingBehaviour_CutLastElements_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count, StringSplitOptions options)
31+
{
32+
int length = 0;
33+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, options, CountExceedingBehaviour.CutLastElements))
34+
{
35+
length += part.Length;
36+
}
37+
return length;
38+
}
39+
40+
public IEnumerable<object[]> GetArgsWithDelimiterAndCountAndStringSplitOptions()
41+
{
42+
yield return new object[] { "12131415161718190", '1', 3, StringSplitOptions.None };
43+
yield return new object[] { "12131415161718190", '1', 2, StringSplitOptions.None };
44+
yield return ["abba", 'b', 4, StringSplitOptions.None];
45+
yield return ["aaa", 'a', 1, StringSplitOptions.None];
46+
yield return ["aba", 'a', 10, StringSplitOptions.None];
47+
yield return ["12131415161718190", '1', 12, StringSplitOptions.None];
48+
yield return [" xy z", 'y', 2, StringSplitOptions.TrimEntries];
49+
yield return ["a bcd e", 'c', 1, StringSplitOptions.TrimEntries];
50+
yield return [" ab cdef g ", 'd', 4, StringSplitOptions.TrimEntries];
51+
yield return ["abb", 'b', 1, StringSplitOptions.RemoveEmptyEntries];
52+
yield return ["abb", 'b', 2, StringSplitOptions.RemoveEmptyEntries];
53+
yield return ["aaa", 'a', 1, StringSplitOptions.RemoveEmptyEntries];
54+
yield return ["aaa", 'a', 2, StringSplitOptions.RemoveEmptyEntries];
55+
yield return ["aba ", 'a', 1, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
56+
yield return ["aba ", 'a', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
57+
yield return ["aba ", 'a', 3, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
58+
yield return ["1 13141516171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
59+
yield return ["1 131 151 171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
60+
yield return ["1131151171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
61+
}
62+
}
63+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_StringSplitOptions_Benchmark
7+
{
8+
9+
[Benchmark]
10+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndStringSplitOptions))]
11+
public int Split_StringSplitOptions_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, StringSplitOptions options)
12+
{
13+
int count = 0;
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, options))
15+
{
16+
count += part.Length;
17+
}
18+
return count;
19+
}
20+
21+
[Benchmark(Baseline = true)]
22+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndStringSplitOptions))]
23+
public int Split_StringSplitOptions_String(string value, char delimiter, StringSplitOptions options)
24+
{
25+
return value.Split(delimiter, options).Length;
26+
}
27+
28+
public IEnumerable<object[]> GetArgsWithDelimiterAndStringSplitOptions()
29+
{
30+
yield return ["xyz", 'y', StringSplitOptions.None];
31+
yield return ["abcde", 'c', StringSplitOptions.None];
32+
yield return ["abcdefg", 'd', StringSplitOptions.None];
33+
yield return ["abba", 'b', StringSplitOptions.None];
34+
yield return ["aaa", 'a', StringSplitOptions.None];
35+
yield return ["aba", 'a', StringSplitOptions.None];
36+
yield return ["12131415161718190", '1', StringSplitOptions.None];
37+
yield return [" xy z", 'y', StringSplitOptions.TrimEntries];
38+
yield return ["a bcd e", 'c', StringSplitOptions.TrimEntries];
39+
yield return [" ab cdef g ", 'd', StringSplitOptions.TrimEntries];
40+
yield return ["abb", 'b', StringSplitOptions.RemoveEmptyEntries];
41+
yield return ["aaa", 'a', StringSplitOptions.RemoveEmptyEntries];
42+
yield return ["aba ", 'a', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
43+
yield return ["1 13141516171 190", '1', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
44+
}
45+
}
46+
}

SpanExtensions.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.5.33627.172
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpanExtensions", "src\SpanExtensions.csproj", "{75DE5AFD-663E-415D-9B95-6BC513BD4A07}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerformanceTests", "PerformanceTests\PerformanceTests.csproj", "{CE74F420-1038-4E51-AC31-00DA964CC4F5}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
1517
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)