Merge pull request #645 from sp-tarkov/disable-gc-requests
Added NoGCRegion feature
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
"profileSaveIntervalSeconds": 15,
|
||||
"sptFriendNickname": "SPT",
|
||||
"allowProfileWipe": true,
|
||||
"enableNoGCRegions": true,
|
||||
"noGCRegionMaxMemoryGB": 4,
|
||||
"noGCRegionMaxLOHMemoryGB": 3,
|
||||
"bsgLogging": {
|
||||
"verbosity": 6,
|
||||
"sendToServer": false
|
||||
|
||||
@@ -42,6 +42,50 @@ 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 ArgumentOutOfRangeException(
|
||||
$"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 ArgumentOutOfRangeException(
|
||||
$"Invalid value {nameof(NoGCRegionMaxLOHMemoryGB)}: {value}. Must be greater than zero."
|
||||
);
|
||||
}
|
||||
_noGCRegionMaxLOHMemoryGB = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commit hash build server was created from
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
@@ -147,12 +148,9 @@ public static class Program
|
||||
|
||||
app.UseMiddleware<SptLoggerMiddleware>();
|
||||
|
||||
app.Use(
|
||||
async (HttpContext context, RequestDelegate next) =>
|
||||
{
|
||||
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
|
||||
}
|
||||
);
|
||||
app.UseNoGCRegions();
|
||||
|
||||
app.Use(async (context, next) => await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next));
|
||||
|
||||
app.UseSptBlazor();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Runtime;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
|
||||
namespace SPTarkov.Server.Services;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class NoGCRegionMiddleware(RequestDelegate next)
|
||||
{
|
||||
private static long _activeRequests;
|
||||
|
||||
private static bool OtherRequestsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
return Interlocked.Read(ref _activeRequests) > 1;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
Interlocked.Increment(ref _activeRequests);
|
||||
|
||||
var config = context.RequestServices.GetRequiredService<ConfigServer>().GetConfig<CoreConfig>();
|
||||
|
||||
// if no other requests are running, start the no GC region, otherwise dont start it
|
||||
if (!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
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref _activeRequests);
|
||||
}
|
||||
|
||||
// if no other requests are running, end the no GC region, otherwise dont stop it as other requests need it still
|
||||
if (!OtherRequestsActive)
|
||||
{
|
||||
if (config.EnableNoGCRegions && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
|
||||
{
|
||||
try
|
||||
{
|
||||
GC.EndNoGCRegion();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored, we dont care about handling this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static class NoGCRegionMiddlewareExtensions
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static IApplicationBuilder UseNoGCRegions(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<NoGCRegionMiddleware>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user