perf(baseline): time full Draw() handler into LastDrawMs field

This commit is contained in:
2026-06-16 19:13:45 +02:00
parent 458df3b4bd
commit 68c4e28495
+63 -37
View File
@@ -166,6 +166,15 @@ public sealed class Plugin : IAsyncDalamudPlugin
// because the tick reads it from a different thread than the writer.
private volatile bool _isDisposing;
// v1.9.0 B5: last full Draw() wall-time in ms, written once per frame at
// the end of the UiBuilder.Draw handler. Covers the GlobalStyleScope push
// and the font push (§7.5 First-Frame-HITCH must include atlas/style
// prologue cost), not just WindowSystem.Draw — measuring the inner call
// alone would drop the prologue and make the figure non-comparable to the
// v1.5.6 baseline. Only accumulated here; the disk write happens in
// PerformanceBaselineStep so the hot path stays allocation-free.
internal double LastDrawMs;
internal int DeferredSaveFrames = -1;
// Cancels the v1.4.8 FTS5 bulk-insert worker on plugin teardown. The
@@ -1012,48 +1021,65 @@ public sealed class Plugin : IAsyncDalamudPlugin
private void Draw()
{
// v1.4.8 B2: pick up external edits of the active custom theme JSON
// without forcing the user to re-click the picker. The disk-stat is
// 1Hz-throttled inside RefreshActiveIfStale, so this is essentially
// free on built-in themes and ~1 stat/second on custom themes.
ThemeRegistry.RefreshActiveIfStale();
using IDisposable _style = Ui.StyleEngine.GlobalStyleScope.Push(
ThemeRegistry.Active,
ThemeRegistry,
Config.WindowOpacity
);
if (Config.HideInLoadingScreens && Condition[ConditionFlag.BetweenAreas])
{
TypingIpc.Update();
// v1.9.0 B5: time the whole handler (style + font prologue included).
// Bail before measuring once teardown has begun — a late Draw tick
// must not touch ThemeRegistry / FontManager after DisposeAsync.
if (_isDisposing)
return;
}
// Hide all plugin windows while the New Game+ menu is open.
if (
Config.HideInNewGamePlusMenu
&& GameFunctions.GameFunctions.IsAddonInteractable(
GameFunctions.GameFunctions.NewGamePlusAddonName
var drawWatch = Stopwatch.StartNew();
try
{
// v1.4.8 B2: pick up external edits of the active custom theme JSON
// without forcing the user to re-click the picker. The disk-stat is
// 1Hz-throttled inside RefreshActiveIfStale, so this is essentially
// free on built-in themes and ~1 stat/second on custom themes.
ThemeRegistry.RefreshActiveIfStale();
using IDisposable _style = Ui.StyleEngine.GlobalStyleScope.Push(
ThemeRegistry.Active,
ThemeRegistry,
Config.WindowOpacity
);
if (Config.HideInLoadingScreens && Condition[ConditionFlag.BetweenAreas])
{
TypingIpc.Update();
return;
}
// Hide all plugin windows while the New Game+ menu is open.
if (
Config.HideInNewGamePlusMenu
&& GameFunctions.GameFunctions.IsAddonInteractable(
GameFunctions.GameFunctions.NewGamePlusAddonName
)
)
)
{
{
TypingIpc.Update();
return;
}
Interface.UiBuilder.DisableUserUiHide = !Config.HideWhenUiHidden;
// RegularFont is nullable only because the live rebuild path
// disposes it before reassigning; both ends of that swap happen on
// this same draw thread, so it cannot be null here.
var useRegularFont = Config.FontsEnabled || Config.UseHellionFont;
using ((useRegularFont ? FontManager.RegularFont! : FontManager.Axis).Push())
WindowSystem.Draw();
TypingIpc.Update();
return;
FileDialogManager.Draw();
}
finally
{
// finally so the early-return frames (loading screen / NG+) record
// their (cheap) time too instead of freezing on the last full frame.
drawWatch.Stop();
LastDrawMs = drawWatch.Elapsed.TotalMilliseconds;
}
Interface.UiBuilder.DisableUserUiHide = !Config.HideWhenUiHidden;
// RegularFont is nullable only because the live rebuild path
// disposes it before reassigning; both ends of that swap happen on
// this same draw thread, so it cannot be null here.
var useRegularFont = Config.FontsEnabled || Config.UseHellionFont;
using ((useRegularFont ? FontManager.RegularFont! : FontManager.Axis).Push())
WindowSystem.Draw();
TypingIpc.Update();
FileDialogManager.Draw();
}
internal void SaveConfig()