Skip to content

Commit

Permalink
Bump SharedArrayPool's max arrays per partition default from 8 to 32 (#…
Browse files Browse the repository at this point in the history
…87905)

The 8 value was picked arbitrarily years ago, with a smaller value being picked because nothing was ever trimmed from the pool.  Since then, we've seen a significant increase in use of the pool, putting pressure on its storage, and we also added trimming so that memory pressure causes arrays to be pitched.  Longer term, we might want to remove this limit entirely and have more of a dynamic scheme for allowing the buckets to grow and shrink.  For now, though, I'm bumping the limit up from 8 arrays per core to 32 arrays per core to provide some more wiggle room. 32 is also somewhat arbitrary, though recent examples on a few real services that were hitting the 8 limit (resulting in increased allocation and contention) were mollified by 32.
  • Loading branch information
stephentoub committed Jun 29, 2023
1 parent 7ab70f9 commit d4fcdc1
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 16 deletions.
22 changes: 8 additions & 14 deletions src/libraries/System.Buffers/tests/ArrayPool/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace System.Buffers.ArrayPool.Tests
public partial class ArrayPoolUnitTests : ArrayPoolTest
{
private const int MaxEventWaitTimeoutInMs = 200;
private const string MaxArraysPerPartitionDefault = "32";

private struct TestStruct
{
Expand Down Expand Up @@ -602,14 +603,14 @@ private static void ConfigurablePool_AllocatedArraysAreCleared<T>()
public static IEnumerable<object[]> BytePoolInstances()
{
yield return new object[] { ArrayPool<byte>.Create() };
yield return new object[] { ArrayPool<byte>.Create(1024*1024, 50) };
yield return new object[] { ArrayPool<byte>.Create(1024*1024, 1) };
yield return new object[] { ArrayPool<byte>.Create(1024 * 1024, 50) };
yield return new object[] { ArrayPool<byte>.Create(1024 * 1024, 1) };
yield return new object[] { ArrayPool<byte>.Shared };
}

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[InlineData("", "", "2147483647", "8")]
[InlineData("0", "0", "2147483647", "8")]
[InlineData("", "", "2147483647", MaxArraysPerPartitionDefault)]
[InlineData("0", "0", "2147483647", MaxArraysPerPartitionDefault)]
[InlineData("1", "2", "1", "2")]
[InlineData("2", "1", "2", "1")]
[InlineData("4", "123", "4", "123")]
Expand All @@ -623,7 +624,7 @@ public static IEnumerable<object[]> BytePoolInstances()
" " +
" " +
" " +
"2" +
"2" +
" " +
" " +
" " +
Expand All @@ -638,7 +639,7 @@ public static IEnumerable<object[]> BytePoolInstances()
" " +
" " +
" ",
"2147483647", "8")]
"2147483647", MaxArraysPerPartitionDefault)]
public void SharedPool_SetEnvironmentVariables_ValuesRespected(
string partitionCount, string maxArraysPerPartition, string expectedPartitionCount, string expectedMaxArraysPerPartition)
{
Expand Down Expand Up @@ -669,14 +670,7 @@ public void SharedPool_SetEnvironmentVariables_ValuesRespected(
FieldInfo maxArraysPerPartitionField = staticsType.GetField("s_maxArraysPerPartition", BindingFlags.NonPublic | BindingFlags.Static);
Assert.NotNull(maxArraysPerPartitionField);
int maxArraysPerPartitionValue = (int)maxArraysPerPartitionField.GetValue(null);
if (int.Parse(expectedMaxArraysPerPartition) > 0)
{
Assert.Equal(int.Parse(expectedMaxArraysPerPartition), maxArraysPerPartitionValue);
}
else
{
Assert.Equal(8, maxArraysPerPartitionValue);
}
Assert.Equal(int.Parse(int.Parse(expectedMaxArraysPerPartition) > 0 ? expectedMaxArraysPerPartition : MaxArraysPerPartitionDefault), maxArraysPerPartitionValue);
// Make sure the pool is still usable
for (int i = 0; i < 2; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,12 +536,12 @@ private static int GetPartitionCount()
}

/// <summary>Gets the maximum number of arrays of a given size allowed to be cached per partition.</summary>
/// <returns>Defaults to 8. This does not factor in or impact the number of arrays cached per thread in TLS (currently only 1).</returns>
/// <returns>Defaults to 32. This does not factor in or impact the number of arrays cached per thread in TLS (currently only 1).</returns>
private static int GetMaxArraysPerPartition()
{
return TryGetInt32EnvironmentVariable("DOTNET_SYSTEM_BUFFERS_SHAREDARRAYPOOL_MAXARRAYSPERPARTITION", out int result) && result > 0 ?
result :
8; // arbitrary limit
32; // arbitrary limit
}

/// <summary>Look up an environment variable and try to parse it as an Int32.</summary>
Expand Down

0 comments on commit d4fcdc1

Please sign in to comment.