Skip to content
Merged
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
34 changes: 0 additions & 34 deletions DictionaryEntry.sln

This file was deleted.

5 changes: 5 additions & 0 deletions DictionaryEntry.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Solution>
<Project Path="src/DictionaryEntry.Benchmarks/DictionaryEntry.Benchmarks.csproj" />
<Project Path="src/DictionaryEntry.Tests/DictionaryEntry.Tests.csproj" />
<Project Path="src/DictionaryEntry/DictionaryEntry.csproj" />
</Solution>
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.AdvancedOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("BatchOperations")]
public class BatchOperationsBenchmarks
[BenchmarkCategory("AdvancedOps")]
public class BatchOperationsBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
Expand Down Expand Up @@ -45,18 +43,17 @@ private void BatchOperationsEntry(string key)
value = Math.Min(100, value);
occupied.Insert(value);
},
vacant => vacant.Insert(5)
);
vacant => vacant.Insert(5));
}

[Benchmark(Baseline = true)]
public void BatchOperations_Traditional_Exists() => BatchOperationsTraditional(ExistingKey);

[Benchmark]
public void BatchOperations_Entry_Exists() => BatchOperationsEntry(ExistingKey);
public void BatchOperations_Traditional_NotExists() => BatchOperationsTraditional(NewKey);

[Benchmark]
public void BatchOperations_Traditional_NotExists() => BatchOperationsTraditional(NewKey);
public void BatchOperations_Entry_Exists() => BatchOperationsEntry(ExistingKey);

[Benchmark]
public void BatchOperations_Entry_NotExists() => BatchOperationsEntry(NewKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.AdvancedOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("PatternMatching")]
public class PatternMatchingBenchmarks
[BenchmarkCategory("AdvancedOps")]
public class PatternMatchingBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
Expand All @@ -30,25 +28,22 @@ private string PatternMatchingTraditional(string key)
_ => "Zero or negative"
};
}

return "Not found";
}

private string PatternMatchingEntry(string key)
{
return _dictionary.Entry(key).Match(
occupied =>
occupied => occupied.Value() switch
{
return occupied.Value() switch
{
> 100 => "Very large",
> 50 => "Large",
> 10 => "Medium",
> 0 => "Small",
_ => "Zero or negative"
};
> 100 => "Very large",
> 50 => "Large",
> 10 => "Medium",
> 0 => "Small",
_ => "Zero or negative"
},
_ => "Not found"
);
_ => "Not found");
}

private void DifferentActionsTraditional(string key)
Expand All @@ -67,8 +62,7 @@ private void DifferentActionsEntry(string key)
{
_dictionary.Entry(key).Match(
occupied => occupied.Insert(occupied.Value() * 2),
vacant => vacant.Insert(1)
);
vacant => vacant.Insert(1));
}

[Benchmark(Baseline = true)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using BenchmarkDotNet.Attributes;
// ReSharper disable PreferConcreteValueOverDefault
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.BasicOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("DefaultValue")]
public class DefaultValueBenchmarks
[BenchmarkCategory("BasicOps")]
public class DefaultValueBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private Dictionary<string, string?> _stringDictionary = null!;
Expand All @@ -28,6 +25,7 @@ private int DefaultValueTraditional(string key)
value = default;
_dictionary[key] = value;
}

return value;
}

Expand All @@ -38,6 +36,7 @@ private int DefaultValueTraditional(string key)
value = default;
_stringDictionary[key] = value;
}

return value;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks.BasicOps;

