thread safety and performance improv

This commit is contained in:
rootdarkarchon
2023-04-04 13:54:33 +02:00
parent a4d9207506
commit 1e9d4998ce
4 changed files with 42 additions and 24 deletions

View File

@@ -105,11 +105,10 @@ public sealed class FileCacheManager : IDisposable
public FileCacheEntity? GetFileCacheByHash(string hash) public FileCacheEntity? GetFileCacheByHash(string hash)
{ {
if (_fileCaches.Any(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal))) var entry = _fileCaches.FirstOrDefault(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal));
if (!EqualityComparer<KeyValuePair<string, FileCacheEntity>>.Default.Equals(entry, default))
{ {
return GetValidatedFileCache(_fileCaches.Where(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal)) return GetValidatedFileCache(entry.Value);
.OrderByDescending(f => f.Value.PrefixedFilePath.Length)
.FirstOrDefault(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal)).Value);
} }
return null; return null;

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Authors></Authors> <Authors></Authors>
<Company></Company> <Company></Company>
<Version>0.8.17</Version> <Version>0.8.18</Version>
<Description></Description> <Description></Description>
<Copyright></Copyright> <Copyright></Copyright>
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl> <PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>

View File

@@ -320,19 +320,6 @@ public class PlayerDataFactory
Stopwatch st = Stopwatch.StartNew(); Stopwatch st = Stopwatch.StartNew();
// gather up data from ipc
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
previousData.HeelsOffset = _ipcManager.GetHeelsOffset();
Task<string> getGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(playerRelatedObject.Address);
Task<string> getCustomizeData = _ipcManager.GetCustomizePlusScale();
Task<string> getPalettePlusData = _ipcManager.PalettePlusBuildPalette();
previousData.GlamourerString[playerRelatedObject.ObjectKind] = await getGlamourerData.ConfigureAwait(false);
_logger.LogDebug("Glamourer is now: {data}", previousData.GlamourerString[playerRelatedObject.ObjectKind]);
previousData.CustomizePlusScale = await getCustomizeData.ConfigureAwait(false);
_logger.LogDebug("Customize is now: {data}", previousData.CustomizePlusScale);
previousData.PalettePlusPalette = await getPalettePlusData.ConfigureAwait(false);
_logger.LogDebug("Palette is now: {data}", previousData.PalettePlusPalette);
// gather static replacements from render model // gather static replacements from render model
var (forwardResolve, reverseResolve) = BuildDataFromModel(objectKind, charaPointer, token); var (forwardResolve, reverseResolve) = BuildDataFromModel(objectKind, charaPointer, token);
Dictionary<string, List<string>> resolvedPaths = await GetFileReplacementsFromPaths(forwardResolve, reverseResolve).ConfigureAwait(false); Dictionary<string, List<string>> resolvedPaths = await GetFileReplacementsFromPaths(forwardResolve, reverseResolve).ConfigureAwait(false);
@@ -381,6 +368,19 @@ public class PlayerDataFactory
previousData.FileReplacements[item.Key] = new HashSet<FileReplacement>(item.Value.Where(v => v.HasFileReplacement).OrderBy(v => v.ResolvedPath, StringComparer.Ordinal), FileReplacementComparer.Instance); previousData.FileReplacements[item.Key] = new HashSet<FileReplacement>(item.Value.Where(v => v.HasFileReplacement).OrderBy(v => v.ResolvedPath, StringComparer.Ordinal), FileReplacementComparer.Instance);
} }
// gather up data from ipc
previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations();
previousData.HeelsOffset = _ipcManager.GetHeelsOffset();
Task<string> getGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(playerRelatedObject.Address);
Task<string> getCustomizeData = _ipcManager.GetCustomizePlusScale();
Task<string> getPalettePlusData = _ipcManager.PalettePlusBuildPalette();
previousData.GlamourerString[playerRelatedObject.ObjectKind] = await getGlamourerData.ConfigureAwait(false);
_logger.LogDebug("Glamourer is now: {data}", previousData.GlamourerString[playerRelatedObject.ObjectKind]);
previousData.CustomizePlusScale = await getCustomizeData.ConfigureAwait(false);
_logger.LogDebug("Customize is now: {data}", previousData.CustomizePlusScale);
previousData.PalettePlusPalette = await getPalettePlusData.ConfigureAwait(false);
_logger.LogDebug("Palette is now: {data}", previousData.PalettePlusPalette);
st.Stop(); 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(st.ElapsedTicks).TotalMilliseconds);

