From 09790553c3faf22674aa0690979803a0175589e4 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sat, 10 Feb 2024 14:21:48 +0100 Subject: [PATCH] relieve gc pressure maybe --- .../PlayerData/Factories/PlayerDataFactory.cs | 5 +-- MareSynchronos/Services/DalamudUtilService.cs | 40 +++++++++++++----- .../Services/PerformanceCollectorService.cs | 41 +++++++++++-------- MareSynchronos/Utils/Crypto.cs | 16 +++----- 4 files changed, 62 insertions(+), 40 deletions(-) diff --git a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs index a188f1f..8c66e7b 100644 --- a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs +++ b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs @@ -136,7 +136,7 @@ public class PlayerDataFactory totalWaitTime -= 50; } - Stopwatch st = Stopwatch.StartNew(); + DateTime start = DateTime.UtcNow; // penumbra call, it's currently broken IReadOnlyDictionary? resolvedPaths; @@ -225,8 +225,7 @@ public class PlayerDataFactory } } - st.Stop(); - _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(st.ElapsedTicks).TotalMilliseconds); + _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(DateTime.UtcNow.Ticks - start.Ticks).TotalMilliseconds); return previousData; } diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index 71b78b6..13aee2b 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -31,7 +31,8 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private string _lastGlobalBlockPlayer = string.Empty; private string _lastGlobalBlockReason = string.Empty; private ushort _lastZone = 0; - private Dictionary _playerCharas = new(StringComparer.Ordinal); + private readonly Dictionary _playerCharas = new(StringComparer.Ordinal); + private readonly List _notUpdatedCharas = []; private bool _sentBetweenAreas = false; public DalamudUtilService(ILogger logger, IClientState clientState, IObjectTable objectTable, IFramework framework, @@ -360,13 +361,13 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return result; } - private unsafe void CheckCharacterForDrawing(PlayerCharacter p) + private unsafe void CheckCharacterForDrawing(nint address, string characterName) { if (!IsAnythingDrawing) { - var gameObj = (GameObject*)p.Address; + var gameObj = (GameObject*)address; var drawObj = gameObj->DrawObject; - var playerName = p.Name.ToString(); + var playerName = characterName; bool isDrawing = false; bool isDrawingChanged = false; if ((nint)drawObj != IntPtr.Zero) @@ -431,13 +432,32 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber } IsAnythingDrawing = false; - _playerCharas = _performanceCollector.LogPerformance(this, "ObjTableToCharas", - () => _objectTable.OfType().Where(o => o.ObjectIndex < 200) - .ToDictionary(p => p.GetHash256(), p => + _performanceCollector.LogPerformance(this, "ObjTableToCharas", + () => + { + _notUpdatedCharas.AddRange(_playerCharas.Keys); + + foreach (var chara in _objectTable) { - CheckCharacterForDrawing(p); - return (p.Name.ToString(), p.Address); - }, StringComparer.Ordinal)); + 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)) { diff --git a/MareSynchronos/Services/PerformanceCollectorService.cs b/MareSynchronos/Services/PerformanceCollectorService.cs index 5dc209d..aab74a4 100644 --- a/MareSynchronos/Services/PerformanceCollectorService.cs +++ b/MareSynchronos/Services/PerformanceCollectorService.cs @@ -3,7 +3,6 @@ using MareSynchronos.Utils; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; -using System.Diagnostics; using System.Globalization; using System.Text; @@ -14,7 +13,7 @@ public sealed class PerformanceCollectorService : IHostedService private const string _counterSplit = "=>"; private readonly ILogger _logger; private readonly MareConfigService _mareConfigService; - private readonly ConcurrentDictionary>> _performanceCounters = new(StringComparer.Ordinal); + public ConcurrentDictionary>> PerformanceCounters { get; } = new(StringComparer.Ordinal); private readonly CancellationTokenSource _periodicLogPruneTask = new(); public PerformanceCollectorService(ILogger logger, MareConfigService mareConfigService) @@ -23,49 +22,57 @@ public sealed class PerformanceCollectorService : IHostedService _mareConfigService = mareConfigService; } - public T LogPerformance(object sender, string counterName, Func func) + public T LogPerformance(object sender, string counterName, Func func, int maxEntries = 10000) { if (!_mareConfigService.Current.LogPerformance) return func.Invoke(); 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 { return func.Invoke(); } finally { - st.Stop(); - list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); + var elapsed = DateTime.UtcNow.Ticks - dt; +#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; } 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 { act.Invoke(); } finally { - st.Stop(); - list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); + var elapsed = DateTime.UtcNow.Ticks - dt; +#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"); } - var data = _performanceCounters.ToList(); + var data = PerformanceCounters.ToList(); var longestCounterName = data.OrderByDescending(d => d.Key.Length).First().Key.Length + 2; sb.Append("-Last".PadRight(15, '-')); sb.Append('|'); @@ -169,12 +176,12 @@ public sealed class PerformanceCollectorService : IHostedService { await Task.Delay(TimeSpan.FromMinutes(10), _periodicLogPruneTask.Token).ConfigureAwait(false); - foreach (var entries in _performanceCounters.ToList()) + foreach (var entries in PerformanceCounters.ToList()) { try { 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); } diff --git a/MareSynchronos/Utils/Crypto.cs b/MareSynchronos/Utils/Crypto.cs index 45f7482..b8890bc 100644 --- a/MareSynchronos/Utils/Crypto.cs +++ b/MareSynchronos/Utils/Crypto.cs @@ -7,10 +7,12 @@ namespace MareSynchronos.Utils; public static class Crypto { +#pragma warning disable SYSLIB0021 // Type or member is obsolete + private static readonly Dictionary _hashListSHA1 = new(StringComparer.Ordinal); private static readonly Dictionary _hashListSHA256 = new(StringComparer.Ordinal); - -#pragma warning disable SYSLIB0021 // Type or member is obsolete + private static readonly SHA256CryptoServiceProvider _sha256CryptoProvider = new(); + private static readonly SHA1CryptoServiceProvider _sha1CryptoProvider = new(); public static string GetFileHash(this string filePath) { @@ -39,10 +41,7 @@ public static class Crypto if (_hashListSHA1.TryGetValue(stringToCompute, out var hash)) return hash; - using SHA1CryptoServiceProvider cryptoProvider = new(); - var computedHash = BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); - _hashListSHA1[stringToCompute] = computedHash; - return computedHash; + return _hashListSHA1[stringToCompute] = BitConverter.ToString(_sha1CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); } private static string GetOrComputeHashSHA256(string stringToCompute) @@ -50,10 +49,7 @@ public static class Crypto if (_hashListSHA256.TryGetValue(stringToCompute, out var hash)) return hash; - using SHA256CryptoServiceProvider cryptoProvider = new(); - var computedHash = BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); - _hashListSHA256[stringToCompute] = computedHash; - return computedHash; + return _hashListSHA256[stringToCompute] = BitConverter.ToString(_sha256CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); } #pragma warning restore SYSLIB0021 // Type or member is obsolete