Some misc performance changes + logging

This commit is contained in:
Zeffuro
2026-01-11 05:09:28 +01:00
parent 51934eb23d
commit 6d15ee1b13
5 changed files with 73 additions and 14 deletions
+23
View File
@@ -62,6 +62,10 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow
private readonly HashSet<uint> _searchMatchScratch = new(); private readonly HashSet<uint> _searchMatchScratch = new();
private bool _isRefreshing; private bool _isRefreshing;
private int _requestedUpdateCount;
private int _refreshFromLifecycleCount;
private long _lastLogTick;
public void ManualRefresh() public void ManualRefresh()
{ {
if (!IsOpen) return; if (!IsOpen) return;
@@ -104,6 +108,10 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow
try try
{ {
_isRefreshing = true; _isRefreshing = true;
_refreshFromLifecycleCount++;
LogRefreshStats();
InventoryState.RefreshFromGame(); InventoryState.RefreshFromGame();
RefreshCategoriesCore(autosize: true); RefreshCategoriesCore(autosize: true);
} }
@@ -405,8 +413,23 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow
RefreshCategoriesCore(false); RefreshCategoriesCore(false);
} }
private void LogRefreshStats()
{
long now = Environment.TickCount64;
if (now - _lastLogTick > 1000) // Log every second
{
Services.Logger.DebugOnly($"[Perf] Last 1s: OnRequestedUpdate={_requestedUpdateCount}, RefreshFromLifecycle={_refreshFromLifecycleCount}");
_requestedUpdateCount = 0;
_refreshFromLifecycleCount = 0;
_lastLogTick = now;
}
}
protected override void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData) protected override void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
{ {
_requestedUpdateCount++;
LogRefreshStats();
base.OnRequestedUpdate(addon, numberArrayData, stringArrayData); base.OnRequestedUpdate(addon, numberArrayData, stringArrayData);
if (DragDropState.IsDragging) if (DragDropState.IsDragging)
+1 -1
View File
@@ -88,7 +88,7 @@ public static class Util
{ {
FileInfo file = JsonFileHelper.GetFileInfo(SystemConfiguration.FileName); FileInfo file = JsonFileHelper.GetFileInfo(SystemConfiguration.FileName);
var config = JsonFileHelper.LoadFile<SystemConfiguration>(file.FullName); var config = JsonFileHelper.LoadFile<SystemConfiguration>(file.FullName);
config?.EnsureInitialized(); config.EnsureInitialized();
return config; return config;
} }
+14 -6
View File
@@ -20,6 +20,8 @@ public sealed unsafe class LootedItemsTracker : IDisposable
private readonly List<LootedItemInfo> _lootedItems = new(capacity: 64); private readonly List<LootedItemInfo> _lootedItems = new(capacity: 64);
private readonly Dictionary<(uint ItemId, bool IsHq), (InventoryItem Item, int Quantity)> _pendingChanges = new(capacity: 32); private readonly Dictionary<(uint ItemId, bool IsHq), (InventoryItem Item, int Quantity)> _pendingChanges = new(capacity: 32);
private static HashSet<uint>? _filteredCategoryItems;
private bool _isEnabled; private bool _isEnabled;
private long _batchStartTick; private long _batchStartTick;
private bool _hasPendingRemoval; private bool _hasPendingRemoval;
@@ -171,12 +173,18 @@ public sealed unsafe class LootedItemsTracker : IDisposable
private static bool ShouldFilterItem(uint itemId) private static bool ShouldFilterItem(uint itemId)
{ {
if (!Services.DataManager.GetExcelSheet<Item>().TryGetRow(itemId, out var item)) if (_filteredCategoryItems == null)
return false; {
_filteredCategoryItems = new HashSet<uint>();
var sheet = Services.DataManager.GetExcelSheet<Item>();
foreach (var row in sheet)
{
if (row.ItemUICategory.RowId == 62)
_filteredCategoryItems.Add(row.RowId);
}
Services.Logger.DebugOnly($"[LootedItemsTracker] Built filter cache with {_filteredCategoryItems.Count} items");
}
if (item.ItemUICategory.RowId == 62) return _filteredCategoryItems.Contains(itemId);
return true;
return false;
} }
} }
@@ -1,5 +1,6 @@
using System; using System;
using AetherBags.Inventory.Items; using AetherBags.Inventory.Items;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Common.Math; using FFXIVClientStructs.FFXIV.Common.Math;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
@@ -42,17 +43,28 @@ public sealed unsafe class LootedItemDisplayNode : SimpleComponentNode
_quantityTextNode.AttachNode(this); _quantityTextNode.AttachNode(this);
} }
public LootedItemInfo LootedItem public LootedItemInfo? LootedItem
{ {
get; get;
set set
{ {
bool needsCollisionUpdate = field is null && value is not null; bool needsCollisionUpdate = field is null && value is not null;
field = value; field = value;
var item = value.Item;
_iconNode.IconId = item.IconId; if (value is not null)
_iconNode.ItemTooltip = item.ItemId; {
_quantityTextNode.String = value.Quantity > 1 ? value.Quantity.ToString() : string.Empty; InventoryItem item = value.Item;
_iconNode.IconId = item.IconId;
_iconNode.ItemTooltip = item.ItemId;
_quantityTextNode.String = value.Quantity > 1 ? value.Quantity.ToString() : string.Empty;
_iconNode.IsVisible = true;
_quantityTextNode.IsVisible = true;
}
else
{
_iconNode.IsVisible = false;
_quantityTextNode.String = string.Empty;
}
if (needsCollisionUpdate) if (needsCollisionUpdate)
{ {
@@ -61,7 +73,7 @@ public sealed unsafe class LootedItemDisplayNode : SimpleComponentNode
addon->UpdateCollisionNodeList(false); addon->UpdateCollisionNodeList(false);
} }
} }
} = null!; } = null;
private void OnMouseClick(AtkEventListener* thisPtr, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, AtkEventData* atkEventData) private void OnMouseClick(AtkEventListener* thisPtr, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, AtkEventData* atkEventData)
{ {
@@ -180,6 +180,7 @@ public abstract class DeferrableLayoutListNode : SimpleComponentNode
private List<NodeBase>? _desiredScratch; private List<NodeBase>? _desiredScratch;
private List<NodeBase>? _toRemoveScratch; private List<NodeBase>? _toRemoveScratch;
private HashSet<object>? _dataKeysScratch; private HashSet<object>? _dataKeysScratch;
private Dictionary<object, NodeBase>? _byKeyScratch;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private List<NodeBase> RentExistingList(int capacity) private List<NodeBase> RentExistingList(int capacity)
@@ -309,7 +310,16 @@ public abstract class DeferrableLayoutListNode : SimpleComponentNode
Dictionary<TKey, TU>? byKey = null; Dictionary<TKey, TU>? byKey = null;
if (existing.Count > 0) if (existing.Count > 0)
{ {
byKey = new Dictionary<TKey, TU>(existing.Count, keyComparer); if (_byKeyScratch is Dictionary<TKey, TU> reusable)
{
byKey = reusable;
byKey.Clear();
}
else
{
byKey = new Dictionary<TKey, TU>(existing.Count, keyComparer);
}
for (int i = 0; i < existing.Count; i++) for (int i = 0; i < existing.Count; i++)
{ {
var tu = (TU)existing[i]; var tu = (TU)existing[i];
@@ -407,6 +417,12 @@ public abstract class DeferrableLayoutListNode : SimpleComponentNode
RecalculateLayout(); RecalculateLayout();
} }
if (byKey != null)
{
byKey.Clear();
_byKeyScratch = byKey as Dictionary<object, NodeBase>;
}
return structureChanged || orderChanged; return structureChanged || orderChanged;
} }