diff --git a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs new file mode 100644 index 0000000000..2a6a23116e --- /dev/null +++ b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs @@ -0,0 +1,90 @@ +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Memory +{ + using System.Linq; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using SixLabors.ImageSharp.Memory; + + using Xunit; + + public class ArrayPoolMemoryManagerTests + { + private const int MaxPooledBufferSizeInBytes = 2048; + + private MemoryManager MemoryManager { get; } = new ArrayPoolMemoryManager(MaxPooledBufferSizeInBytes); + + /// + /// Rent 'n' buffers -> return all -> re-rent, verify if there is at least one in common. + /// + private bool CheckIsPooled(int size) + where T : struct + { + IBuffer buf1 = this.MemoryManager.Allocate(size); + IBuffer buf2 = this.MemoryManager.Allocate(size); + IBuffer buf3 = this.MemoryManager.Allocate(size); + + ref T buf1FirstPrev = ref buf1.DangerousGetPinnableReference(); + ref T buf2FirstPrev = ref buf2.DangerousGetPinnableReference(); + ref T buf3FirstPrev = ref buf3.DangerousGetPinnableReference(); + + buf1.Dispose(); + buf2.Dispose(); + buf3.Dispose(); + + buf1 = this.MemoryManager.Allocate(size); + buf2 = this.MemoryManager.Allocate(size); + buf3 = this.MemoryManager.Allocate(size); + + bool same1 = Unsafe.AreSame(ref buf1FirstPrev, ref buf1.DangerousGetPinnableReference()); + bool same2 = Unsafe.AreSame(ref buf2FirstPrev, ref buf2.DangerousGetPinnableReference()); + bool same3 = Unsafe.AreSame(ref buf3FirstPrev, ref buf3.DangerousGetPinnableReference()); + + buf1.Dispose(); + buf2.Dispose(); + buf3.Dispose(); + + return same1 || same2 || same3; + } + + [StructLayout(LayoutKind.Explicit, Size = MaxPooledBufferSizeInBytes / 4)] + struct LargeStruct + { + } + + [Theory] + [InlineData(32)] + [InlineData(512)] + [InlineData(MaxPooledBufferSizeInBytes - 1)] + public void SmallBuffersArePooled_OfByte(int size) + { + Assert.True(this.CheckIsPooled(size)); + } + + + [Theory] + [InlineData(128 * 1024 * 1024)] + [InlineData(MaxPooledBufferSizeInBytes + 1)] + public void LargeBuffersAreNotPooled_OfByte(int size) + { + Assert.False(this.CheckIsPooled(size)); + } + + [Fact] + public unsafe void SmallBuffersArePooled_OfBigValueType() + { + int count = MaxPooledBufferSizeInBytes / sizeof(LargeStruct) - 1; + + Assert.True(this.CheckIsPooled(count)); + } + + [Fact] + public unsafe void LaregeBuffersAreNotPooled_OfBigValueType() + { + int count = MaxPooledBufferSizeInBytes / sizeof(LargeStruct) + 1; + + Assert.False(this.CheckIsPooled(count)); + } + } +} \ No newline at end of file