87 lines
5.2 KiB
C#
87 lines
5.2 KiB
C#
using AyCode.Core.Benchmarks.Workloads.Scenarios;
|
|
|
|
namespace AyCode.Core.Benchmarks.Reporting;
|
|
|
|
/// <summary>
|
|
/// Per-cell benchmark result row. Populated by the benchmark execution loop (Console-side
|
|
/// <c>BenchmarkLoop.RunBenchmarksForTestData</c> / BDN-side <c>BdnSummaryAdapter</c>); consumed by the
|
|
/// output formatters in <c>BenchmarkReportWriter</c> (console table + .log + .LLM file writers).
|
|
/// Pure DTO — no behaviour.
|
|
/// </summary>
|
|
public sealed class BenchmarkResult
|
|
{
|
|
public string TestDataName { get; set; } = "";
|
|
public BenchmarkEngine Engine { get; set; }
|
|
public BenchmarkIoMode IoMode { get; set; }
|
|
public BenchmarkDispatchMode DispatchMode { get; set; }
|
|
public string OptionsPreset { get; set; } = "";
|
|
|
|
/// <summary>
|
|
/// CLR type name of the order graph serialised in this row (e.g. <c>"TestOrder_All_False"</c>,
|
|
/// <c>"TestOrder_All_True"</c>). Captured from <see cref="ISerializerBenchmark.OrderTypeName"/> in
|
|
/// the runner loop; surfaced in the SERIALIZER OPTIONS section of every output
|
|
/// (.log, .LLM, console) so the reader can correlate each preset with its TestOrder variant
|
|
/// without inflating the per-row tables with an extra column.
|
|
/// </summary>
|
|
public string OrderTypeName { get; set; } = "";
|
|
|
|
/// <summary>True if Serialize() captures a full round-trip and Deserialize() is a no-op
|
|
/// (single-use streaming transports like NamedPipe). Excluded from "Fastest Serialize" / "Fastest Deserialize"
|
|
/// winners rankings; still ranked in "Fastest Round-trip". Display-side: Ser µs/op / SerAlloc / Des µs/op / DesAlloc
|
|
/// all show "N/A" since they were never measured separately; RT µs/op / RT Alloc carry the full round-trip values.</summary>
|
|
public bool IsRoundTripOnly { get; set; }
|
|
|
|
/// <summary>Synthesized display name for backwards compatibility / single-string-row scenarios. Includes DispatchMode so SGen and Runtime variants of the same preset don't collide in grouping (e.g. SUMMARY: WINNERS).</summary>
|
|
public string SerializerName => $"{Engine.ToDisplay()} ({IoMode.ToDisplay()}, {OptionsPreset}, {DispatchMode.ToDisplay()})";
|
|
|
|
public string? OptionsDescription { get; set; }
|
|
public int SerializedSize { get; set; }
|
|
public double SerializeTimeMs { get; set; }
|
|
public double DeserializeTimeMs { get; set; }
|
|
|
|
// Per-sample min/max alongside the median (median is the *Time*Ms field above). Surfaces
|
|
// inter-sample range — the visible noise floor for the row. 0 when the operation was skipped
|
|
// (mode != "all"/"ser"/"des") or when a single-sample fast path was used (min == max == median).
|
|
public double SerializeTimeMinMs { get; set; }
|
|
public double SerializeTimeMaxMs { get; set; }
|
|
public double DeserializeTimeMinMs { get; set; }
|
|
public double DeserializeTimeMaxMs { get; set; }
|
|
|
|
// Sample-population stddev (ms). Used by FormatMicrosWithRange to compute CV (stddev/mean)
|
|
// and emit the ⚠️ marker on rows above Configuration.UnstableCVThreshold. 0 in single-sample mode.
|
|
public double SerializeTimeStdDevMs { get; set; }
|
|
public double DeserializeTimeStdDevMs { get; set; }
|
|
|
|
// Per-row adaptive iteration count (post-CalibrateIterations). Each Ser and Des function calibrates
|
|
// independently to land its sample window at ~Configuration.TargetSampleMs; per-op µs is then iter-independent
|
|
// (`SerializeTimeMs / SerializeIterations * 1000`). For round-trip-only rows (NamedPipe etc.),
|
|
// RoundTripIterations carries the calibrated iter count; SerializeIterations and DeserializeIterations
|
|
// stay 0 (Ser and Des are not separately measurable on those rows).
|
|
public int SerializeIterations { get; set; }
|
|
public int DeserializeIterations { get; set; }
|
|
public int RoundTripIterations { get; set; }
|
|
|
|
public long SerializeAllocBytesPerOp { get; set; }
|
|
public long DeserializeAllocBytesPerOp { get; set; }
|
|
public long SetupSerializeAllocBytes { get; set; }
|
|
public long SetupDeserializeAllocBytes { get; set; }
|
|
|
|
/// <summary>Total round-trip time. For in-memory benchmarks: synthesized so that
|
|
/// <c>RoundTripTimeMs / RoundTripIterations</c> yields the correct <c>SerPerOp + DesPerOp</c> µs/op
|
|
/// (necessary because Ser and Des may have different iter counts post-calibration).
|
|
/// For round-trip-only benchmarks (NamedPipe etc.): the directly-measured pipe round-trip time.</summary>
|
|
public double RoundTripTimeMs { get; set; }
|
|
|
|
// Round-trip min/max + stddev — only populated for round-trip-only benchmarks (NamedPipe etc.) where
|
|
// RT is directly measured. For in-memory rows RT = Ser + Des, which has no single-sample
|
|
// distribution; surface Ser/Des range separately instead.
|
|
public double RoundTripTimeMinMs { get; set; }
|
|
public double RoundTripTimeMaxMs { get; set; }
|
|
public double RoundTripTimeStdDevMs { get; set; }
|
|
|
|
/// <summary>Total round-trip allocation per op. For in-memory benchmarks: <c>SerializeAlloc + DeserializeAlloc</c>.
|
|
/// For round-trip-only benchmarks: process-wide allocation measured via <see cref="GC.GetTotalAllocatedBytes"/>
|
|
/// (covers ALL threads — client, server-drain, channel internals — not just the caller).</summary>
|
|
public long RoundTripAllocBytesPerOp { get; set; }
|
|
}
|