Skip to content

Commit 3972e14

Browse files
AlexAlex
authored andcommitted
Added NoGCRegion feature
1 parent f1710cf commit 3972e14

File tree

4 files changed

+128
-5
lines changed

4 files changed

+128
-5
lines changed

Libraries/SPTarkov.Server.Assets/SPT_Data/configs/core.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
"profileSaveIntervalSeconds": 15,
66
"sptFriendNickname": "SPT",
77
"allowProfileWipe": true,
8+
"enableNoGCRegions": true,
9+
"noGCRegionMaxMemoryGB": 4,
10+
"noGCRegionMaxLOHMemoryGB": 3,
811
"bsgLogging": {
912
"verbosity": 6,
1013
"sendToServer": false

Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,44 @@ public record CoreConfig : BaseConfig
4242
[JsonPropertyName("features")]
4343
public required ServerFeatures Features { get; set; }
4444

45+
[JsonPropertyName("enableNoGCRegions")]
46+
// ReSharper disable once InconsistentNaming
47+
public required bool EnableNoGCRegions { get; set; }
48+
49+
// ReSharper disable once InconsistentNaming
50+
private int _noGCRegionMaxMemoryGB = 4;
51+
[JsonPropertyName("noGCRegionMaxMemoryGB")]
52+
// ReSharper disable once InconsistentNaming
53+
public required int NoGCRegionMaxMemoryGB
54+
{
55+
get => _noGCRegionMaxMemoryGB;
56+
set
57+
{
58+
if (value <= 0)
59+
{
60+
throw new Exception($"Invalid value {nameof(NoGCRegionMaxMemoryGB)}: {value}. Must be greater than zero.");
61+
}
62+
_noGCRegionMaxMemoryGB = value;
63+
}
64+
}
65+
66+
// ReSharper disable once InconsistentNaming
67+
private int _noGCRegionMaxLOHMemoryGB = 3;
68+
[JsonPropertyName("noGCRegionMaxLOHMemoryGB")]
69+
// ReSharper disable once InconsistentNaming
70+
public required int NoGCRegionMaxLOHMemoryGB
71+
{
72+
get => _noGCRegionMaxLOHMemoryGB;
73+
set
74+
{
75+
if (value <= 0)
76+
{
77+
throw new Exception($"Invalid value {nameof(NoGCRegionMaxLOHMemoryGB)}: {value}. Must be greater than zero.");
78+
}
79+
_noGCRegionMaxLOHMemoryGB = value;
80+
}
81+
}
82+
4583
/// <summary>
4684
/// Commit hash build server was created from
4785
/// </summary>

SPTarkov.Server/Program.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net;
22
using System.Net.Sockets;
3+
using System.Runtime;
34
using System.Runtime.InteropServices;
45
using System.Security.Authentication;
56
using System.Text;
@@ -118,6 +119,8 @@ public static async Task StartServer(string[] args)
118119
forwardedHeadersOptions.KnownProxies.Clear();
119120
app.UseForwardedHeaders(forwardedHeadersOptions);
120121

122+
app.UseRequestTracking();
123+
121124
SetConsoleOutputMode();
122125

123126
await app.Services.GetRequiredService<SptServerStartupService>().Startup();
@@ -147,14 +150,52 @@ private static void ConfigureWebApp(WebApplication app)
147150

148151
app.UseMiddleware<SptLoggerMiddleware>();
149152

150-
app.Use(
151-
async (HttpContext context, RequestDelegate next) =>
153+
app.Use(async (context, next) => await HandleRequest(context, next));
154+
155+
app.UseSptBlazor();
156+
}
157+
158+
private static async Task HandleRequest(HttpContext context, RequestDelegate next)
159+
{
160+
var config = context.RequestServices.GetRequiredService<ConfigServer>().GetConfig<CoreConfig>();
161+
162+
// if no other requests are running, start the no GC region, otherwise dont start it
163+
if (!RequestTrackingMiddleware.OtherRequestsActive)
164+
{
165+
if (config.EnableNoGCRegions && GCSettings.LatencyMode != GCLatencyMode.NoGCRegion)
152166
{
153-
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
167+
try
168+
{
169+
GC.TryStartNoGCRegion(
170+
1024L * 1024L * 1024L * config.NoGCRegionMaxMemoryGB,
171+
1024L * 1024L * 1024L * config.NoGCRegionMaxLOHMemoryGB,
172+
true
173+
);
174+
}
175+
catch (Exception)
176+
{
177+
// ignored, we keep going
178+
}
154179
}
155-
);
180+
}
156181

157-
app.UseSptBlazor();
182+
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
183+
184+
// if no other requests are running, end the no GC region, otherwise dont stop it as other requests need it still
185+
if (!RequestTrackingMiddleware.OtherRequestsActive)
186+
{
187+
if (config.EnableNoGCRegions && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
188+
{
189+
try
190+
{
191+
GC.EndNoGCRegion();
192+
}
193+
catch (Exception)
194+
{
195+
// ignored, we dont care about handling this
196+
}
197+
}
198+
}
158199
}
159200

160201
private static void ConfigureKestrel(WebApplicationBuilder builder)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace SPTarkov.Server.Services;
2+
3+
public class RequestTrackingMiddleware
4+
{
5+
private static int _activeRequests;
6+
private readonly RequestDelegate _next;
7+
8+
public static bool OtherRequestsActive
9+
{
10+
get
11+
{
12+
return _activeRequests > 1;
13+
}
14+
}
15+
16+
public RequestTrackingMiddleware(RequestDelegate next)
17+
{
18+
_next = next;
19+
}
20+
21+
public async Task InvokeAsync(HttpContext context)
22+
{
23+
Interlocked.Increment(ref _activeRequests);
24+
try
25+
{
26+
await _next(context);
27+
}
28+
finally
29+
{
30+
Interlocked.Decrement(ref _activeRequests);
31+
}
32+
}
33+
}
34+
35+
public static class RequestTrackingMiddlewareExtensions
36+
{
37+
public static IApplicationBuilder UseRequestTracking(this IApplicationBuilder builder)
38+
{
39+
return builder.UseMiddleware<RequestTrackingMiddleware>();
40+
}
41+
}

0 commit comments

Comments
 (0)