relieve gc pressure maybe

This commit is contained in:
rootdarkarchon
2024-02-10 14:21:48 +01:00
parent 780dd26166
commit 09790553c3
4 changed files with 62 additions and 40 deletions

View File

@@ -136,7 +136,7 @@ public class PlayerDataFactory
totalWaitTime -= 50; totalWaitTime -= 50;
} }
Stopwatch st = Stopwatch.StartNew(); DateTime start = DateTime.UtcNow;
// penumbra call, it's currently broken // penumbra call, it's currently broken
IReadOnlyDictionary<string, string[]>? resolvedPaths; IReadOnlyDictionary<string, string[]>? resolvedPaths;
@@ -225,8 +225,7 @@ public class PlayerDataFactory
} }
} }
st.Stop(); _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(DateTime.UtcNow.Ticks - start.Ticks).TotalMilliseconds);
_logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(st.ElapsedTicks).TotalMilliseconds);
return previousData; return previousData;
} }

View File

@@ -31,7 +31,8 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
private string _lastGlobalBlockPlayer = string.Empty; private string _lastGlobalBlockPlayer = string.Empty;
private string _lastGlobalBlockReason = string.Empty; private string _lastGlobalBlockReason = string.Empty;
private ushort _lastZone = 0; private ushort _lastZone = 0;
private Dictionary<string, (string Name, nint Address)> _playerCharas = new(StringComparer.Ordinal); private readonly Dictionary<string, (string Name, nint Address)> _playerCharas = new(StringComparer.Ordinal);
private readonly List<string> _notUpdatedCharas = [];
private bool _sentBetweenAreas = false; private bool _sentBetweenAreas = false;
public DalamudUtilService(ILogger<DalamudUtilService> logger, IClientState clientState, IObjectTable objectTable, IFramework framework, public DalamudUtilService(ILogger<DalamudUtilService> logger, IClientState clientState, IObjectTable objectTable, IFramework framework,
@@ -360,13 +361,13 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
return result; return result;
} }
private unsafe void CheckCharacterForDrawing(PlayerCharacter p) private unsafe void CheckCharacterForDrawing(nint address, string characterName)
{ {
if (!IsAnythingDrawing) if (!IsAnythingDrawing)
{ {
var gameObj = (GameObject*)p.Address; var gameObj = (GameObject*)address;
var drawObj = gameObj->DrawObject; var drawObj = gameObj->DrawObject;
var playerName = p.Name.ToString(); var playerName = characterName;
bool isDrawing = false; bool isDrawing = false;
bool isDrawingChanged = false; bool isDrawingChanged = false;
if ((nint)drawObj != IntPtr.Zero) if ((nint)drawObj != IntPtr.Zero)
@@ -431,13 +432,32 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
} }
IsAnythingDrawing = false; IsAnythingDrawing = false;
_playerCharas = _performanceCollector.LogPerformance(this, "ObjTableToCharas", _performanceCollector.LogPerformance(this, "ObjTableToCharas",
() => _objectTable.OfType<PlayerCharacter>().Where(o => o.ObjectIndex < 200) () =>
.ToDictionary(p => p.GetHash256(), p =>
{ {
CheckCharacterForDrawing(p); _notUpdatedCharas.AddRange(_playerCharas.Keys);
return (p.Name.ToString(), p.Address);
}, StringComparer.Ordinal)); foreach (var chara in _objectTable)
{
if (chara.ObjectIndex % 2 != 0 || chara.ObjectIndex >= 200) continue;
string charaName = chara.Name.ToString();
string homeWorldId = ((BattleChara*)chara.Address)->Character.HomeWorld.ToString();
var hash = (charaName + homeWorldId).GetHash256();
if (!IsAnythingDrawing)
CheckCharacterForDrawing(chara.Address, charaName);
_notUpdatedCharas.Remove(hash);
_playerCharas[hash] = (charaName, chara.Address);
}
foreach (var notUpdatedChara in _notUpdatedCharas)
{
_playerCharas.Remove(notUpdatedChara);
}
_notUpdatedCharas.Clear();
});
if (!IsAnythingDrawing && !string.IsNullOrEmpty(_lastGlobalBlockPlayer)) if (!IsAnythingDrawing && !string.IsNullOrEmpty(_lastGlobalBlockPlayer))
{ {

View File

@@ -3,7 +3,6 @@ using MareSynchronos.Utils;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
@@ -14,7 +13,7 @@ public sealed class PerformanceCollectorService : IHostedService
private const string _counterSplit = "=>"; private const string _counterSplit = "=>";
private readonly ILogger<PerformanceCollectorService> _logger; private readonly ILogger<PerformanceCollectorService> _logger;
private readonly MareConfigService _mareConfigService; private readonly MareConfigService _mareConfigService;
private readonly ConcurrentDictionary<string, RollingList<Tuple<TimeOnly, long>>> _performanceCounters = new(StringComparer.Ordinal); public ConcurrentDictionary<string, RollingList<Tuple<TimeOnly, long>>> PerformanceCounters { get; } = new(StringComparer.Ordinal);
private readonly CancellationTokenSource _periodicLogPruneTask = new(); private readonly CancellationTokenSource _periodicLogPruneTask = new();
public PerformanceCollectorService(ILogger<PerformanceCollectorService> logger, MareConfigService mareConfigService) public PerformanceCollectorService(ILogger<PerformanceCollectorService> logger, MareConfigService mareConfigService)
@@ -23,49 +22,57 @@ public sealed class PerformanceCollectorService : IHostedService
_mareConfigService = mareConfigService; _mareConfigService = mareConfigService;
} }
public T LogPerformance<T>(object sender, string counterName, Func<T> func) public T LogPerformance<T>(object sender, string counterName, Func<T> func, int maxEntries = 10000)
{ {
if (!_mareConfigService.Current.LogPerformance) return func.Invoke(); if (!_mareConfigService.Current.LogPerformance) return func.Invoke();
counterName = sender.GetType().Name + _counterSplit + counterName; counterName = sender.GetType().Name + _counterSplit + counterName;
if (!_performanceCounters.TryGetValue(counterName, out var list)) if (!PerformanceCounters.TryGetValue(counterName, out var list))
{ {
list = _performanceCounters[counterName] = new(10000); list = PerformanceCounters[counterName] = new(maxEntries);
} }
Stopwatch st = Stopwatch.StartNew(); var dt = DateTime.UtcNow.Ticks;
try try
{ {
return func.Invoke(); return func.Invoke();
} }
finally finally
{ {
st.Stop(); var elapsed = DateTime.UtcNow.Ticks - dt;
list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); #if DEBUG
if (TimeSpan.FromTicks(elapsed) > TimeSpan.FromMilliseconds(10))
_logger.LogWarning(">10ms spike on {counterName}: {time}", counterName, TimeSpan.FromTicks(elapsed));
#endif
list.Add(new(TimeOnly.FromDateTime(DateTime.Now), elapsed));
} }
} }
public void LogPerformance(object sender, string counterName, Action act) public void LogPerformance(object sender, string counterName, Action act, int maxEntries = 10000)
{ {
if (!_mareConfigService.Current.LogPerformance) { act.Invoke(); return; } if (!_mareConfigService.Current.LogPerformance) { act.Invoke(); return; }
counterName = sender.GetType().Name + _counterSplit + counterName; counterName = sender.GetType().Name + _counterSplit + counterName;
if (!_performanceCounters.TryGetValue(counterName, out var list)) if (!PerformanceCounters.TryGetValue(counterName, out var list))
{ {
list = _performanceCounters[counterName] = new(10000); list = PerformanceCounters[counterName] = new(maxEntries);
} }
Stopwatch st = Stopwatch.StartNew(); var dt = DateTime.UtcNow.Ticks;
try try
{ {
act.Invoke(); act.Invoke();
} }
finally finally
{ {
st.Stop(); var elapsed = DateTime.UtcNow.Ticks - dt;
list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); #if DEBUG
if (TimeSpan.FromTicks(elapsed) > TimeSpan.FromMilliseconds(10))
_logger.LogWarning(">10ms spike on {counterName}: {time}", counterName, TimeSpan.FromTicks(elapsed));
#endif
list.Add(new(TimeOnly.FromDateTime(DateTime.Now), elapsed));
} }
} }
@@ -97,7 +104,7 @@ public sealed class PerformanceCollectorService : IHostedService
{ {
sb.AppendLine("Performance metrics over total lifetime of each counter"); sb.AppendLine("Performance metrics over total lifetime of each counter");
} }
var data = _performanceCounters.ToList(); var data = PerformanceCounters.ToList();
var longestCounterName = data.OrderByDescending(d => d.Key.Length).First().Key.Length + 2; var longestCounterName = data.OrderByDescending(d => d.Key.Length).First().Key.Length + 2;
sb.Append("-Last".PadRight(15, '-')); sb.Append("-Last".PadRight(15, '-'));
sb.Append('|'); sb.Append('|');
@@ -169,12 +176,12 @@ public sealed class PerformanceCollectorService : IHostedService
{ {
await Task.Delay(TimeSpan.FromMinutes(10), _periodicLogPruneTask.Token).ConfigureAwait(false); await Task.Delay(TimeSpan.FromMinutes(10), _periodicLogPruneTask.Token).ConfigureAwait(false);
foreach (var entries in _performanceCounters.ToList()) foreach (var entries in PerformanceCounters.ToList())
{ {
try try
{ {
var last = entries.Value.ToList().Last(); var last = entries.Value.ToList().Last();
if (last.Item1.AddMinutes(10) < TimeOnly.FromDateTime(DateTime.Now) && !_performanceCounters.TryRemove(entries.Key, out _)) if (last.Item1.AddMinutes(10) < TimeOnly.FromDateTime(DateTime.Now) && !PerformanceCounters.TryRemove(entries.Key, out _))
{ {
_logger.LogDebug("Could not remove performance counter {counter}", entries.Key); _logger.LogDebug("Could not remove performance counter {counter}", entries.Key);
} }

View File

@@ -7,10 +7,12 @@ namespace MareSynchronos.Utils;
public static class Crypto public static class Crypto
{ {
#pragma warning disable SYSLIB0021 // Type or member is obsolete
private static readonly Dictionary<string, string> _hashListSHA1 = new(StringComparer.Ordinal); private static readonly Dictionary<string, string> _hashListSHA1 = new(StringComparer.Ordinal);
private static readonly Dictionary<string, string> _hashListSHA256 = new(StringComparer.Ordinal); private static readonly Dictionary<string, string> _hashListSHA256 = new(StringComparer.Ordinal);
private static readonly SHA256CryptoServiceProvider _sha256CryptoProvider = new();
#pragma warning disable SYSLIB0021 // Type or member is obsolete private static readonly SHA1CryptoServiceProvider _sha1CryptoProvider = new();
public static string GetFileHash(this string filePath) public static string GetFileHash(this string filePath)
{ {
@@ -39,10 +41,7 @@ public static class Crypto
if (_hashListSHA1.TryGetValue(stringToCompute, out var hash)) if (_hashListSHA1.TryGetValue(stringToCompute, out var hash))
return hash; return hash;
using SHA1CryptoServiceProvider cryptoProvider = new(); return _hashListSHA1[stringToCompute] = BitConverter.ToString(_sha1CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal);
var computedHash = BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal);
_hashListSHA1[stringToCompute] = computedHash;
return computedHash;
} }
private static string GetOrComputeHashSHA256(string stringToCompute) private static string GetOrComputeHashSHA256(string stringToCompute)
@@ -50,10 +49,7 @@ public static class Crypto
if (_hashListSHA256.TryGetValue(stringToCompute, out var hash)) if (_hashListSHA256.TryGetValue(stringToCompute, out var hash))
return hash; return hash;
using SHA256CryptoServiceProvider cryptoProvider = new(); return _hashListSHA256[stringToCompute] = BitConverter.ToString(_sha256CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal);
var computedHash = BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal);
_hashListSHA256[stringToCompute] = computedHash;
return computedHash;
} }
#pragma warning restore SYSLIB0021 // Type or member is obsolete #pragma warning restore SYSLIB0021 // Type or member is obsolete