Files
2026-05-31 14:27:52 -07:00

143 lines
4.1 KiB
C#

using NUnit.Framework;
using Rukhanka.Hybrid;
using System;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Random = Unity.Mathematics.Random;
#if RUKHANKA_WITH_TEST_PERFORMANCE
using Unity.PerformanceTesting;
#endif
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Tests
{
[BurstCompile]
public class AnimatorParameterTest
{
#if RUKHANKA_WITH_TEST_PERFORMANCE
[BurstCompile]
static void ParameterAccessByLinearSearch(ref NativeSlice<AnimatorControllerParameterComponent> paramArr, int iterationCount, out int dummyResult)
{
var l = paramArr.Length;
dummyResult = 0;
for (int i = 0; i < iterationCount; ++i)
{
var idx = i % l;
var p = paramArr[idx];
bool found = false;
int k = 0;
for (; k < paramArr.Length && !found; ++k)
{
var candidat = paramArr[k];
found = candidat.hash == p.hash;
}
dummyResult += paramArr[k - 1].value.intValue;
}
}
/////////////////////////////////////////////////////////////////////////////////
NativeArray<AnimatorControllerParameterComponent> CreateTestParamArray(int len)
{
var paramArr = new NativeArray<AnimatorControllerParameterComponent>(len, Allocator.Temp);
var rng = new Random((uint)DateTime.Now.Millisecond + 1);
for (var i = 0; i < paramArr.Length; ++i)
{
var randomHash = rng.NextUInt();
var acpc = new AnimatorControllerParameterComponent()
{
hash = randomHash,
type = ControllerParameterType.Int,
value = default
};
paramArr[i] = acpc;
}
return paramArr;
}
/////////////////////////////////////////////////////////////////////////////////
[Test, Performance]
public void LinearSearchParameterAccess()
{
// Create test data
var paramArr = CreateTestParamArray(200);
var iterationsCount = 1000000;
var testGroupSize = new int[] {2, 5, 10, 20, 50, 100};
foreach (var paramCount in testGroupSize)
{
var paramArrForTest = new NativeSlice<AnimatorControllerParameterComponent>(paramArr, 0, paramCount);
Measure.Method(() =>
{
ParameterAccessByLinearSearch(ref paramArrForTest, iterationsCount, out var dummyResult);
})
.MeasurementCount(10)
.SampleGroup($"Linear Parameter Access. Parameter count: {paramArrForTest.Length}, Searches count: {iterationsCount}")
.Run();
}
}
/////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
static unsafe void ParameterAccessHashLookup(ref NativeSlice<AnimatorControllerParameterComponent> paramArr, ref BlobAssetReference<PerfectHashTableBlob> pht, int iterationCount, out int dummyResult)
{
dummyResult = 0;
var l = paramArr.Length;
for (int i = 0; i < iterationCount; ++i)
{
var idx = i % l;
var p = paramArr[idx];
var ps = new ReadOnlySpan<AnimatorControllerParameterComponent>(paramArr.GetUnsafePtr(), paramArr.Length);
var pi = FastAnimatorParameter.GetRuntimeParameterIndex(p.hash, pht, ps);
dummyResult += paramArr[pi].value.intValue;
}
}
/////////////////////////////////////////////////////////////////////////////////
[Test, Performance]
public void HashTableParameterAccess()
{
// Create test data
var paramArr = CreateTestParamArray(200);
var iterationsCount = 1000000;
var testGroupSize = new int[] {2, 5, 10, 20, 50, 100};
foreach (var paramCount in testGroupSize)
{
var paramArrSlice = new NativeSlice<AnimatorControllerParameterComponent>(paramArr, 0, paramCount);
var hashesArr = new NativeArray<uint>(paramCount, Allocator.Temp);
for (int i = 0; i < hashesArr.Length; ++i)
{
hashesArr[i] = paramArr[i].hash;
}
var perfectHashTableBlob = AnimatorControllerBaker.CreateParametersPerfectHashTableBlobInternal(hashesArr);
Measure.Method(() =>
{
ParameterAccessHashLookup(ref paramArrSlice, ref perfectHashTableBlob, iterationsCount, out _);
})
.MeasurementCount(10)
.SampleGroup($"Hash Table Parameter Access. Parameter count: {paramArrSlice.Length}, Searches count: {iterationsCount}")
.Run();
perfectHashTableBlob.Dispose();
}
}
#endif
}
}