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.HonorificHeaderRenderStep(this),
|
||||||
new SelfTests.AboutIntegrationsStatusStep(this),
|
new SelfTests.AboutIntegrationsStatusStep(this),
|
||||||
new SelfTests.PerformanceBaselineStep(this),
|
new SelfTests.PerformanceBaselineStep(this),
|
||||||
|
new SelfTests.GlobalStyleScopeAllocStep(this),
|
||||||
new SelfTests.MainWindowFocusOpacityStep(this),
|
new SelfTests.MainWindowFocusOpacityStep(this),
|
||||||
new SelfTests.MainWindowFlagsStep(this),
|
new SelfTests.MainWindowFlagsStep(this),
|
||||||
new SelfTests.SenderNameReformatStep(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