thread safety and performance improv
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user