Improve benchmark reporting and add LLM-friendly results

- Add TypeName to TestDataSet for clearer test scenario reporting
- Display serializer options in console and log outputs
- Extend BenchmarkResult with OptionsDescription
- Serializer benchmarks now provide detailed config summaries
- Log files now include test type and serializer options summary
- Generate .LLM Markdown results for LLM consumption and docs
- Reference .LLM results in BINARY_IMPLEMENTATION.md for visibility
This commit is contained in:
Loretta 2026-04-04 11:02:08 +02:00
parent 9150df6982
commit 5ba2684ac4
3 changed files with 101 additions and 5 deletions

View File

@ -225,6 +225,8 @@ internal sealed class TestDataSet
IIdRefPercent = iidRefPercent;
}
public string TypeName => Order.GetType().Name;
/// <summary>
/// Gets display name including IId ref percentage if set.
/// </summary>

View File

@ -82,13 +82,13 @@ public static class Program
System.Console.WriteLine("╔══════════════════════════════════════════════════════════════════════╗");
System.Console.WriteLine("║ COMPREHENSIVE SERIALIZER BENCHMARK SUITE ║");
System.Console.WriteLine("╚══════════════════════════════════════════════════════════════════════╝");
System.Console.WriteLine($"Mode: {mode} | Iterations: {TestIterations} | Warmup: {WarmupIterations}");
System.Console.WriteLine($"Build: {BuildConfiguration} | .NET: {Environment.Version}");
System.Console.WriteLine();
var allResults = new List<BenchmarkResult>();
var testDataSets = BenchmarkTestDataProvider.CreateTestDataSets();
System.Console.WriteLine($"Mode: {mode} | Iterations: {TestIterations} | Warmup: {WarmupIterations}");
System.Console.WriteLine($"Build: {BuildConfiguration} | .NET: {Environment.Version} | Test Type: {testDataSets.FirstOrDefault()?.TypeName ?? "unknown"}");
System.Console.WriteLine();
foreach (var testData in testDataSets)
{
System.Console.WriteLine($"\n{'═'.ToString().PadRight(70, '═')}");
@ -188,6 +188,7 @@ public static class Program
{
TestDataName = testData.DisplayName, // Use DisplayName for IId% info
SerializerName = serializer.Name,
OptionsDescription = serializer.OptionsDescription,
SerializedSize = serializer.SerializedSize
};
@ -271,6 +272,7 @@ public static class Program
{
string Name { get; }
int SerializedSize { get; }
string? OptionsDescription => null;
void Warmup(int iterations);
void Serialize();
void Deserialize();
@ -284,6 +286,7 @@ public static class Program
public string Name { get; }
public int SerializedSize => _serialized.Length;
public string OptionsDescription => $"WireMode={_options.WireMode}, RefHandling={_options.ReferenceHandling}, Interning={_options.UseStringInterning}, Metadata={_options.UseMetadata}, SGen={_options.UseGeneratedCode}, Compression={_options.UseCompression}";
public AcBinaryBenchmark(TestOrder order, AcBinarySerializerOptions options, string name)
{
@ -359,6 +362,7 @@ public static class Program
public string Name { get; }
public int SerializedSize => _serialized.Length;
public string OptionsDescription { get; }
public MessagePackBenchmark(TestOrder order, string name)
{
@ -368,7 +372,10 @@ public static class Program
//_options = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
//_options = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.Lz4Block);
_options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None);
var isContractless = _options.Resolver is ContractlessStandardResolver;
OptionsDescription = $"Mode={( isContractless ? "Contractless" : "ContractBased")}, Compression={_options.Compression}";
_serialized = MessagePackSerializer.Serialize(order, _options);
}
@ -397,6 +404,7 @@ public static class Program
public string Name { get; }
public int SerializedSize => _serialized.Length;
public string OptionsDescription => $"WireMode={_options.WireMode}, RefHandling={_options.ReferenceHandling}, Interning={_options.UseStringInterning}, Metadata={_options.UseMetadata}, SGen={_options.UseGeneratedCode}, Compression={_options.UseCompression}";
public AcBinaryBufferWriterBenchmark(TestOrder order, AcBinarySerializerOptions options, string name)
{
@ -476,6 +484,7 @@ public static class Program
{
public string TestDataName { get; set; } = "";
public string SerializerName { get; set; } = "";
public string? OptionsDescription { get; set; }
public int SerializedSize { get; set; }
public double SerializeTimeMs { get; set; }
public double DeserializeTimeMs { get; set; }
@ -496,6 +505,20 @@ public static class Program
System.Console.WriteLine("║ GROUPED RESULTS BY TEST DATA ║");
System.Console.WriteLine("╚══════════════════════════════════════════════════════════════════════════════════════════════════════╝");
// Print serializer options
var optionsMap = results
.Where(r => r.OptionsDescription != null)
.Select(r => (r.SerializerName, r.OptionsDescription!))
.Distinct()
.ToList();
if (optionsMap.Count > 0)
{
System.Console.WriteLine();
System.Console.WriteLine(" Serializer Options:");
foreach (var (name, opts) in optionsMap)
System.Console.WriteLine($" {name}: {opts}");
}
foreach (var testData in testDataSets)
{
var testResults = results.Where(r => r.TestDataName == testData.DisplayName).OrderBy(r => r.RoundTripTimeMs).ToList();
@ -724,9 +747,24 @@ public static class Program
sb.AppendLine($"║ Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}".PadRight(100) + "║");
sb.AppendLine($"║ Build: {BuildConfiguration}".PadRight(100) + "║");
sb.AppendLine($"║ Iterations: {TestIterations}".PadRight(100) + "║");
sb.AppendLine($"║ Test Type: {testDataSets.FirstOrDefault()?.TypeName ?? "unknown"}".PadRight(100) + "║");
sb.AppendLine("╚══════════════════════════════════════════════════════════════════════════════════════════════════════╝");
sb.AppendLine();
// Serializer options summary
var optionsMap = results
.Where(r => r.OptionsDescription != null)
.Select(r => (r.SerializerName, r.OptionsDescription!))
.Distinct()
.ToList();
if (optionsMap.Count > 0)
{
sb.AppendLine("=== SERIALIZER OPTIONS ===");
foreach (var (name, opts) in optionsMap)
sb.AppendLine($" {name}: {opts}");
sb.AppendLine();
}
// CSV-like data for easy import
sb.AppendLine("=== RAW DATA (CSV) ===");
sb.AppendLine("TestData,Serializer,Size,SerializeMs,DeserializeMs,RoundTripMs");
@ -825,6 +863,61 @@ public static class Program
File.WriteAllText(logFilePath, sb.ToString(), Utf8NoBom);
System.Console.WriteLine($"✓ Results saved to: {logFilePath}");
// Save LLM-optimized results
var llmFilePath = Path.Combine(ResultsDirectory, $"{baseFileName}.LLM");
SaveLlmResults(llmFilePath, results, testDataSets);
}
private static void SaveLlmResults(string filePath, List<BenchmarkResult> results, List<TestDataSet> testDataSets)
{
var sb = new StringBuilder();
var testTypeName = testDataSets.FirstOrDefault()?.TypeName ?? "unknown";
sb.AppendLine($"# AcBinary Benchmark {BuildConfiguration} {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
sb.AppendLine($"Iterations: {TestIterations} | Warmup: {WarmupIterations} | .NET: {Environment.Version} | TestType: {testTypeName}");
// Options summary
var optionsMap = results
.Where(r => r.OptionsDescription != null)
.Select(r => (r.SerializerName, r.OptionsDescription!))
.Distinct()
.ToList();
if (optionsMap.Count > 0)
{
sb.AppendLine();
sb.AppendLine("## Options");
sb.AppendLine();
foreach (var (name, opts) in optionsMap)
sb.AppendLine($"- **{name}**: {opts}");
}
// Flat results table sorted by test data then round-trip
sb.AppendLine();
sb.AppendLine("## Results");
sb.AppendLine();
sb.AppendLine("TestData | Serializer | Size(B) | Ser(ms) | Deser(ms) | RT(ms)");
sb.AppendLine("---|---|---|---|---|---");
foreach (var testData in testDataSets)
{
var testResults = results
.Where(r => r.TestDataName == testData.DisplayName)
.OrderBy(r => r.RoundTripTimeMs)
.ToList();
foreach (var r in testResults)
{
var inv = System.Globalization.CultureInfo.InvariantCulture;
var ser = r.SerializeTimeMs > 0 ? r.SerializeTimeMs.ToString("F2", inv) : "-";
var des = r.DeserializeTimeMs > 0 ? r.DeserializeTimeMs.ToString("F2", inv) : "-";
var rt = r.RoundTripTimeMs > 0 ? r.RoundTripTimeMs.ToString("F2", inv) : "-";
sb.AppendLine($"{r.TestDataName} | {r.SerializerName} | {r.SerializedSize} | {ser} | {des} | {rt}");
}
}
File.WriteAllText(filePath, sb.ToString(), Utf8NoBom);
System.Console.WriteLine($"✓ LLM results saved to: {filePath}");
}
/// <summary>

View File

@ -3,6 +3,7 @@
Low-level technical decisions, memory management, internal structure of `AcBinarySerializer`. For framework developers modifying the serialization pipeline.
> Format spec: `BINARY_FORMAT.md` | Options/presets: `BINARY_OPTIONS.md` | Features: `BINARY_FEATURES.md` | Output writers: `BINARY_WRITERS.md`
> Benchmark results: `../../Test_Benchmark_Results/Benchmark/*.LLM`
## Zero-Allocation Buffer Management