feat: Adds a single threaded array pool (#967)
## Added Feature Adds a single threaded array pool that works exactly the same as `ArrayPool<T>.Shared`. The `STArrayPool<T>.Shared` can only be used on a single thread, the main game thread of the server. Note: Unlike the built-in array pool, there is no hook into the _GC Gen 2_. This means to relieve potentially high memory pressure, `ArrayPool<T>.Shared.Trim()` must be called. The pool will only release arrays _after two successive calls within 10 seconds or longer_. If the server is at less than 70% total memory usage, or the server is not going to use this pool for something egregious, then don't bother ever calling Trim(). ## Changes - [X] Fixes ArrayPool calls that should be cleared due to references. - [X] Benchmarks against ArrayPool with 4+ rented arrays deep of the same length. - [x] Unit tests
This commit is contained in:
parent
0925a2d435
commit
76fddcbccd
9 changed files with 604 additions and 12 deletions
|
|
@ -0,0 +1,95 @@
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Buffers;
|
||||
using Server.Collections;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkPooledRefQueue
|
||||
{
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
// Allocate
|
||||
var arrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
var stArrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
stArrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(stArrays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UseQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var queue = new Queue<long>();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UsePooledRefQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
using var queue = PooledRefQueue<long>.Create();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void UsePooledRefQueueMT()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
using var queue = PooledRefQueue<long>.CreateMT();
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
queue.Enqueue(j);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 32; j++)
|
||||
{
|
||||
var num = queue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[SimpleJob(RuntimeMoniker.Net60)]
|
||||
public class BenchmarkSTArray
|
||||
{
|
||||
private static long[][] arrays = new long[16][];
|
||||
private static long[][] stArrays = new long[16][];
|
||||
private static long[][] newArrays = new long[16][];
|
||||
private static Queue<long>[] newQueue = new Queue<long>[16];
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
// Allocate
|
||||
arrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
stArrays = new long[16][];
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
stArrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(stArrays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ArrayPool()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
arrays[i] = ArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
ArrayPool<long>.Shared.Return(arrays[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void STArrayPool()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
arrays[i] = STArrayPool<long>.Shared.Rent(64);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
STArrayPool<long>.Shared.Return(arrays[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void NewArray()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
newArrays[i] = new long[64];
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void NewQueue()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
newQueue[i] = new Queue<long>();
|
||||
newQueue[i].EnsureCapacity(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue