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

Commit 90ece57

Browse files
committed
Merge branch 'khellang/configurable-thread-count' into dev
2 parents de5dd4c + 4c68807 commit 90ece57

File tree

3 files changed

+154
-29
lines changed

3 files changed

+154
-29
lines changed

src/Microsoft.AspNet.Server.Kestrel/KestrelServerInformation.cs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Globalization;
67
using Microsoft.AspNet.Server.Features;
78
using Microsoft.AspNet.Server.Kestrel.Filter;
89
using Microsoft.Extensions.Configuration;
@@ -11,11 +12,11 @@ namespace Microsoft.AspNet.Server.Kestrel
1112
{
1213
public class KestrelServerInformation : IKestrelServerInformation, IServerAddressesFeature
1314
{
14-
public KestrelServerInformation(IConfiguration configuration, int threadCount)
15+
public KestrelServerInformation(IConfiguration configuration)
1516
{
1617
Addresses = GetAddresses(configuration);
17-
ThreadCount = threadCount;
18-
NoDelay = true;
18+
ThreadCount = GetThreadCount(configuration);
19+
NoDelay = GetNoDelay(configuration);
1920
}
2021

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

2728
public IConnectionFilter ConnectionFilter { get; set; }
2829

30+
private static int ProcessorThreadCount
31+
{
32+
get
33+
{
34+
// Actual core count would be a better number
35+
// rather than logical cores which includes hyper-threaded cores.
36+
// Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving).
37+
var threadCount = Environment.ProcessorCount >> 1;
38+
39+
if (threadCount < 1)
40+
{
41+
// Ensure shifted value is at least one
42+
return 1;
43+
}
44+
45+
if (threadCount > 16)
46+
{
47+
// Receive Side Scaling RSS Processor count currently maxes out at 16
48+
// would be better to check the NIC's current hardware queues; but xplat...
49+
return 16;
50+
}
51+
52+
return threadCount;
53+
}
54+
}
55+
2956
private static ICollection<string> GetAddresses(IConfiguration configuration)
3057
{
3158
var addresses = new List<string>();
@@ -39,5 +66,41 @@ private static ICollection<string> GetAddresses(IConfiguration configuration)
3966

4067
return addresses;
4168
}
69+
70+
private static int GetThreadCount(IConfiguration configuration)
71+
{
72+
var threadCountString = configuration["kestrel.threadCount"];
73+
74+
if (string.IsNullOrEmpty(threadCountString))
75+
{
76+
return ProcessorThreadCount;
77+
}
78+
79+
int threadCount;
80+
if (int.TryParse(threadCountString, NumberStyles.Integer, CultureInfo.InvariantCulture, out threadCount))
81+
{
82+
return threadCount;
83+
}
84+
85+
return ProcessorThreadCount;
86+
}
87+
88+
private static bool GetNoDelay(IConfiguration configuration)
89+
{
90+
var noDelayString = configuration["kestrel.noDelay"];
91+
92+
if (string.IsNullOrEmpty(noDelayString))
93+
{
94+
return true;
95+
}
96+
97+
bool noDelay;
98+
if (bool.TryParse(noDelayString, out noDelay))
99+
{
100+
return noDelay;
101+
}
102+
103+
return true;
104+
}
42105
}
43106
}

src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,36 +27,11 @@ public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFact
2727

2828
public IServer CreateServer(IConfiguration configuration)
2929
{
30-
var threadCount = GetThreadCount();
31-
var information = new KestrelServerInformation(configuration, threadCount);
30+
var information = new KestrelServerInformation(configuration);
3231
var serverFeatures = new FeatureCollection();
3332
serverFeatures.Set<IKestrelServerInformation>(information);
3433
serverFeatures.Set<IServerAddressesFeature>(information);
3534
return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel"));
3635
}
37-
38-
private static int GetThreadCount()
39-
{
40-
// Actual core count would be a better number
41-
// rather than logical cores which includes hyper-threaded cores.
42-
// Divide by 2 for hyper-threading, and good defaults (still need threads to do webserving).
43-
// Can be user overriden using IKestrelServerInformation.ThreadCount
44-
var threadCount = Environment.ProcessorCount >> 1;
45-
46-
if (threadCount < 1)
47-
{
48-
// Ensure shifted value is at least one
49-
return 1;
50-
}
51-
52-
if (threadCount > 16)
53-
{
54-
// Receive Side Scaling RSS Processor count currently maxes out at 16
55-
// would be better to check the NIC's current hardware queues; but xplat...
56-
return 16;
57-
}
58-
59-
return threadCount;
60-
}
6136
}
6237
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.AspNet.Server.Kestrel;
7+
using Microsoft.Extensions.Configuration;
8+
using Xunit;
9+
10+
namespace Microsoft.AspNet.Server.KestrelTests
11+
{
12+
public class KestrelServerInformationTests
13+
{
14+
[Fact]
15+
public void SetThreadCountUsingConfiguration()
16+
{
17+
const int expected = 42;
18+
19+
var values = new Dictionary<string, string>
20+
{
21+
{ "kestrel.threadCount", expected.ToString() }
22+
};
23+
24+
var configuration = new ConfigurationBuilder()
25+
.AddInMemoryCollection(values)
26+
.Build();
27+
28+
var information = new KestrelServerInformation(configuration);
29+
30+
Assert.Equal(expected, information.ThreadCount);
31+
}
32+
33+
[Fact]
34+
public void SetThreadCountUsingProcessorCount()
35+
{
36+
// Ideally we'd mock Environment.ProcessorCount to test edge cases.
37+
var expected = Clamp(Environment.ProcessorCount >> 1, 1, 16);
38+
39+
var configuration = new ConfigurationBuilder().Build();
40+
41+
var information = new KestrelServerInformation(configuration);
42+
43+
Assert.Equal(expected, information.ThreadCount);
44+
}
45+
46+
[Fact]
47+
public void SetAddressesUsingConfiguration()
48+
{
49+
var expected = new List<string> { "http://localhost:1337", "https://localhost:42" };
50+
51+
var values = new Dictionary<string, string>
52+
{
53+
{ "server.urls", string.Join(";", expected) }
54+
};
55+
56+
var configuration = new ConfigurationBuilder()
57+
.AddInMemoryCollection(values)
58+
.Build();
59+
60+
var information = new KestrelServerInformation(configuration);
61+
62+
Assert.Equal(expected, information.Addresses);
63+
}
64+
65+
[Fact]
66+
public void SetNoDelayUsingConfiguration()
67+
{
68+
var values = new Dictionary<string, string>
69+
{
70+
{ "kestrel.noDelay", "false" }
71+
};
72+
73+
var configuration = new ConfigurationBuilder()
74+
.AddInMemoryCollection(values)
75+
.Build();
76+
77+
var information = new KestrelServerInformation(configuration);
78+
79+
Assert.False(information.NoDelay);
80+
}
81+
82+
private static int Clamp(int value, int min, int max)
83+
{
84+
return value < min ? min : value > max ? max : value;
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)