Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.

Commit

Permalink
Merge branch 'khellang/configurable-thread-count' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
halter73 committed Dec 8, 2015
2 parents de5dd4c + 4c68807 commit 90ece57
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 29 deletions.
69 changes: 66 additions & 3 deletions src/Microsoft.AspNet.Server.Kestrel/KestrelServerInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.AspNet.Server.Features;
using Microsoft.AspNet.Server.Kestrel.Filter;
using Microsoft.Extensions.Configuration;
Expand All @@ -11,11 +12,11 @@ namespace Microsoft.AspNet.Server.Kestrel
{
public class KestrelServerInformation : IKestrelServerInformation, IServerAddressesFeature
{
public KestrelServerInformation(IConfiguration configuration, int threadCount)
public KestrelServerInformation(IConfiguration configuration)
{
Addresses = GetAddresses(configuration);
ThreadCount = threadCount;
NoDelay = true;
ThreadCount = GetThreadCount(configuration);
NoDelay = GetNoDelay(configuration);
}

public ICollection<string> Addresses { get; }
Expand All @@ -26,6 +27,32 @@ public KestrelServerInformation(IConfiguration configuration, int threadCount)

public IConnectionFilter ConnectionFilter { get; set; }

private static int ProcessorThreadCount
{
get
{
// Actual core count would be a better number
// rather than logical cores which includes hyper-threaded cores.
// Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving).
var threadCount = Environment.ProcessorCount >> 1;

if (threadCount < 1)
{
// Ensure shifted value is at least one
return 1;
}

if (threadCount > 16)
{
// Receive Side Scaling RSS Processor count currently maxes out at 16
// would be better to check the NIC's current hardware queues; but xplat...
return 16;
}

return threadCount;
}
}

private static ICollection<string> GetAddresses(IConfiguration configuration)
{
var addresses = new List<string>();
Expand All @@ -39,5 +66,41 @@ private static ICollection<string> GetAddresses(IConfiguration configuration)

return addresses;
}

private static int GetThreadCount(IConfiguration configuration)
{
var threadCountString = configuration["kestrel.threadCount"];

if (string.IsNullOrEmpty(threadCountString))
{
return ProcessorThreadCount;
}

int threadCount;
if (int.TryParse(threadCountString, NumberStyles.Integer, CultureInfo.InvariantCulture, out threadCount))
{
return threadCount;
}

return ProcessorThreadCount;
}

private static bool GetNoDelay(IConfiguration configuration)
{
var noDelayString = configuration["kestrel.noDelay"];

if (string.IsNullOrEmpty(noDelayString))
{
return true;
}

bool noDelay;
if (bool.TryParse(noDelayString, out noDelay))
{
return noDelay;
}

return true;
}
}
}
27 changes: 1 addition & 26 deletions src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,11 @@ public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFact

public IServer CreateServer(IConfiguration configuration)
{
var threadCount = GetThreadCount();
var information = new KestrelServerInformation(configuration, threadCount);
var information = new KestrelServerInformation(configuration);
var serverFeatures = new FeatureCollection();
serverFeatures.Set<IKestrelServerInformation>(information);
serverFeatures.Set<IServerAddressesFeature>(information);
return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel"));
}

private static int GetThreadCount()
{
// Actual core count would be a better number
// rather than logical cores which includes hyper-threaded cores.
// Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving).
// Can be user overriden using IKestrelServerInformation.ThreadCount
var threadCount = Environment.ProcessorCount >> 1;

if (threadCount < 1)
{
// Ensure shifted value is at least one
return 1;
}

if (threadCount > 16)
{
// Receive Side Scaling RSS Processor count currently maxes out at 16
// would be better to check the NIC's current hardware queues; but xplat...
return 16;
}

return threadCount;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using Microsoft.AspNet.Server.Kestrel;
using Microsoft.Extensions.Configuration;
using Xunit;

namespace Microsoft.AspNet.Server.KestrelTests
{
public class KestrelServerInformationTests
{
[Fact]
public void SetThreadCountUsingConfiguration()
{
const int expected = 42;

var values = new Dictionary<string, string>
{
{ "kestrel.threadCount", expected.ToString() }
};

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

var information = new KestrelServerInformation(configuration);

Assert.Equal(expected, information.ThreadCount);
}

[Fact]
public void SetThreadCountUsingProcessorCount()
{
// Ideally we'd mock Environment.ProcessorCount to test edge cases.
var expected = Clamp(Environment.ProcessorCount >> 1, 1, 16);

var configuration = new ConfigurationBuilder().Build();

var information = new KestrelServerInformation(configuration);

Assert.Equal(expected, information.ThreadCount);
}

[Fact]
public void SetAddressesUsingConfiguration()
{
var expected = new List<string> { "http://localhost:1337", "https://localhost:42" };

var values = new Dictionary<string, string>
{
{ "server.urls", string.Join(";", expected) }
};

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

var information = new KestrelServerInformation(configuration);

Assert.Equal(expected, information.Addresses);
}

[Fact]
public void SetNoDelayUsingConfiguration()
{
var values = new Dictionary<string, string>
{
{ "kestrel.noDelay", "false" }
};

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

var information = new KestrelServerInformation(configuration);

Assert.False(information.NoDelay);
}

private static int Clamp(int value, int min, int max)
{
return value < min ? min : value > max ? max : value;
}
}
}

0 comments on commit 90ece57

Please sign in to comment.