AyCode.Core/AyCode.Benchmark/JitDisassemblyBenchmark.cs

60 lines
3.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AyCode.Core.Serializers;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
namespace AyCode.Core.Benchmarks;
/// <summary>
/// Direct JIT-disassembly harness for the AcBinary <b>Large Serialize</b> hot path — the cell where
/// the PGO-driven inline bistability shows up (~120 µs/op fast mode ⇄ ~142 µs/op slow mode, same
/// source, run-to-run).
///
/// <para><b>Not a BenchmarkDotNet benchmark.</b> BDN's <c>DisassemblyDiagnoser</c> produced no output
/// ("No benchmarks were disassembled"); this harness leans on the runtime's own JIT disassembler
/// instead. <see cref="Run"/> builds the workload and exercises the Large Ser FastMode path — when the
/// process is launched with <c>DOTNET_JitDisasm=&lt;pattern&gt;</c> the JIT dumps the x64 assembly of
/// every matching method to stdout as it compiles them.</para>
///
/// <para><b>Run it</b> (via the <c>--jitasm</c> switch). Set:</para>
/// <list type="bullet">
/// <item><c>DOTNET_TieredCompilation=0</c> — each method compiled once, straight to full-opt Tier-1:
/// deterministic codegen, no tiering/PGO lottery (so the disasm is reproducible).</item>
/// <item><c>DOTNET_JitDisasm=&lt;pattern&gt;</c> — e.g. <c>*GeneratedWriter*</c> for the SGen writer
/// hot loop. The un-inlined <c>call</c>s in that loop are the candidates for the PGO-flipped inline
/// site; pinning the right callee with <c>[MethodImpl(AggressiveInlining)]</c> locks in the fast mode.</item>
/// </list>
///
/// <para>The workload mirrors <see cref="AcBinaryVsMemPackBenchmark"/> exactly — Large (5×5×5×10)
/// <see cref="TestOrder_All_False"/> graph, AsciiShort charset, FastMode + Compact wire.</para>
/// </summary>
public sealed class JitDisassemblyBenchmark
{
/// <summary>
/// Builds the Large workload and JITs + exercises the Large Ser FastMode hot path. With
/// <c>DOTNET_JitDisasm</c> set, the JIT emits the matching methods' disassembly to stdout on
/// first compile; the loop guarantees every reachable serializer method is JIT-compiled (and,
/// if tiering is left on, promoted to Tier-1).
/// </summary>
public void Run()
{
// Mirror AcBinaryVsMemPackBenchmark exactly: AsciiShort charset (where the Large-Ser bimodality
// was observed), Large (5×5×5×10) TestOrder_All_False graph, FastMode + Compact wire.
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.AsciiShort;
var allTestData = BenchmarkTestDataProvider_All_False.CreateTestDataSets();
var largeSet = (TestDataSet<TestOrder_All_False>)allTestData.First(t => t.Name.StartsWith("Large"));
var order = largeSet.Order;
var options = AcBinarySerializerOptions.FastMode;
options.WireMode = WireMode.Compact;
Console.WriteLine("=== JIT-DISASM HARNESS: Large Ser FastMode (TestOrder_All_False, AsciiShort) — start ===");
byte[] last = null!;
for (var i = 0; i < 50; i++)
last = AcBinarySerializer.Serialize(order, options);
Console.WriteLine($"=== JIT-DISASM HARNESS: done — 50 Large Ser ops, last payload {last.Length} bytes ===");
}
}