From 76633c986717d3915909dc8633d3a4a31fc2dcd6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 20 Feb 2018 21:58:26 +0100 Subject: [PATCH] allowing bucket sizes to be passed to ArrayPoolMemoryManager --- .../Memory/ArrayPoolMemoryManager.cs | 46 ++++++++++++------- .../Memory/ArrayPoolMemoryManagerTests.cs | 16 +++---- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs index 4f80b15ecb..7c2240a574 100644 --- a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs +++ b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs @@ -1,15 +1,11 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Buffers; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Memory { - using Guard = SixLabors.Guard; - /// /// Implements by allocating memory from . /// @@ -27,14 +23,18 @@ namespace SixLabors.ImageSharp.Memory private const int DefaultLargeBufferThresholdInBytes = 8 * 1024 * 1024; /// - /// The for huge buffers, which is not kept clean. + /// The for small-to-medium buffers which is not kept clean. /// - private ArrayPool largeArrayPool; + private ArrayPool normalArrayPool; /// - /// The for small-to-medium buffers which is not kept clean. + /// The for huge buffers, which is not kept clean. /// - private ArrayPool normalArrayPool; + private ArrayPool largeArrayPool; + + private readonly int maxArraysPerBucketNormalPool; + + private readonly int maxArraysPerBucketLargePool; /// /// Initializes a new instance of the class. @@ -57,14 +57,28 @@ namespace SixLabors.ImageSharp.Memory /// Initializes a new instance of the class. /// /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated. - /// The threshold to pool arrays in which has less buckets for memory safety. - public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int largeBufferThresholdInBytes) + /// Arrays over this threshold will be pooled in which has less buckets for memory safety. + public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes) + : this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, 8, 24) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated. + /// The threshold to pool arrays in which has less buckets for memory safety. + /// Max arrays per bucket for the large array pool + /// Max arrays per bucket for the normal array pool + public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool) { Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes)); - Guard.MustBeLessThanOrEqualTo(largeBufferThresholdInBytes, maxPoolSizeInBytes, nameof(largeBufferThresholdInBytes)); + Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes)); this.MaxPoolSizeInBytes = maxPoolSizeInBytes; - this.LargeBufferThresholdInBytes = largeBufferThresholdInBytes; + this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes; + this.maxArraysPerBucketLargePool = maxArraysPerBucketLargePool; + this.maxArraysPerBucketNormalPool = maxArraysPerBucketNormalPool; this.InitArrayPools(); } @@ -77,7 +91,7 @@ namespace SixLabors.ImageSharp.Memory /// /// Gets the threshold to pool arrays in which has less buckets for memory safety. /// - public int LargeBufferThresholdInBytes { get; } + public int PoolSelectorThresholdInBytes { get; } /// public override void ReleaseRetainedResources() @@ -124,13 +138,13 @@ namespace SixLabors.ImageSharp.Memory private ArrayPool GetArrayPool(int bufferSizeInBytes) { - return bufferSizeInBytes <= this.LargeBufferThresholdInBytes ? this.normalArrayPool : this.largeArrayPool; + return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool; } private void InitArrayPools() { - this.largeArrayPool = ArrayPool.Create(this.MaxPoolSizeInBytes, 8); - this.normalArrayPool = ArrayPool.Create(this.LargeBufferThresholdInBytes, 24); + this.largeArrayPool = ArrayPool.Create(this.MaxPoolSizeInBytes, this.maxArraysPerBucketLargePool); + this.normalArrayPool = ArrayPool.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs index 0bd243fda2..581e0b78d9 100644 --- a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs +++ b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs @@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Tests.Memory { private const int MaxPooledBufferSizeInBytes = 2048; - private const int LargeBufferThresholdInBytes = MaxPooledBufferSizeInBytes / 2; + private const int PoolSelectorThresholdInBytes = MaxPooledBufferSizeInBytes / 2; - private MemoryManager MemoryManager { get; } = new ArrayPoolMemoryManager(MaxPooledBufferSizeInBytes, LargeBufferThresholdInBytes); + private MemoryManager MemoryManager { get; } = new ArrayPoolMemoryManager(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes); /// /// Rent a buffer -> return it -> re-rent -> verify if it's span points to the previous location @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Memory public class BufferTests : BufferTestSuite { public BufferTests() - : base(new ArrayPoolMemoryManager(MaxPooledBufferSizeInBytes, LargeBufferThresholdInBytes)) + : base(new ArrayPoolMemoryManager(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes)) { } } @@ -53,19 +53,19 @@ namespace SixLabors.ImageSharp.Tests.Memory { var mgr = new ArrayPoolMemoryManager(1111, 666); Assert.Equal(1111, mgr.MaxPoolSizeInBytes); - Assert.Equal(666, mgr.LargeBufferThresholdInBytes); + Assert.Equal(666, mgr.PoolSelectorThresholdInBytes); } [Fact] - public void WhenPassedOnly_MaxPooledBufferSizeInBytes_SmallerThresholdIsAutoCalculated() + public void WhenPassedOnly_MaxPooledBufferSizeInBytes_SmallerThresholdValueIsAutoCalculated() { var mgr = new ArrayPoolMemoryManager(5000); Assert.Equal(5000, mgr.MaxPoolSizeInBytes); - Assert.True(mgr.LargeBufferThresholdInBytes < mgr.MaxPoolSizeInBytes); + Assert.True(mgr.PoolSelectorThresholdInBytes < mgr.MaxPoolSizeInBytes); } [Fact] - public void When_LargeBufferThresholdInBytes_IsGreaterThan_MaxPooledBufferSizeInBytes_Throws() + public void When_PoolSelectorThresholdInBytes_IsGreaterThan_MaxPooledBufferSizeInBytes_ExceptionIsThrown() { Assert.ThrowsAny(() => { new ArrayPoolMemoryManager(100, 200); }); } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [Fact] public void AllocationOverLargeArrayThreshold_UsesDifferentPool() { - int arrayLengthThreshold = LargeBufferThresholdInBytes / sizeof(int); + int arrayLengthThreshold = PoolSelectorThresholdInBytes / sizeof(int); IBuffer small = this.MemoryManager.Allocate(arrayLengthThreshold - 1); ref int ptr2Small = ref small.DangerousGetPinnableReference();