View File

@@ -12,6 +12,7 @@ using MareSynchronos.Utils;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
namespace MareSynchronos.Services; namespace MareSynchronos.Services;
@@ -53,6 +54,7 @@ public class DalamudUtilService : IHostedService
public unsafe GameObject* GposeTarget => TargetSystem.Instance()->GPoseTarget; public unsafe GameObject* GposeTarget => TargetSystem.Instance()->GPoseTarget;
public unsafe Dalamud.Game.ClientState.Objects.Types.GameObject? GposeTargetGameObject => GposeTarget == null ? null : _objectTable[GposeTarget->ObjectIndex]; public unsafe Dalamud.Game.ClientState.Objects.Types.GameObject? GposeTargetGameObject => GposeTarget == null ? null : _objectTable[GposeTarget->ObjectIndex];
public bool IsInCutscene { get; private set; } = false; public bool IsInCutscene { get; private set; } = false;
public bool IsInFrameworkThread => _framework.IsInFrameworkUpdateThread;
public bool IsInGpose { get; private set; } = false; public bool IsInGpose { get; private set; } = false;
public bool IsLoggedIn { get; private set; } public bool IsLoggedIn { get; private set; }
public bool IsPlayerPresent => _clientState.LocalPlayer != null && _clientState.LocalPlayer.IsValid(); public bool IsPlayerPresent => _clientState.LocalPlayer != null && _clientState.LocalPlayer.IsValid();
@@ -146,20 +148,37 @@ public class DalamudUtilService : IHostedService
return false; return false;
} }
public async Task RunOnFrameworkThread(Action act) public async Task RunOnFrameworkThread(Action act, [CallerMemberName] string callerMember = "",
[CallerFilePath] string callerFilePath = "", [CallerLineNumber] int lineNumber = 0)
{ {
_logger.LogTrace("Running Action on framework thread (FrameworkContext: {ctx}): {act}", _framework.IsInFrameworkUpdateThread, act); _logger.LogTrace("Running Action on framework thread (FrameworkContext: {ctx}): {member} in {file}:{line}", _framework.IsInFrameworkUpdateThread, callerMember, callerFilePath, lineNumber);
if (!_framework.IsInFrameworkUpdateThread) if (!_framework.IsInFrameworkUpdateThread)
await _framework.RunOnFrameworkThread(act).ConfigureAwait(false); {
await _framework.RunOnFrameworkThread(act).ContinueWith((_) => Task.CompletedTask).ConfigureAwait(false);
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
{
_logger.LogTrace("Still on framework");
await Task.Delay(1).ConfigureAwait(false);
}
}
else else
act(); act();
} }
public async Task<T> RunOnFrameworkThread<T>(Func<T> func) public async Task<T> RunOnFrameworkThread<T>(Func<T> func, [CallerMemberName] string callerMember = "",
[CallerFilePath] string callerFilePath = "", [CallerLineNumber] int lineNumber = 0)
{ {
_logger.LogTrace("Running Func on framework thread (FrameworkContext: {ctx}): {act}", _framework.IsInFrameworkUpdateThread, func); _logger.LogTrace("Running Func on framework thread (FrameworkContext: {ctx}): {member} in {file}:{line}", _framework.IsInFrameworkUpdateThread, callerMember, callerFilePath, lineNumber);
if (!_framework.IsInFrameworkUpdateThread) if (!_framework.IsInFrameworkUpdateThread)
return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false); {
var result = await _framework.RunOnFrameworkThread(func).ContinueWith((task) => task.Result).ConfigureAwait(false);
while (_framework.IsInFrameworkUpdateThread) // yield the thread again, should technically never be triggered
{
_logger.LogTrace("Still on framework");
await Task.Delay(1).ConfigureAwait(false);
}
return result;
}
else else
return func.Invoke(); return func.Invoke();
} }