From 98e5ca74337516d1a6bd5a48b36432bd987998db Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 2 Feb 2020 19:50:35 +0100 Subject: [PATCH] More tests for MemoryGroup.Allocate() --- .../DiscontiguousBuffers/MemoryGroup{T}.cs | 5 +- .../DiscontiguousBuffers/MemoryGroupTests.cs | 33 ++++++++- .../TestUtilities/TestMemoryAllocator.cs | 67 ++++++++++++------- 3 files changed, 79 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 670a0aaf6d..e9c0be02d3 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -27,7 +27,10 @@ namespace SixLabors.ImageSharp.Memory public bool IsValid { get; protected set; } // bufferLengthAlignment == image.Width in row-major images - public static MemoryGroup Allocate(MemoryAllocator allocator, long totalLength, int blockAlignment) + public static MemoryGroup Allocate(MemoryAllocator allocator, + long totalLength, + int blockAlignment, + AllocationOptions allocationOptions = AllocationOptions.None) { long bufferCount = totalLength / allocator.GetBlockCapacity(); diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs index adb398ee66..85aebb874a 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using Xunit; @@ -80,6 +81,36 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers MemoryGroup.Allocate(this.memoryAllocator, 50, 43); }); } + + [Theory] + [InlineData(AllocationOptions.None)] + [InlineData(AllocationOptions.Clean)] + public void MemoryAllocator_IsUtilizedCorrectly(AllocationOptions allocationOptions) + { + this.memoryAllocator.BlockCapacity = 200; + + HashSet bufferHashes; + + int expectedBlockCount = 5; + using (var g = MemoryGroup.Allocate(this.memoryAllocator, 500, 100, allocationOptions)) + { + IReadOnlyList allocationLog = this.memoryAllocator.AllocationLog; + Assert.Equal(expectedBlockCount, allocationLog.Count); + bufferHashes = allocationLog.Select(l => l.HashCodeOfBuffer).ToHashSet(); + Assert.Equal(expectedBlockCount, bufferHashes.Count); + Assert.Equal(0, this.memoryAllocator.ReturnLog.Count); + + for (int i = 0; i < expectedBlockCount; i++) + { + Assert.Equal(allocationOptions, allocationLog[i].AllocationOptions); + Assert.Equal(100, allocationLog[i].Length); + Assert.Equal(200, allocationLog[i].LengthInBytes); + } + } + + Assert.Equal(expectedBlockCount, this.memoryAllocator.ReturnLog.Count); + Assert.True(bufferHashes.SetEquals(this.memoryAllocator.ReturnLog.Select(l => l.HashCodeOfBuffer))); + } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs index 6f9473116a..c49a689901 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs @@ -13,7 +13,8 @@ namespace SixLabors.ImageSharp.Tests.Memory { internal class TestMemoryAllocator : MemoryAllocator { - private List allocationLog = new List(); + private readonly List allocationLog = new List(); + private readonly List returnLog = new List(); public TestMemoryAllocator(byte dirtyValue = 42) { @@ -27,27 +28,29 @@ namespace SixLabors.ImageSharp.Tests.Memory public int BlockCapacity { get; set; } = int.MaxValue; - public IList AllocationLog => this.allocationLog; + public IReadOnlyList AllocationLog => this.allocationLog; + + public IReadOnlyList ReturnLog => this.returnLog; protected internal override int GetBlockCapacity() => this.BlockCapacity; public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { T[] array = this.AllocateArray(length, options); - return new BasicArrayBuffer(array, length); + return new BasicArrayBuffer(array, length, this); } public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None) { byte[] array = this.AllocateArray(length, options); - return new ManagedByteBuffer(array); + return new ManagedByteBuffer(array, this); } private T[] AllocateArray(int length, AllocationOptions options) where T : struct { - this.allocationLog.Add(AllocationRequest.Create(options, length)); var array = new T[length + 42]; + this.allocationLog.Add(AllocationRequest.Create(options, length, array)); if (options == AllocationOptions.None) { @@ -58,25 +61,32 @@ namespace SixLabors.ImageSharp.Tests.Memory return array; } + private void Return(BasicArrayBuffer buffer) + where T : struct + { + this.returnLog.Add(new ReturnRequest(buffer.Array.GetHashCode())); + } + public struct AllocationRequest { - private AllocationRequest(Type elementType, AllocationOptions allocationOptions, int length, int lengthInBytes) + private AllocationRequest(Type elementType, AllocationOptions allocationOptions, int length, int lengthInBytes, int hashCodeOfBuffer) { this.ElementType = elementType; this.AllocationOptions = allocationOptions; this.Length = length; this.LengthInBytes = lengthInBytes; + this.HashCodeOfBuffer = hashCodeOfBuffer; if (elementType == typeof(Vector4)) { } } - public static AllocationRequest Create(AllocationOptions allocationOptions, int length) + public static AllocationRequest Create(AllocationOptions allocationOptions, int length, T[] buffer) { Type type = typeof(T); int elementSize = Marshal.SizeOf(type); - return new AllocationRequest(type, allocationOptions, length, length * elementSize); + return new AllocationRequest(type, allocationOptions, length, length * elementSize, buffer.GetHashCode()); } public Type ElementType { get; } @@ -86,6 +96,18 @@ namespace SixLabors.ImageSharp.Tests.Memory public int Length { get; } public int LengthInBytes { get; } + + public int HashCodeOfBuffer { get; } + } + + public struct ReturnRequest + { + public ReturnRequest(int hashCodeOfBuffer) + { + this.HashCodeOfBuffer = hashCodeOfBuffer; + } + + public int HashCodeOfBuffer { get; } } /// @@ -94,36 +116,29 @@ namespace SixLabors.ImageSharp.Tests.Memory private class BasicArrayBuffer : MemoryManager where T : struct { + private readonly TestMemoryAllocator allocator; private GCHandle pinHandle; - /// - /// Initializes a new instance of the class - /// - /// The array - /// The length of the buffer - public BasicArrayBuffer(T[] array, int length) + public BasicArrayBuffer(T[] array, int length, TestMemoryAllocator allocator) { + this.allocator = allocator; DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length)); this.Array = array; this.Length = length; } - /// - /// Initializes a new instance of the class - /// - /// The array - public BasicArrayBuffer(T[] array) - : this(array, array.Length) + public BasicArrayBuffer(T[] array, TestMemoryAllocator allocator) + : this(array, array.Length, allocator) { } /// - /// Gets the array + /// Gets the array. /// public T[] Array { get; } /// - /// Gets the length + /// Gets the length. /// public int Length { get; } @@ -149,13 +164,17 @@ namespace SixLabors.ImageSharp.Tests.Memory /// protected override void Dispose(bool disposing) { + if (disposing) + { + this.allocator.Return(this); + } } } private class ManagedByteBuffer : BasicArrayBuffer, IManagedByteBuffer { - public ManagedByteBuffer(byte[] array) - : base(array) + public ManagedByteBuffer(byte[] array, TestMemoryAllocator allocator) + : base(array, allocator) { } }