From 5d2b25bccb7aa088810721dbcc47430072319e2e Mon Sep 17 00:00:00 2001 From: Loporrit <141286461+loporrit@users.noreply.github.com> Date: Sat, 10 Feb 2024 18:45:18 +0000 Subject: [PATCH] Revert "relieve gc pressure maybe" This reverts commit 40b8310ba9a4ed90a2dcb51d1dbe530d3ce712b5. --- .../PlayerData/Factories/PlayerDataFactory.cs | 5 +- .../PlayerData/Handlers/PairHandler.cs | 2 +- MareSynchronos/Services/DalamudUtilService.cs | 89 ++++++++----------- .../Services/PerformanceCollectorService.cs | 41 ++++----- MareSynchronos/Utils/Crypto.cs | 16 ++-- 5 files changed, 68 insertions(+), 85 deletions(-) diff --git a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs index 8c66e7b..a188f1f 100644 --- a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs +++ b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs @@ -136,7 +136,7 @@ public class PlayerDataFactory totalWaitTime -= 50; } - DateTime start = DateTime.UtcNow; + Stopwatch st = Stopwatch.StartNew(); // penumbra call, it's currently broken IReadOnlyDictionary? resolvedPaths; @@ -225,7 +225,8 @@ public class PlayerDataFactory } } - _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(DateTime.UtcNow.Ticks - start.Ticks).TotalMilliseconds); + st.Stop(); + _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(st.ElapsedTicks).TotalMilliseconds); return previousData; } diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index 13a2f6b..84b3387 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -459,7 +459,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase if (string.IsNullOrEmpty(PlayerName)) { var pc = _dalamudUtil.FindPlayerByNameHash(OnlineUser.Ident); - if (pc.ObjectId == 0) return; + if (pc == default((string, nint))) return; Logger.LogDebug("One-Time Initializing {this}", this); Initialize(pc.Name); Logger.LogDebug("One-Time Initialized {this}", this); diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index b57875b..c4273ee 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -1,5 +1,7 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Control; @@ -12,24 +14,16 @@ using Microsoft.Extensions.Logging; using System.Numerics; using System.Runtime.CompilerServices; using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; -using DalamudGameObject = Dalamud.Game.ClientState.Objects.Types.GameObject; namespace MareSynchronos.Services; public class DalamudUtilService : IHostedService, IMediatorSubscriber { - internal struct PlayerCharacter - { - public uint ObjectId; - public string Name; - public uint HomeWorldId; - public nint Address; - }; - private struct PlayerInfo { - public PlayerCharacter Character; - public string Hash; + public String Name; + public uint WorldId; + public String Hash; }; private readonly List _classJobIdsIgnoredForPets = [30]; @@ -46,8 +40,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private string _lastGlobalBlockPlayer = string.Empty; private string _lastGlobalBlockReason = string.Empty; private ushort _lastZone = 0; - private readonly Dictionary _playerCharas = new(StringComparer.Ordinal); - private readonly List _notUpdatedCharas = []; + private Dictionary _playerCharas = new(StringComparer.Ordinal); private bool _sentBetweenAreas = false; private static readonly Dictionary _playerInfoCache = new(); @@ -77,7 +70,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber await RunOnFrameworkThread(() => { var addr = GetPlayerCharacterFromCachedTableByIdent(ident); - var pc = _clientState.LocalPlayer!; + var pc = GetPlayerCharacter(); var gobj = CreateGameObject(addr); // Any further than roughly 55y is out of range for targetting if (gobj != null && Vector3.Distance(pc.Position, gobj.Position) < 55.0f) @@ -186,6 +179,12 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return await RunOnFrameworkThread(() => GetPet(playerPointer)).ConfigureAwait(false); } + public PlayerCharacter GetPlayerCharacter() + { + EnsureIsOnFramework(); + return _clientState.LocalPlayer!; + } + public IntPtr GetPlayerCharacterFromCachedTableByIdent(string characterName) { if (_playerCharas.TryGetValue(characterName, out var pchar)) return pchar.Address; @@ -373,23 +372,21 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return _gameGui.WorldToScreen(obj.Position, out var screenPos) ? screenPos : Vector2.Zero; } - internal PlayerCharacter FindPlayerByNameHash(string ident) + internal (string Name, nint Address) FindPlayerByNameHash(string ident) { _playerCharas.TryGetValue(ident, out var result); return result; } - private unsafe PlayerInfo GetPlayerInfo(DalamudGameObject chara) + private PlayerInfo GetPlayerInfo(PlayerCharacter p) { - uint id = chara.ObjectId; + uint id = p.ObjectId; if (!_playerInfoCache.TryGetValue(id, out var info)) { - info.Character.ObjectId = id; - info.Character.Name = chara.Name.ToString(); - info.Character.HomeWorldId = ((BattleChara*)chara.Address)->Character.HomeWorld; - info.Character.Address = chara.Address; - info.Hash = Crypto.GetHash256(info.Character.Name + info.Character.HomeWorldId.ToString()); + info.Name = p.Name.ToString(); + info.WorldId = p.HomeWorld.Id; + info.Hash = Crypto.GetHash256(info.Name + info.WorldId.ToString()); _playerInfoCache[id] = info; } @@ -402,6 +399,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber { var gameObj = (GameObject*)p.Address; var drawObj = gameObj->DrawObject; + var playerInfo = GetPlayerInfo(p); bool isDrawing = false; bool isDrawingChanged = false; if ((nint)drawObj != IntPtr.Zero) @@ -413,20 +411,20 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber if (!isDrawing) { isDrawing = ((CharacterBase*)drawObj)->HasModelFilesInSlotLoaded != 0; - if (isDrawing && !string.Equals(_lastGlobalBlockPlayer, p.Name, StringComparison.Ordinal) + if (isDrawing && !string.Equals(_lastGlobalBlockPlayer, playerInfo.Name, StringComparison.Ordinal) && !string.Equals(_lastGlobalBlockReason, "HasModelFilesInSlotLoaded", StringComparison.Ordinal)) { - _lastGlobalBlockPlayer = p.Name; + _lastGlobalBlockPlayer = playerInfo.Name; _lastGlobalBlockReason = "HasModelFilesInSlotLoaded"; isDrawingChanged = true; } } else { - if (!string.Equals(_lastGlobalBlockPlayer, p.Name, StringComparison.Ordinal) + if (!string.Equals(_lastGlobalBlockPlayer, playerInfo.Name, StringComparison.Ordinal) && !string.Equals(_lastGlobalBlockReason, "HasModelInSlotLoaded", StringComparison.Ordinal)) { - _lastGlobalBlockPlayer = p.Name; + _lastGlobalBlockPlayer = playerInfo.Name; _lastGlobalBlockReason = "HasModelInSlotLoaded"; isDrawingChanged = true; } @@ -434,10 +432,10 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber } else { - if (!string.Equals(_lastGlobalBlockPlayer, p.Name, StringComparison.Ordinal) + if (!string.Equals(_lastGlobalBlockPlayer, playerInfo.Name, StringComparison.Ordinal) && !string.Equals(_lastGlobalBlockReason, "RenderFlags", StringComparison.Ordinal)) { - _lastGlobalBlockPlayer = p.Name; + _lastGlobalBlockPlayer = playerInfo.Name; _lastGlobalBlockReason = "RenderFlags"; isDrawingChanged = true; } @@ -446,7 +444,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber if (isDrawingChanged) { - _logger.LogTrace("Global draw block: START => {name} ({reason})", p.Name, _lastGlobalBlockReason); + _logger.LogTrace("Global draw block: START => {name} ({reason})", playerInfo.Name, _lastGlobalBlockReason); } IsAnythingDrawing |= isDrawing; @@ -466,32 +464,19 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber } IsAnythingDrawing = false; + + var playerCharaList = new Dictionary(StringComparer.Ordinal); _performanceCollector.LogPerformance(this, "ObjTableToCharas", - () => - { - _notUpdatedCharas.AddRange(_playerCharas.Keys); - - foreach (var chara in _objectTable) + () => { + foreach (var p in _objectTable.OfType().Where(o => o.ObjectIndex < 200)) { - if (chara.ObjectIndex % 2 != 0 || chara.ObjectIndex >= 200) continue; - - string charaName = chara.Name.ToString(); - uint homeWorldId = ((BattleChara*)chara.Address)->Character.HomeWorld; - - var info = GetPlayerInfo(chara); - if (!IsAnythingDrawing) - CheckCharacterForDrawing(info.Character); - _notUpdatedCharas.Remove(info.Hash); - _playerCharas[info.Hash] = info.Character; + CheckCharacterForDrawing(p); + var info = GetPlayerInfo(p); + playerCharaList.Add(info.Hash, (info.Name, p.Address)); } - - foreach (var notUpdatedChara in _notUpdatedCharas) - { - _playerCharas.Remove(notUpdatedChara); - } - - _notUpdatedCharas.Clear(); - }); + } + ); + _playerCharas = playerCharaList; if (!IsAnythingDrawing && !string.IsNullOrEmpty(_lastGlobalBlockPlayer)) { diff --git a/MareSynchronos/Services/PerformanceCollectorService.cs b/MareSynchronos/Services/PerformanceCollectorService.cs index aab74a4..5dc209d 100644 --- a/MareSynchronos/Services/PerformanceCollectorService.cs +++ b/MareSynchronos/Services/PerformanceCollectorService.cs @@ -3,6 +3,7 @@ using MareSynchronos.Utils; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; +using System.Diagnostics; using System.Globalization; using System.Text; @@ -13,7 +14,7 @@ public sealed class PerformanceCollectorService : IHostedService private const string _counterSplit = "=>"; private readonly ILogger _logger; private readonly MareConfigService _mareConfigService; - public ConcurrentDictionary>> PerformanceCounters { get; } = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary>> _performanceCounters = new(StringComparer.Ordinal); private readonly CancellationTokenSource _periodicLogPruneTask = new(); public PerformanceCollectorService(ILogger logger, MareConfigService mareConfigService) @@ -22,57 +23,49 @@ public sealed class PerformanceCollectorService : IHostedService _mareConfigService = mareConfigService; } - public T LogPerformance(object sender, string counterName, Func func, int maxEntries = 10000) + public T LogPerformance(object sender, string counterName, Func func) { 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(maxEntries); + list = _performanceCounters[counterName] = new(10000); } - var dt = DateTime.UtcNow.Ticks; + Stopwatch st = Stopwatch.StartNew(); try { return func.Invoke(); } finally { - 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)); + st.Stop(); + list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); } } - public void LogPerformance(object sender, string counterName, Action act, int maxEntries = 10000) + public void LogPerformance(object sender, string counterName, Action act) { 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(maxEntries); + list = _performanceCounters[counterName] = new(10000); } - var dt = DateTime.UtcNow.Ticks; + Stopwatch st = Stopwatch.StartNew(); try { act.Invoke(); } finally { - 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)); + st.Stop(); + list.Add(new(TimeOnly.FromDateTime(DateTime.Now), st.ElapsedTicks)); } } @@ -104,7 +97,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('|'); @@ -176,12 +169,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 b8890bc..45f7482 100644 --- a/MareSynchronos/Utils/Crypto.cs +++ b/MareSynchronos/Utils/Crypto.cs @@ -7,12 +7,10 @@ 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); - private static readonly SHA256CryptoServiceProvider _sha256CryptoProvider = new(); - private static readonly SHA1CryptoServiceProvider _sha1CryptoProvider = new(); + +#pragma warning disable SYSLIB0021 // Type or member is obsolete public static string GetFileHash(this string filePath) { @@ -41,7 +39,10 @@ public static class Crypto if (_hashListSHA1.TryGetValue(stringToCompute, out var hash)) return hash; - return _hashListSHA1[stringToCompute] = BitConverter.ToString(_sha1CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); + using SHA1CryptoServiceProvider cryptoProvider = new(); + var computedHash = BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); + _hashListSHA1[stringToCompute] = computedHash; + return computedHash; } private static string GetOrComputeHashSHA256(string stringToCompute) @@ -49,7 +50,10 @@ public static class Crypto if (_hashListSHA256.TryGetValue(stringToCompute, out var hash)) return hash; - return _hashListSHA256[stringToCompute] = BitConverter.ToString(_sha256CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); + using SHA256CryptoServiceProvider cryptoProvider = new(); + 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