From 31afef5a8526d38b77f46b420a8d2e1e764f37ac Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Wed, 26 Jun 2024 11:24:22 -0700 Subject: [PATCH 1/2] Increase the default number of IO queues on larger machines The number of IO queues is currently limited to 16. On machines with more processors, increasing the number of IO queues appears to improve throughput on some benchmarks. --- .../Transport.Sockets/src/Internal/IOQueue.cs | 17 +++++++++++++++++ .../src/SocketConnectionFactoryOptions.cs | 4 ++-- .../src/SocketTransportOptions.cs | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs index b378718f1826..a7625e98c547 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs @@ -10,6 +10,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal; internal sealed class IOQueue : PipeScheduler, IThreadPoolWorkItem { + public static readonly int DefaultCount = DetermineDefaultCount(); + private readonly ConcurrentQueue _workItems = new ConcurrentQueue(); private int _doingWork; @@ -73,4 +75,19 @@ public Work(Action callback, object? state) State = state; } } + + private static int DetermineDefaultCount() + { + // Since each IOQueue schedules one work item to process its work, the number of IOQueues determines the maximum + // parallelism of processing work queued to IOQueues. The default number below is based on the processor count and tries + // to use a high-enough number for that to not be a significant limiting factor for throughput. + + int processorCount = Environment.ProcessorCount; + if (OperatingSystem.IsWindows() || processorCount <= 32) + { + return Math.Min(processorCount, 16); + } + + return (processorCount + 1) / 2; + } } diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs index 35ce2bd8fd75..403f6fc108de 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs @@ -33,9 +33,9 @@ internal SocketConnectionFactoryOptions(SocketTransportOptions transportOptions) /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool. /// /// - /// Defaults to rounded down and clamped between 1 and 16. + /// Defaults to a value based on and limited to . /// - public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16); + public int IOQueueCount { get; set; } = Internal.IOQueue.DefaultCount; /// /// Wait until there is data available to allocate a buffer. Setting this to false can increase throughput at the cost of increased memory usage. diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs index a307465447ad..ad1a877df63c 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs @@ -28,9 +28,9 @@ static SocketTransportOptions() /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool. /// /// - /// Defaults to rounded down and clamped between 1 and 16. + /// Defaults to a value based on and limited to . /// - public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16); + public int IOQueueCount { get; set; } = Internal.IOQueue.DefaultCount; /// /// Wait until there is data available to allocate a buffer. Setting this to false can increase throughput at the cost of increased memory usage. From a0076563e1f2c6f7ee5cad67fa272a4521f817f9 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Fri, 28 Jun 2024 15:15:10 -0700 Subject: [PATCH 2/2] Update comment, simplify calculation --- .../Kestrel/Transport.Sockets/src/Internal/IOQueue.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs index a7625e98c547..0c958b7ce255 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs @@ -81,6 +81,9 @@ private static int DetermineDefaultCount() // Since each IOQueue schedules one work item to process its work, the number of IOQueues determines the maximum // parallelism of processing work queued to IOQueues. The default number below is based on the processor count and tries // to use a high-enough number for that to not be a significant limiting factor for throughput. + // + // On Windows, the default number is limited due to some other perf issues. Once those are fixed, the same heuristic + // could apply there as well. int processorCount = Environment.ProcessorCount; if (OperatingSystem.IsWindows() || processorCount <= 32) @@ -88,6 +91,6 @@ private static int DetermineDefaultCount() return Math.Min(processorCount, 16); } - return (processorCount + 1) / 2; + return processorCount / 2; } }