Browse Source

use WeakReference with timer, configure trim period for sandbox

af/UniformUnmanagedMemoryPoolMemoryAllocator-02-MemoryGuards
Anton Firszov 5 years ago
parent
commit
ca17d33ea3
  1. 15
      src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs
  2. 22
      src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
  3. 10
      tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

15
src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs

@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Memory.Internals
// Invoke the timer callback more frequently, than trimSettings.TrimPeriodMilliseconds, // Invoke the timer callback more frequently, than trimSettings.TrimPeriodMilliseconds,
// and also invoke it on Gen 2 GC. // and also invoke it on Gen 2 GC.
// We are checking in the callback if enough time passed since the last trimming. If not, we do nothing. // We are checking in the callback if enough time passed since the last trimming. If not, we do nothing.
var weakPoolRef = new WeakReference<UniformUnmanagedMemoryPool>(this);
this.trimTimer = new Timer( this.trimTimer = new Timer(
s => ((UniformUnmanagedMemoryPool)s)?.Trim(), s => TimerCallback((WeakReference<UniformUnmanagedMemoryPool>)s),
this, weakPoolRef,
this.trimSettings.TrimPeriodMilliseconds / 4, this.trimSettings.TrimPeriodMilliseconds / 4,
this.trimSettings.TrimPeriodMilliseconds / 4); this.trimSettings.TrimPeriodMilliseconds / 4);
@ -217,6 +218,14 @@ namespace SixLabors.ImageSharp.Memory.Internals
private static void ThrowReturnedMoreArraysThanRented() => private static void ThrowReturnedMoreArraysThanRented() =>
throw new InvalidMemoryOperationException("Returned more arrays then rented"); throw new InvalidMemoryOperationException("Returned more arrays then rented");
private static void TimerCallback(WeakReference<UniformUnmanagedMemoryPool> weakPoolRef)
{
if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool pool))
{
pool.Trim();
}
}
private bool Trim() private bool Trim()
{ {
UnmanagedMemoryHandle[] buffersLocal = this.buffers; UnmanagedMemoryHandle[] buffersLocal = this.buffers;
@ -307,7 +316,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
public class TrimSettings public class TrimSettings
{ {
// Trim half of the retained pool buffers every minute. // Trim half of the retained pool buffers every minute.
public int TrimPeriodMilliseconds { get; set; } = 60_000; public int TrimPeriodMilliseconds { get; set; } = 20_000;
public float Rate { get; set; } = 0.5f; public float Rate { get; set; } = 0.5f;

22
src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs

@ -18,6 +18,7 @@ namespace SixLabors.ImageSharp.Memory
private readonly int sharedArrayPoolThresholdInBytes; private readonly int sharedArrayPoolThresholdInBytes;
private readonly int poolBufferSizeInBytes; private readonly int poolBufferSizeInBytes;
private readonly int poolCapacity; private readonly int poolCapacity;
private readonly UniformUnmanagedMemoryPool.TrimSettings trimSettings;
private UniformUnmanagedMemoryPool pool; private UniformUnmanagedMemoryPool pool;
private readonly UnmanagedMemoryAllocator nonPoolAllocator; private readonly UnmanagedMemoryAllocator nonPoolAllocator;
@ -42,17 +43,32 @@ namespace SixLabors.ImageSharp.Memory
{ {
} }
// Internal constructor allowing to change the shared array pool threshold for testing purposes.
internal UniformUnmanagedMemoryPoolMemoryAllocator( internal UniformUnmanagedMemoryPoolMemoryAllocator(
int sharedArrayPoolThresholdInBytes, int sharedArrayPoolThresholdInBytes,
int poolBufferSizeInBytes, int poolBufferSizeInBytes,
long maxPoolSizeInBytes, long maxPoolSizeInBytes,
int unmanagedBufferSizeInBytes) int unmanagedBufferSizeInBytes)
: this(
sharedArrayPoolThresholdInBytes,
poolBufferSizeInBytes,
maxPoolSizeInBytes,
unmanagedBufferSizeInBytes,
UniformUnmanagedMemoryPool.TrimSettings.Default)
{
}
internal UniformUnmanagedMemoryPoolMemoryAllocator(
int sharedArrayPoolThresholdInBytes,
int poolBufferSizeInBytes,
long maxPoolSizeInBytes,
int unmanagedBufferSizeInBytes,
UniformUnmanagedMemoryPool.TrimSettings trimSettings)
{ {
this.sharedArrayPoolThresholdInBytes = sharedArrayPoolThresholdInBytes; this.sharedArrayPoolThresholdInBytes = sharedArrayPoolThresholdInBytes;
this.poolBufferSizeInBytes = poolBufferSizeInBytes; this.poolBufferSizeInBytes = poolBufferSizeInBytes;
this.poolCapacity = (int)(maxPoolSizeInBytes / poolBufferSizeInBytes); this.poolCapacity = (int)(maxPoolSizeInBytes / poolBufferSizeInBytes);
this.pool = new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity); this.trimSettings = trimSettings;
this.pool = new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity, this.trimSettings);
this.nonPoolAllocator = new UnmanagedMemoryAllocator(unmanagedBufferSizeInBytes); this.nonPoolAllocator = new UnmanagedMemoryAllocator(unmanagedBufferSizeInBytes);
} }
@ -125,7 +141,7 @@ namespace SixLabors.ImageSharp.Memory
{ {
UniformUnmanagedMemoryPool oldPool = Interlocked.Exchange( UniformUnmanagedMemoryPool oldPool = Interlocked.Exchange(
ref this.pool, ref this.pool,
new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity)); new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity, this.trimSettings));
oldPool.Release(); oldPool.Release();
} }

10
tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

@ -11,6 +11,7 @@ using System.Threading;
using CommandLine; using CommandLine;
using SixLabors.ImageSharp.Benchmarks.LoadResizeSave; using SixLabors.ImageSharp.Benchmarks.LoadResizeSave;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Tests.ProfilingSandbox namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
{ {
@ -231,6 +232,9 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
[Option('f', "file", Required = false, Default = null)] [Option('f', "file", Required = false, Default = null)]
public string FileOutput { get; set; } public string FileOutput { get; set; }
[Option('t', "trim-time", Required = false, Default = 60)]
public int TrimTimeSeconds { get; set; }
public static CommandLineOptions Parse(string[] args) public static CommandLineOptions Parse(string[] args)
{ {
CommandLineOptions result = null; CommandLineOptions result = null;
@ -257,7 +261,11 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
1024 * 1024, 1024 * 1024,
(int)B(this.MaxContiguousPoolBufferMegaBytes), (int)B(this.MaxContiguousPoolBufferMegaBytes),
B(this.MaxPoolSizeMegaBytes), B(this.MaxPoolSizeMegaBytes),
(int)B(this.MaxCapacityOfUnmanagedBuffersMegaBytes)); (int)B(this.MaxCapacityOfUnmanagedBuffersMegaBytes),
new UniformUnmanagedMemoryPool.TrimSettings
{
TrimPeriodMilliseconds = this.TrimTimeSeconds * 100
});
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }

Loading…
Cancel
Save