Browse Source

Use 2 ArrayPool-s with different maxArrayPerBuckets parameters,

so we never have more than 8 buckets for large buffers for	 a single value type.
pull/436/head
Anton Firszov 8 years ago
parent
commit
d86eb2473f
  1. 43
      src/ImageSharp/Memory/PixelDataPool{T}.cs
  2. 32
      tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs

43
src/ImageSharp/Memory/PixelDataPool{T}.cs

@ -17,17 +17,32 @@ namespace SixLabors.ImageSharp.Memory
/// The maximum size of pooled arrays in bytes. /// The maximum size of pooled arrays in bytes.
/// Currently set to 32MB, which is equivalent to 8 megapixels of raw <see cref="Rgba32"/> data. /// Currently set to 32MB, which is equivalent to 8 megapixels of raw <see cref="Rgba32"/> data.
/// </summary> /// </summary>
private const int MaxPooledBufferSizeInBytes = 32 * 1024 * 1024; internal const int MaxPooledBufferSizeInBytes = 32 * 1024 * 1024;
/// <summary> /// <summary>
/// The maximum array length of the <see cref="ArrayPool"/>. /// The threshold to pool arrays in <see cref="LargeArrayPool"/> which has less buckets for memory safety.
/// </summary> /// </summary>
private static readonly int MaxArrayLength = MaxPooledBufferSizeInBytes / Unsafe.SizeOf<T>(); private const int LargeBufferThresholdInBytes = 8 * 1024 * 1024;
/// <summary> /// <summary>
/// The <see cref="ArrayPool{T}"/> which is not kept clean. /// The maximum array length of the <see cref="LargeArrayPool"/>.
/// </summary> /// </summary>
private static readonly ArrayPool<T> ArrayPool = ArrayPool<T>.Create(MaxArrayLength, 50); private static readonly int MaxLargeArrayLength = MaxPooledBufferSizeInBytes / Unsafe.SizeOf<T>();
/// <summary>
/// The maximum array length of the <see cref="NormalArrayPool"/>.
/// </summary>
private static readonly int MaxNormalArrayLength = LargeBufferThresholdInBytes / Unsafe.SizeOf<T>();
/// <summary>
/// The <see cref="ArrayPool{T}"/> for huge buffers, which is not kept clean.
/// </summary>
private static readonly ArrayPool<T> LargeArrayPool = ArrayPool<T>.Create(MaxLargeArrayLength, 8);
/// <summary>
/// The <see cref="ArrayPool{T}"/> for small-to-medium buffers which is not kept clean.
/// </summary>
private static readonly ArrayPool<T> NormalArrayPool = ArrayPool<T>.Create(MaxNormalArrayLength, 24);
/// <summary> /// <summary>
/// Rents the pixel array from the pool. /// Rents the pixel array from the pool.
@ -36,7 +51,14 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The <see cref="T:TPixel[]"/></returns> /// <returns>The <see cref="T:TPixel[]"/></returns>
public static T[] Rent(int minimumLength) public static T[] Rent(int minimumLength)
{ {
return ArrayPool.Rent(minimumLength); if (minimumLength <= MaxNormalArrayLength)
{
return NormalArrayPool.Rent(minimumLength);
}
else
{
return LargeArrayPool.Rent(minimumLength);
}
} }
/// <summary> /// <summary>
@ -45,7 +67,14 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="array">The array to return to the buffer pool.</param> /// <param name="array">The array to return to the buffer pool.</param>
public static void Return(T[] array) public static void Return(T[] array)
{ {
ArrayPool.Return(array); if (array.Length <= MaxNormalArrayLength)
{
NormalArrayPool.Return(array);
}
else
{
LargeArrayPool.Return(array);
}
} }
} }
} }

32
tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs

@ -9,19 +9,25 @@ using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Memory namespace SixLabors.ImageSharp.Tests.Memory
{ {
using System;
/// <summary> /// <summary>
/// Tests the <see cref="PixelDataPool{T}"/> class. /// Tests the <see cref="PixelDataPool{T}"/> class.
/// </summary> /// </summary>
public class PixelDataPoolTests public class PixelDataPoolTests
{ {
private const int MaxPooledBufferSizeInBytes = PixelDataPool<byte>.MaxPooledBufferSizeInBytes;
readonly object monitor = new object(); readonly object monitor = new object();
[Fact] [Theory]
public void PixelDataPoolRentsMinimumSize() [InlineData(1)]
[InlineData(1024)]
public void PixelDataPoolRentsMinimumSize(int size)
{ {
Rgba32[] pixels = PixelDataPool<Rgba32>.Rent(1024); Rgba32[] pixels = PixelDataPool<Rgba32>.Rent(size);
Assert.True(pixels.Length >= 1024); Assert.True(pixels.Length >= size);
} }
[Fact] [Fact]
@ -65,17 +71,21 @@ namespace SixLabors.ImageSharp.Tests.Memory
} }
} }
[Fact] [Theory]
public void SmallBuffersArePooled() [InlineData(32)]
[InlineData(512)]
[InlineData(MaxPooledBufferSizeInBytes-1)]
public void SmallBuffersArePooled(int size)
{ {
Assert.True(this.CheckIsPooled<byte>(5, 512)); Assert.True(this.CheckIsPooled<byte>(5, size));
} }
[Fact] [Theory]
public void LargeBuffersAreNotPooled_OfByte() [InlineData(128 * 1024 * 1024)]
[InlineData(MaxPooledBufferSizeInBytes+1)]
public void LargeBuffersAreNotPooled_OfByte(int size)
{ {
const int mb128 = 128 * 1024 * 1024; Assert.False(this.CheckIsPooled<byte>(2, size));
Assert.False(this.CheckIsPooled<byte>(2, mb128));
} }
[StructLayout(LayoutKind.Explicit, Size = 512)] [StructLayout(LayoutKind.Explicit, Size = 512)]

Loading…
Cancel
Save