[BenchmarkCategory("BasicOps")]
public class DictionaryContainsBenchmarks : BenchmarkBase
{
private Dictionary<int, int> _dictionary = null!;
private const int ExistingKey = 42;
private const int MissingKey = 21;

[GlobalSetup]
public void Setup()
{
_dictionary = new Dictionary<int, int> { { ExistingKey, 1 } };
}

[Benchmark(Baseline = true)]
public bool TryGetValue_Found() => _dictionary.TryGetValue(ExistingKey, out _);

[Benchmark]
public bool Entry_IsOccupied_Found() => _dictionary.Entry(ExistingKey).IsOccupied();

[Benchmark]
public bool TryGetValue_NotFound() => _dictionary.TryGetValue(MissingKey, out _);

[Benchmark]
public bool Entry_IsOccupied_NotFound() => _dictionary.Entry(MissingKey).IsOccupied();
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.BasicOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("GetOrAdd")]
public class GetOrAddBenchmarks
[BenchmarkCategory("BasicOps")]
public class GetOrAddBenchmarks : BenchmarkBase
{
private Dictionary<int, int> _dictionary = null!;
private const int ExistingKey = 42;
Expand All @@ -26,14 +24,14 @@ public void Cleanup()

private int GetOrAddTraditional(int key)
{
if (_dictionary.TryGetValue(key, out var val))
if (_dictionary.TryGetValue(key, out var value))
{
return val;
return value;
}

val = 1;
_dictionary[key] = val;
return val;
value = 1;
_dictionary[key] = value;
return value;
}

private int GetOrAddEntry(int key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.BasicOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("IncrementCounter")]
public class IncrementCounterBenchmarks
[BenchmarkCategory("BasicOps")]
public class IncrementCounterBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.BasicOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("InitializeAbsent")]
public class InitializeAbsentBenchmarks
[BenchmarkCategory("BasicOps")]
public class InitializeAbsentBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks;
namespace DictionaryEntry.Benchmarks.BasicOps;

[MemoryDiagnoser]
[SimpleJob(invocationCount: 10_000_000)]
[BenchmarkCategory("GetAndRemove")]
public class GetAndRemoveBenchmarks
[BenchmarkCategory("BasicOps")]
public class RetrieveAndRemoveBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
Expand All @@ -19,12 +17,7 @@ public void Setup()

private int? GetAndRemoveTraditional(string key)
{
if (_dictionary.Remove(key, out var value))
{
return value;
}

return null;
return _dictionary.Remove(key, out var value) ? value : null;
}

private int? GetAndRemoveEntry(string key)
Expand Down
44 changes: 44 additions & 0 deletions src/DictionaryEntry.Benchmarks/BasicOps/TryGetEntryBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using BenchmarkDotNet.Attributes;

namespace DictionaryEntry.Benchmarks.BasicOps;

[BenchmarkCategory("BasicOps")]
public class TryGetEntryBenchmarks : BenchmarkBase
{
private Dictionary<string, int> _dictionary = null!;
private const string ExistingKey = "existing";
private const string MissingKey = "missing";

[GlobalSetup]
public void Setup()
{
_dictionary = new Dictionary<string, int> { { ExistingKey, 42 } };
}

private int? TryLookupTraditional(string key)
{
return _dictionary.TryGetValue(key, out var value) ? value : null;
}

private int? TryLookupEntry(string key)
{
if (_dictionary.Entry(key).TryGetOccupied(out var occupied))
{
return occupied.Value();
}

return null;
}

[Benchmark(Baseline = true)]
public int? TryLookup_Traditional_Exists() => TryLookupTraditional(ExistingKey);

[Benchmark]
public int? TryLookup_Traditional_NotExists() => TryLookupTraditional(MissingKey);

[Benchmark]
public int? TryLookup_Entry_Exists() => TryLookupEntry(ExistingKey);

[Benchmark]
public int? TryLookup_Entry_NotExists() => TryLookupEntry(MissingKey);
}
12 changes: 12 additions & 0 deletions src/DictionaryEntry.Benchmarks/BenchmarkBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Engines;

namespace DictionaryEntry.Benchmarks;

[SimpleJob(RunStrategy.Throughput, iterationCount: 15, warmupCount: 10, invocationCount: 100_000_000)]
[MemoryDiagnoser(displayGenColumns: false)]
[HideColumns("Error", "StdDev", "Median", "Ratio", "Alloc Ratio", "RatioSD")]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByJob)]
[CategoriesColumn]
public abstract class BenchmarkBase;
Loading