Files
HellionChat/HellionChat/SelfTests/PerformanceBaselineStep.cs
T
JonKazama-Hellion 16557213cd chore: comments, second pass -- the task codes the first pass missed
The first sweep matched a character class that swallowed the digit, so a bare
B1 slipped through while B1-2 was caught. Searching the whole A-Z space instead
of guessing prefixes turned up 130-odd more: B0 through B6, C2, C3, D1, H2, M6,
P7, P8, T2, W2, plus GP-04, KB-01, OD-1, PM-1, PM-3, SEC-01, TR-4, TR-7, UI-11,
UI-12, XC-8 and API-3.

Kept deliberately: 41 B4 01 is a byte signature, "N0" a format string,
#L119-L128 a source anchor, LS4/LS6 are linkshells, and A=FF B=0C G=41 R=C2
explains a colour-channel order. Those look like codes and are not.

Also translated the eight German comments left in the theme files and
ImGuiUtil. Seven of them described what a palette does to which channel, which
is worth reading -- just not in a second language in an otherwise English
codebase.
2026-08-19 22:03:12 +02:00

112 lines
3.7 KiB
C#

using Dalamud.Bindings.ImGui;
using Dalamud.Plugin.SelfTest;
namespace HellionChat.SelfTests;
// Optional metric capture. Accumulates 1000 steady-state frames of ImGui IO
// counters plus the plugin's full-Draw wall-time (Plugin.LastDrawMs, B5-1),
// then writes a single perf-baseline.json into the plugin ConfigDirectory so
// the cycle-notes author can copy the baseline figures without a separate
// profiling harness. The step only records — it never fails on a threshold
// (the budgets are evaluated by a human against the JSON ("optional,
// manual"). It returns Waiting until the sample window fills, mirroring the
// per-frame poll idiom of ThemeSwitchSelfTestStep.
internal sealed class PerformanceBaselineStep : ISelfTestStep
{
// Steady-state window. 1000 frames ≈ 16s at 60fps, long enough to
// average out GC blips without making the manual step tedious.
private const int TargetFrames = 1000;
// Rough draw-call proxy: ImGui emits 6 indices per quad, so vertices/6 is an
// intentional under-count of draw work, not the exact quad count.
private const int VerticesPerQuadProxy = 6;
private readonly Plugin _plugin;
private int _frames;
private ulong _lastFrameCount;
private double _drawMsSum;
private double _drawMsMax;
private long _vertexSum;
private long _vertexMax;
private double _deltaMsSum;
private double _deltaMsMax;
private string? _logPath;
public PerformanceBaselineStep(Plugin plugin)
{
_plugin = plugin;
}
public string Name => "Hellion Chat - Performance baseline capture";
public SelfTestStepResult RunStep()
{
var io = ImGui.GetIO();
// Count each real frame once. Without the FrameCount gate a step that
// is polled more than once per frame would inflate the sample count.
var frameCount = Plugin.Interface.UiBuilder.FrameCount;
if (frameCount != _lastFrameCount)
{
_lastFrameCount = frameCount;
_frames++;
var drawMs = _plugin.LastDrawMs;
_drawMsSum += drawMs;
if (drawMs > _drawMsMax)
_drawMsMax = drawMs;
long vertices = io.MetricsRenderVertices;
_vertexSum += vertices;
if (vertices > _vertexMax)
_vertexMax = vertices;
var deltaMs = io.DeltaTime * 1000f;
_deltaMsSum += deltaMs;
if (deltaMs > _deltaMsMax)
_deltaMsMax = deltaMs;
}
if (_frames < TargetFrames)
{
ImGui.Text(
$"Sampling steady-state… {_frames}/{TargetFrames} frames. "
+ "Keep the chat window visible and idle."
);
return SelfTestStepResult.Waiting;
}
_logPath ??= WriteBaselineLog();
ImGui.Text($"Baseline captured ({TargetFrames} frames). Wrote: {_logPath}");
return SelfTestStepResult.Pass;
}
public void CleanUp()
{
_frames = 0;
_lastFrameCount = 0;
_drawMsSum = 0;
_drawMsMax = 0;
_vertexSum = 0;
_vertexMax = 0;
_deltaMsSum = 0;
_deltaMsMax = 0;
_logPath = null;
}
private string WriteBaselineLog()
{
// Disk write happens here, never in the per-frame hot path.
return PerformanceBaselineLog.Write(
avgDrawMs: _drawMsSum / TargetFrames,
maxDrawMs: _drawMsMax,
avgDrawCallsProxy: _vertexSum / (double)TargetFrames / VerticesPerQuadProxy,
maxDrawCallsProxy: _vertexMax / (double)VerticesPerQuadProxy,
avgDeltaMs: _deltaMsSum / TargetFrames,
maxDeltaMs: _deltaMsMax,
frames: TargetFrames
);
}
}