Added NoGCRegion feature

This commit is contained in:
Alex
2025-10-20 11:05:58 +01:00
parent f1710cfb5c
commit 3972e14840
4 changed files with 129 additions and 6 deletions
@@ -5,6 +5,9 @@
"profileSaveIntervalSeconds": 15,
"sptFriendNickname": "SPT",
"allowProfileWipe": true,
"enableNoGCRegions": true,
"noGCRegionMaxMemoryGB": 4,
"noGCRegionMaxLOHMemoryGB": 3,
"bsgLogging": {
"verbosity": 6,
"sendToServer": false
@@ -42,6 +42,44 @@ public record CoreConfig : BaseConfig
[JsonPropertyName("features")]
public required ServerFeatures Features { get; set; }
[JsonPropertyName("enableNoGCRegions")]
// ReSharper disable once InconsistentNaming
public required bool EnableNoGCRegions { get; set; }
// ReSharper disable once InconsistentNaming
private int _noGCRegionMaxMemoryGB = 4;
[JsonPropertyName("noGCRegionMaxMemoryGB")]
// ReSharper disable once InconsistentNaming
public required int NoGCRegionMaxMemoryGB
{
get => _noGCRegionMaxMemoryGB;
set
{
if (value <= 0)
{
throw new Exception($"Invalid value {nameof(NoGCRegionMaxMemoryGB)}: {value}. Must be greater than zero.");
}
_noGCRegionMaxMemoryGB = value;
}
}
// ReSharper disable once InconsistentNaming
private int _noGCRegionMaxLOHMemoryGB = 3;
[JsonPropertyName("noGCRegionMaxLOHMemoryGB")]
// ReSharper disable once InconsistentNaming
public required int NoGCRegionMaxLOHMemoryGB
{
get => _noGCRegionMaxLOHMemoryGB;
set
{
if (value <= 0)
{
throw new Exception($"Invalid value {nameof(NoGCRegionMaxLOHMemoryGB)}: {value}. Must be greater than zero.");
}
_noGCRegionMaxLOHMemoryGB = value;
}
}
/// <summary>
/// Commit hash build server was created from
/// </summary>
+47 -6
View File
@@ -1,5 +1,6 @@
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Text;
@@ -118,6 +119,8 @@ public static class Program
forwardedHeadersOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardedHeadersOptions);
app.UseRequestTracking();
SetConsoleOutputMode();
await app.Services.GetRequiredService<SptServerStartupService>().Startup();
@@ -147,16 +150,54 @@ public static class Program
app.UseMiddleware<SptLoggerMiddleware>();
app.Use(
async (HttpContext context, RequestDelegate next) =>
{
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
}
);
app.Use(async (context, next) => await HandleRequest(context, next));
app.UseSptBlazor();
}
private static async Task HandleRequest(HttpContext context, RequestDelegate next)
{
var config = context.RequestServices.GetRequiredService<ConfigServer>().GetConfig<CoreConfig>();
// if no other requests are running, start the no GC region, otherwise dont start it
if (!RequestTrackingMiddleware.OtherRequestsActive)
{
if (config.EnableNoGCRegions && GCSettings.LatencyMode != GCLatencyMode.NoGCRegion)
{
try
{
GC.TryStartNoGCRegion(
1024L * 1024L * 1024L * config.NoGCRegionMaxMemoryGB,
1024L * 1024L * 1024L * config.NoGCRegionMaxLOHMemoryGB,
true
);
}
catch (Exception)
{
// ignored, we keep going
}
}
}
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
// if no other requests are running, end the no GC region, otherwise dont stop it as other requests need it still
if (!RequestTrackingMiddleware.OtherRequestsActive)
{
if (config.EnableNoGCRegions && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
{
try
{
GC.EndNoGCRegion();
}
catch (Exception)
{
// ignored, we dont care about handling this
}
}
}
}
private static void ConfigureKestrel(WebApplicationBuilder builder)
{
builder.WebHost.ConfigureKestrel(
@@ -0,0 +1,41 @@
namespace SPTarkov.Server.Services;
public class RequestTrackingMiddleware
{
private static int _activeRequests;
private readonly RequestDelegate _next;
public static bool OtherRequestsActive
{
get
{
return _activeRequests > 1;
}
}
public RequestTrackingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Interlocked.Increment(ref _activeRequests);
try
{
await _next(context);
}
finally
{
Interlocked.Decrement(ref _activeRequests);
}
}
}
public static class RequestTrackingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestTracking(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestTrackingMiddleware>();
}
}