test(selftest): add GlobalStyleScope GC-reserve alloc probe
This commit is contained in:
@@ -409,6 +409,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
new SelfTests.HonorificHeaderRenderStep(this),
|
||||
new SelfTests.AboutIntegrationsStatusStep(this),
|
||||
new SelfTests.PerformanceBaselineStep(this),
|
||||
new SelfTests.GlobalStyleScopeAllocStep(this),
|
||||
new SelfTests.MainWindowFocusOpacityStep(this),
|
||||
new SelfTests.MainWindowFlagsStep(this),
|
||||
new SelfTests.SenderNameReformatStep(this),
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.SelfTest;
|
||||
using HellionChat.Ui.StyleEngine;
|
||||
|
||||
namespace HellionChat.SelfTests;
|
||||
|
||||
// GC-reserve probe for the v1.9.0 B4a refactor: GlobalStyleScope.Push runs
|
||||
// once per draw frame, so its StackHandle must allocate nothing. Before the
|
||||
// counter rewrite it boxed 44 ImRaii structs + a List per frame; after, it
|
||||
// holds two ints and pushes straight onto the ImGui stack. This step drives a
|
||||
// real Push()->Dispose() cycle and asserts the per-thread allocation delta is
|
||||
// ~0 (not a non-null-handle check — feedback_hellion_chat_fontmanager_push_trap).
|
||||
// A warm-up cycle pays the one-time JIT/first-touch cost so the measured cycle
|
||||
// reflects steady state, matching the real per-frame hot path.
|
||||
internal sealed class GlobalStyleScopeAllocStep : ISelfTestStep
|
||||
{
|
||||
// Headroom for incidental managed noise (GC bookkeeping, boxing inside
|
||||
// ImGui bindings we do not control). The pre-fix path allocated ~1-2 KB
|
||||
// per cycle (44 boxes + List), so anything under this threshold proves
|
||||
// the StackHandle itself stopped allocating. Tighten only if a future
|
||||
// binding upgrade removes all incidental noise.
|
||||
private const long AllocBudgetBytes = 256;
|
||||
|
||||
private readonly Plugin _plugin;
|
||||
|
||||
public GlobalStyleScopeAllocStep(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
public string Name => "Hellion Chat - GlobalStyleScope GC reserve";
|
||||
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var registry = _plugin.ThemeRegistry;
|
||||
var theme = registry.Active;
|
||||
var opacity = Plugin.Config.WindowOpacity;
|
||||
|
||||
// Warm-up: JIT the Push/Dispose path + first-touch any lazy ImGui
|
||||
// stack growth, so the measured cycle is steady-state only.
|
||||
GlobalStyleScope.Push(theme, registry, opacity).Dispose();
|
||||
|
||||
var before = GC.GetAllocatedBytesForCurrentThread();
|
||||
GlobalStyleScope.Push(theme, registry, opacity).Dispose();
|
||||
var delta = GC.GetAllocatedBytesForCurrentThread() - before;
|
||||
|
||||
if (delta > AllocBudgetBytes)
|
||||
{
|
||||
ImGui.Text(
|
||||
$"GlobalStyleScope.Push allocated {delta} bytes/cycle "
|
||||
+ $"(budget {AllocBudgetBytes}) — StackHandle is not GC-free."
|
||||
);
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
public void CleanUp() { }
|
||||
}
|
||||
Reference in New Issue
Block a user