Skip to content

Instantly share code, notes, and snippets.

@melodia-games
Last active February 27, 2023 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melodia-games/332af80ccad18f2a38b280ac43b2ba75 to your computer and use it in GitHub Desktop.
Save melodia-games/332af80ccad18f2a38b280ac43b2ba75 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using Unity.Mathematics;
using Unity.PerformanceTesting;
//TestRunnerでの実行結果
//Index, Test Name, Version, SampleGroup Name, Unit, IncreaseIsBetter, Min, Max, Median, Average, StandardDeviation, Sum, Values,
//0,"Tests.TestPerformance.Test1",1,"Time","Millisecond",False,12438.2421,12881.16,12617.7891,12627.81142,150.106165086222,252556.2284,12490.3192,12588.2658,12568.1306,12473.9098,12459.1209,12438.2421,12725.6194,12778.6197,12863.0169,12465.9704,12707.7957,12857.5514,12617.7891,12767.8108,12777.468,12463.3161,12480.823,12524.9632,12881.16,12626.3363,
//1,"Tests.TestPerformance.Test2",1,"Time","Millisecond",False,15938.8846,16505.6858,16049.095,16124.86212,186.346231117262,322497.2424,16028.2931,15941.1558,16013.6348,15938.8846,15971.258,15980.1984,16112.7227,16049.095,16024.2381,15981.0402,16088.1292,16014.152,15968.7511,16127.7099,16291.8043,16505.6858,16435.8812999999,16485.3993,16417.4963,16121.7125,
//2,"Tests.TestPerformance.Test3",1,"Time","Millisecond",False,6260.8965,7737.7331,6503.6336,6659.80726,450.464388839386,133196.1452,6341.6141,6334.4877,6260.8965,6871.6594,7053.5972,7693.09649999999,7737.7331,7324.06090000001,6503.6336,6431.834,6311.18210000001,6319.2745,6399.9785,6298.7689,6317.64159999999,6379.83660000001,6594.13519999999,6547.22079999998,6531.54820000002,6943.94580000002,
//3,"Tests.TestPerformance.Test4",1,"Time","Millisecond",False,4141.6657,4450.3624,4291.6683,4291.56786,86.7366240374471,85831.3572,4291.6683,4308.0922,4141.6657,4229.3268,4248.4632,4202.32049999999,4333.6962,4399.51590000001,4349.0954,4247.6873,4266.8997,4301.83660000001,4391.0625,4335.88119999999,4171.9843,4280.39409999999,4288.29000000001,4450.3624,4443.3284,4149.7865,
//4,"Tests.TestPerformance.Test5",1,"Time","Millisecond",False,2346.7899,2508.5416,2413.6465,2414.701275,37.8625926773892,48294.0255,2346.7899,2432.7252,2361.459,2411.0666,2404.8773,2389.3895,2406.8033,2366.409,2382.0981,2448.4486,2449.3874,2449.3305,2508.5416,2381.76730000001,2421.8413,2460.1267,2418.8666,2443.31529999999,2397.1358,2413.6465,
namespace Tests
{
public class TestHashCodePerformance
{
const int Range = 1000;
const int WarmupCount = 5;
const int IterationsPerMeasurement = 10;
const int MeasurementCount = 20;
[Test]
[Performance]
public void Test1() => TestLoops((x, y) => new TestStruct1(x, y));
[Test]
[Performance]
public void Test2() => TestLoops((x, y) => new TestStruct2(x, y));
[Test]
[Performance]
public void Test3() => TestLoops((x, y) => new TestStruct3(x, y));
[Test]
[Performance]
public void Test4() => TestLoops((x, y) => new TestStruct4(x, y));
[Test]
[Performance]
public void Test5() => TestLoops((x, y) => new TestStruct5(x, y));
void TestLoops<T>(Func<int, int, T> hashGetter)
{
Measure.Method(() => {
// 衝突した状態での線形探索コストが計測できるように
// Keyをx,yのstructにしてHashCodeが衝突してもEqualsが異なる状態を作る
var map = new Dictionary<T, bool>();
for (int x = -Range; x <= Range; x++) {
for (int y = -Range; y <= Range; y++) {
// Add
var key = hashGetter(x, y);
map.Add(key, true);
// Lookup
var value = map[key];
// 最適化で消えないために適当な処理を入れる
Debug.Assert(value != !value);
}
}
})
.WarmupCount(WarmupCount)
.IterationsPerMeasurement(IterationsPerMeasurement)
.MeasurementCount(MeasurementCount)
.Run();
}
public readonly struct TestStruct1 : IEquatable<TestStruct1>
{
public readonly int x;
public readonly int y;
public TestStruct1(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return (x, y).GetHashCode();
}
public bool Equals(TestStruct1 other)
{
return x == other.x && y == other.y;
}
public override bool Equals(object other)
{
if (other is TestStruct1 point) {
return Equals(point);
}
return false;
}
}
public readonly struct TestStruct2 : IEquatable<TestStruct2>
{
public readonly int x;
public readonly int y;
public TestStruct2(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return (17 * 23 + x) * 23 + y;
}
public bool Equals(TestStruct2 other)
{
return x == other.x && y == other.y;
}
public override bool Equals(object other)
{
if (other is TestStruct2 point) {
return Equals(point);
}
return false;
}
}
public readonly struct TestStruct3 : IEquatable<TestStruct3>
{
public readonly int x;
public readonly int y;
public TestStruct3(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return HashCode.Combine(x, y);
}
public bool Equals(TestStruct3 other)
{
return x == other.x && y == other.y;
}
public override bool Equals(object other)
{
if (other is TestStruct3 point) {
return Equals(point);
}
return false;
}
}
public readonly struct TestStruct4 : IEquatable<TestStruct4>
{
public readonly int x;
public readonly int y;
public TestStruct4(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return new int2(x, y).GetHashCode();
}
public bool Equals(TestStruct4 other)
{
return x == other.x && y == other.y;
}
public override bool Equals(object other)
{
if (other is TestStruct4 point) {
return Equals(point);
}
return false;
}
}
public readonly struct TestStruct5 : IEquatable<TestStruct5>
{
public readonly int x;
public readonly int y;
public TestStruct5(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return (x << 16) ^ y;
}
public bool Equals(TestStruct5 other)
{
return x == other.x && y == other.y;
}
public override bool Equals(object other)
{
if (other is TestStruct5 point) {
return Equals(point);
}
return false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment