Created
March 31, 2025 00:15
-
-
Save Epicguru/1c816350caa433679c9d08e58af4aa8f to your computer and use it in GitHub Desktop.
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
using BenchmarkDotNet.Attributes; | |
namespace Testbed; | |
// Measure garbage collection and performance of HashCode.Combine. | |
[MemoryDiagnoser] | |
public class HashBenchmark | |
{ | |
[Benchmark(Baseline = true)] | |
public void RealImplementation() | |
{ | |
var hs = new Dictionary<UnityStruct, int>(400); | |
// Produces 80 hash collisions | |
for (int x = 0; x < 20; ++x) | |
{ | |
for (int y = 0; y < 20; ++y) | |
{ | |
var vector = new UnityStruct(x, y, 0); | |
hs[vector] = x; | |
} | |
} | |
var random = new Random(0); | |
for (int i = 0; i < 1000; i++) | |
{ | |
hs.TryGetValue(new UnityStruct(random.Next(0, 20), random.Next(0, 20), 0), out _); | |
hs.ContainsKey(new UnityStruct(random.Next(0, 20), random.Next(0, 20), 0)); | |
hs.TryAdd(new UnityStruct(random.Next(0, 200), random.Next(0, 200), 0), 5); | |
} | |
} | |
[Benchmark] | |
public void AlternativeHash() | |
{ | |
var hs = new Dictionary<AlternativeStruct, int>(400); | |
// Produces 0 hash collisions | |
for (int x = 0; x < 20; ++x) | |
{ | |
for (int y = 0; y < 20; ++y) | |
{ | |
var vector = new AlternativeStruct(x, y, 0); | |
hs[vector] = x; | |
} | |
} | |
var random = new Random(0); | |
for (int i = 0; i < 1000; i++) | |
{ | |
hs.TryGetValue(new AlternativeStruct(random.Next(0, 20), random.Next(0, 20), 0), out _); | |
hs.ContainsKey(new AlternativeStruct(random.Next(0, 20), random.Next(0, 20), 0)); | |
hs.TryAdd(new AlternativeStruct(random.Next(0, 200), random.Next(0, 200), 0), 5); | |
} | |
} | |
[Benchmark] | |
public void FixedHash() | |
{ | |
var hs = new Dictionary<FixedHashStruct, int>(400); | |
// Produces 400 hash collisions | |
for (int x = 0; x < 20; ++x) | |
{ | |
for (int y = 0; y < 20; ++y) | |
{ | |
var vector = new FixedHashStruct(x, y, 0); | |
hs[vector] = x; | |
} | |
} | |
var random = new Random(0); | |
for (int i = 0; i < 1000; i++) | |
{ | |
hs.TryGetValue(new FixedHashStruct(random.Next(0, 20), random.Next(0, 20), 0), out _); | |
hs.ContainsKey(new FixedHashStruct(random.Next(0, 20), random.Next(0, 20), 0)); | |
hs.TryAdd(new FixedHashStruct(random.Next(0, 200), random.Next(0, 200), 0), 5); | |
} | |
} | |
} | |
public struct UnityStruct : IEquatable<UnityStruct> | |
{ | |
public int X; | |
public int Y; | |
public int Z; | |
public UnityStruct(int x, int y, int z) | |
{ | |
X = x; | |
Y = y; | |
Z = z; | |
} | |
public readonly override int GetHashCode() | |
{ | |
var yHash = Y.GetHashCode(); | |
var zHash = Z.GetHashCode(); | |
return X.GetHashCode() ^ (yHash << 4) ^ (yHash >> 28) ^ (zHash >> 4) ^ (zHash << 28); | |
} | |
public bool Equals(UnityStruct other) => X == other.X && Y == other.Y && Z == other.Z; | |
public override bool Equals(object? obj) => obj is UnityStruct other && Equals(other); | |
} | |
public struct AlternativeStruct : IEquatable<AlternativeStruct> | |
{ | |
public int X; | |
public int Y; | |
public int Z; | |
public AlternativeStruct(int x, int y, int z) | |
{ | |
X = x; | |
Y = y; | |
Z = z; | |
} | |
public readonly override int GetHashCode() | |
{ | |
return HashCode.Combine(X, Y, Z); | |
} | |
public bool Equals(AlternativeStruct other) => X == other.X && Y == other.Y && Z == other.Z; | |
public override bool Equals(object? obj) => obj is AlternativeStruct other && Equals(other); | |
} | |
public struct FixedHashStruct : IEquatable<FixedHashStruct> | |
{ | |
public int X; | |
public int Y; | |
public int Z; | |
public FixedHashStruct(int x, int y, int z) | |
{ | |
X = x; | |
Y = y; | |
Z = z; | |
} | |
public readonly override int GetHashCode() => 1234; | |
public bool Equals(FixedHashStruct other) => X == other.X && Y == other.Y && Z == other.Z; | |
public override bool Equals(object? obj) => obj is FixedHashStruct other && Equals(other); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Results on .NET 9: