performance cache + queued character data application

This commit is contained in:
2025-12-05 10:49:30 +09:00
parent 1c36db97dc
commit 541d17132d
6 changed files with 324 additions and 8 deletions

View File

@@ -41,6 +41,7 @@ public interface IPairHandlerAdapter : IDisposable, IPairPerformanceSubject
void Initialize();
void ApplyData(CharacterData data);
void ApplyLastReceivedData(bool forced = false);
bool FetchPerformanceMetricsFromCache();
void LoadCachedCharacterData(CharacterData data);
void SetUploading(bool uploading);
void SetPaused(bool paused);
@@ -67,6 +68,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
private readonly TextureDownscaleService _textureDownscaleService;
private readonly PairStateCache _pairStateCache;
private readonly PairPerformanceMetricsCache _performanceMetricsCache;
private readonly PairManager _pairManager;
private CancellationTokenSource? _applicationCancellationTokenSource = new();
private Guid _applicationId;
@@ -141,7 +143,8 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
PairProcessingLimiter pairProcessingLimiter,
ServerConfigurationManager serverConfigManager,
TextureDownscaleService textureDownscaleService,
PairStateCache pairStateCache) : base(logger, mediator)
PairStateCache pairStateCache,
PairPerformanceMetricsCache performanceMetricsCache) : base(logger, mediator)
{
_pairManager = pairManager;
Ident = ident;
@@ -157,6 +160,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
_serverConfigManager = serverConfigManager;
_textureDownscaleService = textureDownscaleService;
_pairStateCache = pairStateCache;
_performanceMetricsCache = performanceMetricsCache;
LastAppliedDataBytes = -1;
}
@@ -493,7 +497,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
LastAppliedApproximateEffectiveVRAMBytes = -1;
}
var sanitized = RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone());
var sanitized = CloneAndSanitizeLastReceived(out var dataHash);
if (sanitized is null)
{
Logger.LogTrace("Sanitized data null for {Ident}", Ident);
@@ -513,6 +517,100 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
ApplyCharacterData(Guid.NewGuid(), sanitized, shouldForce);
}
public bool FetchPerformanceMetricsFromCache()
{
EnsureInitialized();
var sanitized = CloneAndSanitizeLastReceived(out var dataHash);
if (sanitized is null || string.IsNullOrEmpty(dataHash))
{
return false;
}
if (!TryApplyCachedMetrics(dataHash))
{
return false;
}
_cachedData = sanitized;
_pairStateCache.Store(Ident, sanitized);
return true;
}
private CharacterData? CloneAndSanitizeLastReceived(out string? dataHash)
{
dataHash = null;
if (LastReceivedCharacterData is null)
{
return null;
}
var sanitized = RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone());
if (sanitized is null)
{
return null;
}
dataHash = GetDataHashSafe(sanitized);
return sanitized;
}
private string? GetDataHashSafe(CharacterData data)
{
try
{
return data.DataHash.Value;
}
catch (Exception ex)
{
Logger.LogDebug(ex, "Failed to compute character data hash for {Ident}", Ident);
return null;
}
}
private bool TryApplyCachedMetrics(string? dataHash)
{
if (string.IsNullOrEmpty(dataHash))
{
return false;
}
if (!_performanceMetricsCache.TryGetMetrics(Ident, dataHash, out var metrics))
{
return false;
}
ApplyCachedMetrics(metrics);
return true;
}
private void ApplyCachedMetrics(PairPerformanceMetrics metrics)
{
LastAppliedDataTris = metrics.TriangleCount;
LastAppliedApproximateVRAMBytes = metrics.ApproximateVramBytes;
LastAppliedApproximateEffectiveVRAMBytes = metrics.ApproximateEffectiveVramBytes;
}
private void StorePerformanceMetrics(CharacterData charaData)
{
if (LastAppliedDataTris < 0
|| LastAppliedApproximateVRAMBytes < 0
|| LastAppliedApproximateEffectiveVRAMBytes < 0)
{
return;
}
var dataHash = GetDataHashSafe(charaData);
if (string.IsNullOrEmpty(dataHash))
{
return;
}
_performanceMetricsCache.StoreMetrics(
Ident,
dataHash,
new PairPerformanceMetrics(LastAppliedDataTris, LastAppliedApproximateVRAMBytes, LastAppliedApproximateEffectiveVRAMBytes));
}
private bool HasMissingCachedFiles(CharacterData characterData)
{
try
@@ -878,6 +976,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
_cachedData = null;
_lastAppliedModdedPaths = null;
_needsCollectionRebuild = false;
_performanceMetricsCache.Clear(Ident);
Logger.LogDebug("Disposing {name} complete", name);
}
}
@@ -1262,6 +1361,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
await _playerPerformanceService.CheckTriangleUsageThresholds(this, charaData).ConfigureAwait(false);
}
StorePerformanceMetrics(charaData);
Logger.LogDebug("[{applicationId}] Application finished", _applicationId);
}
catch (OperationCanceledException)
@@ -1693,6 +1793,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
private readonly ServerConfigurationManager _serverConfigManager;
private readonly TextureDownscaleService _textureDownscaleService;
private readonly PairStateCache _pairStateCache;
private readonly PairPerformanceMetricsCache _pairPerformanceMetricsCache;
public PairHandlerAdapterFactory(
ILoggerFactory loggerFactory,
@@ -1709,7 +1810,8 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
PairProcessingLimiter pairProcessingLimiter,
ServerConfigurationManager serverConfigManager,
TextureDownscaleService textureDownscaleService,
PairStateCache pairStateCache)
PairStateCache pairStateCache,
PairPerformanceMetricsCache pairPerformanceMetricsCache)
{
_loggerFactory = loggerFactory;
_mediator = mediator;
@@ -1726,6 +1828,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
_serverConfigManager = serverConfigManager;
_textureDownscaleService = textureDownscaleService;
_pairStateCache = pairStateCache;
_pairPerformanceMetricsCache = pairPerformanceMetricsCache;
}
public IPairHandlerAdapter Create(string ident)
@@ -1748,6 +1851,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
_pairProcessingLimiter,
_serverConfigManager,
_textureDownscaleService,
_pairStateCache);
_pairStateCache,
_pairPerformanceMetricsCache);
}
}