diff --git a/Dalamud/Game/Internal/Framework.cs b/Dalamud/Game/Internal/Framework.cs
index e65ead3a0..e55f502ee 100644
--- a/Dalamud/Game/Internal/Framework.cs
+++ b/Dalamud/Game/Internal/Framework.cs
@@ -1,11 +1,13 @@
using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
using System.Runtime.InteropServices;
using Dalamud.Game.Internal.Gui;
using Dalamud.Game.Internal.Libc;
using Dalamud.Game.Internal.Network;
using Dalamud.Hooking;
using Serilog;
-using Dalamud.Game.Internal.File;
namespace Dalamud.Game.Internal {
///
@@ -30,6 +32,11 @@ namespace Dalamud.Game.Internal {
///
public FrameworkAddressResolver Address { get; }
+#region Stats
+ public static bool StatsEnabled { get; set; }
+ public static Dictionary> StatsHistory = new Dictionary>();
+ private static Stopwatch statsStopwatch = new Stopwatch();
+#endregion
#region Subsystems
///
@@ -108,7 +115,35 @@ namespace Dalamud.Game.Internal {
}
try {
- OnUpdateEvent?.Invoke(this);
+ if (StatsEnabled && OnUpdateEvent != null) {
+ // Stat Tracking for Framework Updates
+ var invokeList = OnUpdateEvent.GetInvocationList();
+ var notUpdated = StatsHistory.Keys.ToList();
+ // Individually invoke OnUpdate handlers and time them.
+ foreach (var d in invokeList) {
+ statsStopwatch.Restart();
+ d.Method.Invoke(d.Target, new object[]{ this });
+ statsStopwatch.Stop();
+ var key = $"{d.Target}::{d.Method.Name}";
+ if (notUpdated.Contains(key)) notUpdated.Remove(key);
+ if (!StatsHistory.ContainsKey(key)) StatsHistory.Add(key, new List());
+ StatsHistory[key].Add(statsStopwatch.Elapsed.TotalMilliseconds);
+ if (StatsHistory[key].Count > 1000) {
+ StatsHistory[key].RemoveRange(0, StatsHistory[key].Count - 1000);
+ }
+ }
+
+ // Cleanup handlers that are no longer being called
+ foreach (var key in notUpdated) {
+ if (StatsHistory[key].Count > 0) {
+ StatsHistory[key].RemoveAt(0);
+ } else {
+ StatsHistory.Remove(key);
+ }
+ }
+ } else {
+ OnUpdateEvent?.Invoke(this);
+ }
} catch (Exception ex) {
Log.Error(ex, "Exception while dispatching Framework::Update event.");
}
diff --git a/Dalamud/Interface/DalamudPluginStatWindow.cs b/Dalamud/Interface/DalamudPluginStatWindow.cs
index 7862075f1..0aad890fd 100644
--- a/Dalamud/Interface/DalamudPluginStatWindow.cs
+++ b/Dalamud/Interface/DalamudPluginStatWindow.cs
@@ -1,14 +1,15 @@
using System;
using System.Linq;
+using Dalamud.Game.Internal;
using Dalamud.Plugin;
using ImGuiNET;
namespace Dalamud.Interface {
- class DalamudPluginStatWindow : IDisposable {
+ internal class DalamudPluginStatWindow : IDisposable {
- private PluginManager pm;
- public DalamudPluginStatWindow(PluginManager pm) {
- this.pm = pm;
+ private readonly PluginManager pluginManager;
+ public DalamudPluginStatWindow(PluginManager pluginManager) {
+ this.pluginManager = pluginManager;
}
public bool Draw() {
@@ -29,7 +30,7 @@ namespace Dalamud.Interface {
ImGui.SameLine();
if (ImGui.Button("Reset")) {
- foreach (var a in this.pm.Plugins) {
+ foreach (var a in this.pluginManager.Plugins) {
a.PluginInterface.UiBuilder.lastDrawTime = -1;
a.PluginInterface.UiBuilder.maxDrawTime = -1;
a.PluginInterface.UiBuilder.drawTimeHistory.Clear();
@@ -51,7 +52,7 @@ namespace Dalamud.Interface {
ImGui.Text("Average");
ImGui.NextColumn();
ImGui.Separator();
- foreach (var a in this.pm.Plugins) {
+ foreach (var a in this.pluginManager.Plugins) {
ImGui.Text(a.Definition.Name);
ImGui.NextColumn();
ImGui.Text($"{a.PluginInterface.UiBuilder.lastDrawTime/10000f:F4}ms");
@@ -69,6 +70,59 @@ namespace Dalamud.Interface {
ImGui.Columns(1);
}
+ ImGui.EndTabItem();
+ }
+
+ if (ImGui.BeginTabItem("Framework times")) {
+
+ var doStats = Framework.StatsEnabled;
+
+ if (ImGui.Checkbox("Enable Framework Update Tracking", ref doStats)) {
+ Framework.StatsEnabled = doStats;
+ }
+
+ if (doStats) {
+ ImGui.SameLine();
+ if (ImGui.Button("Reset")) {
+ Framework.StatsHistory.Clear();
+ }
+
+ ImGui.Columns(4);
+ ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 300);
+ ImGui.SetColumnWidth(1, 100f);
+ ImGui.SetColumnWidth(2, 100f);
+ ImGui.SetColumnWidth(3, 100f);
+ ImGui.Text("Method");
+ ImGui.NextColumn();
+ ImGui.Text("Last");
+ ImGui.NextColumn();
+ ImGui.Text("Longest");
+ ImGui.NextColumn();
+ ImGui.Text("Average");
+ ImGui.NextColumn();
+ ImGui.Separator();
+ ImGui.Separator();
+
+ foreach (var handlerHistory in Framework.StatsHistory) {
+ if (handlerHistory.Value.Count == 0) continue;
+ ImGui.SameLine();
+ ImGui.Text($"{handlerHistory.Key}");
+ ImGui.NextColumn();
+ ImGui.Text($"{handlerHistory.Value.Last():F4}ms");
+ ImGui.NextColumn();
+ ImGui.Text($"{handlerHistory.Value.Max():F4}ms");
+ ImGui.NextColumn();
+ ImGui.Text($"{handlerHistory.Value.Average():F4}ms");
+ ImGui.NextColumn();
+ ImGui.Separator();
+ }
+ ImGui.Columns(0);
+ }
+
+ ImGui.EndTabItem();
+ }
+
+ }
}