224 lines
12 KiB
C#
224 lines
12 KiB
C#
using AyCode.Core.Benchmarks.Workloads.Scenarios;
|
|
using AyCode.Core.Serializers.Binaries;
|
|
using AyCode.Core.Tests.TestModels;
|
|
|
|
namespace AyCode.Core.Serializers.Console;
|
|
|
|
/// <summary>
|
|
/// Interactive console menu for the benchmark application. Shown when the user runs without CLI args:
|
|
/// top-level layer/mode selection + nested Settings sub-menus (iteration counts, wire mode, charset).
|
|
/// All settings mutate <see cref="Configuration"/> in place; the menu loop returns control to the
|
|
/// caller (<c>Program.Main</c>) once the user picks a benchmark layer or quits.
|
|
/// </summary>
|
|
internal static class Menu
|
|
{
|
|
/// <summary>
|
|
/// Interactive menu shown when no CLI args. Returns the (layer, serializerMode) tuple, or null on Quit.
|
|
/// Loops on settings-changes ([S]) — user is returned to this menu after modifying iteration counts.
|
|
/// </summary>
|
|
internal static (BenchmarkLayer layer, SerializerSelectionMode serializerMode)? ShowInteractiveMenu()
|
|
{
|
|
while (true)
|
|
{
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("╔══════════════════════════════════════════════════════════╗");
|
|
System.Console.WriteLine("║ AcBinary Benchmark Suite ║");
|
|
System.Console.WriteLine("╚══════════════════════════════════════════════════════════╝");
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("Select benchmark layer:");
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine(" [1] Core — daily iteration");
|
|
System.Console.WriteLine(" [2] Comprehensive — release validation");
|
|
System.Console.WriteLine(" [3] Edge cases — refactor verification");
|
|
System.Console.WriteLine(" [A] All layers");
|
|
System.Console.WriteLine(" [F] FastestByte — AcBinary FastMode Byte[] vs MemoryPack Byte[] only (tight optimization loop)");
|
|
System.Console.WriteLine(" [P] AsyncPipe — streaming I/O isolation (only AsyncPipe, all test data)");
|
|
System.Console.WriteLine($" [S] Settings — Iteration / WireMode (current: {Configuration.SelectedWireMode})");
|
|
System.Console.WriteLine(" [Q] Quit");
|
|
System.Console.Write("\nSelection: ");
|
|
|
|
var key = System.Console.ReadKey(intercept: false).KeyChar;
|
|
System.Console.WriteLine();
|
|
|
|
switch (char.ToLower(key))
|
|
{
|
|
case '1': return (BenchmarkLayer.Core, SerializerSelectionMode.Standard);
|
|
case '2': return (BenchmarkLayer.Comprehensive, SerializerSelectionMode.Standard);
|
|
case '3': return (BenchmarkLayer.Edge, SerializerSelectionMode.Standard);
|
|
case 'a': return (BenchmarkLayer.All, SerializerSelectionMode.Standard);
|
|
case 'f': return (BenchmarkLayer.All, SerializerSelectionMode.FastestByte);
|
|
case 'p': return (BenchmarkLayer.All, SerializerSelectionMode.AsyncPipe);
|
|
case 's':
|
|
ShowSettingsMenu();
|
|
continue; // re-display the main menu after settings update
|
|
case 'q': return null;
|
|
default: return (BenchmarkLayer.All, SerializerSelectionMode.Standard);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Settings sub-menu — dispatches to per-area sub-menus (iteration counts, wire mode, charset).
|
|
/// Returns to the caller (which re-displays the main menu) when [B]ack is pressed.
|
|
/// </summary>
|
|
private static void ShowSettingsMenu()
|
|
{
|
|
while (true)
|
|
{
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine("Settings");
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine(" [1] Iteration — Warmup / Iterations / Samples");
|
|
System.Console.WriteLine($" [2] WireMode — current: {Configuration.SelectedWireMode}");
|
|
System.Console.WriteLine($" [3] Charset — current: {Configuration.GetCurrentCharsetName()}");
|
|
System.Console.WriteLine(" [B] Back");
|
|
System.Console.Write("\nSelection: ");
|
|
|
|
var key = System.Console.ReadKey(intercept: false).KeyChar;
|
|
System.Console.WriteLine();
|
|
|
|
switch (char.ToLower(key))
|
|
{
|
|
case '1':
|
|
ShowIterationSettingsMenu();
|
|
break;
|
|
case '2':
|
|
ShowWireModeSettingsMenu();
|
|
break;
|
|
case '3':
|
|
ShowCharsetSettingsMenu();
|
|
break;
|
|
case 'b':
|
|
return;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ShowCharsetSettingsMenu()
|
|
{
|
|
while (true)
|
|
{
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine("Charset settings — long-string suffix profile");
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine($"Current: {Configuration.GetCurrentCharsetName()}");
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine(" [1] Latin1FixAscii — empty suffix; short FixStr-fast-path stress (Latin1 baseline values stay short)");
|
|
System.Console.WriteLine(" [2] Latin1Short — \" árvíztűrő tükörfúrógép\" (~24 char Hungarian mixed)");
|
|
System.Console.WriteLine(" [3] Latin1Long — ~47-char Latin1 mixed (default; exceeds FixStr boundary)");
|
|
System.Console.WriteLine(" [4] CjkBmp — CJK BMP (long 3-byte runs)");
|
|
System.Console.WriteLine(" [5] Cyrillic — Russian Cyrillic (long 2-byte runs)");
|
|
System.Console.WriteLine(" [6] Mixed — Hungarian + CJK + Cyrillic + emoji (full-spectrum + surrogate pairs)");
|
|
System.Console.WriteLine(" [B] Back");
|
|
System.Console.Write("\nSelection: ");
|
|
|
|
var key = System.Console.ReadKey(intercept: false).KeyChar;
|
|
System.Console.WriteLine();
|
|
|
|
switch (char.ToLower(key))
|
|
{
|
|
case '1':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1FixAscii;
|
|
System.Console.WriteLine("✓ Charset set to Latin1FixAscii");
|
|
return;
|
|
case '2':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Short;
|
|
System.Console.WriteLine("✓ Charset set to Latin1Short");
|
|
return;
|
|
case '3':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Long;
|
|
System.Console.WriteLine("✓ Charset set to Latin1Long");
|
|
return;
|
|
case '4':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmp;
|
|
System.Console.WriteLine("✓ Charset set to CjkBmp");
|
|
return;
|
|
case '5':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Cyrillic;
|
|
System.Console.WriteLine("✓ Charset set to Cyrillic");
|
|
return;
|
|
case '6':
|
|
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Mixed;
|
|
System.Console.WriteLine("✓ Charset set to Mixed");
|
|
return;
|
|
case 'b':
|
|
return;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ShowIterationSettingsMenu()
|
|
{
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine("Iteration settings — press Enter to keep current value");
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine();
|
|
|
|
Configuration.WarmupIterations = PromptInt("WarmupIterations", Configuration.WarmupIterations, min: 0);
|
|
Configuration.TestIterations = PromptInt("TestIterations ", Configuration.TestIterations, min: 1);
|
|
Configuration.BenchmarkSamples = PromptInt("BenchmarkSamples", Configuration.BenchmarkSamples, min: 1);
|
|
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine($"✓ Iteration settings updated: Warmup={Configuration.WarmupIterations} | Iterations={Configuration.TestIterations} | Samples={Configuration.BenchmarkSamples}");
|
|
}
|
|
|
|
private static void ShowWireModeSettingsMenu()
|
|
{
|
|
while (true)
|
|
{
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine("WireMode settings");
|
|
System.Console.WriteLine("─────────────────────────────────────────────");
|
|
System.Console.WriteLine($"Current: {Configuration.SelectedWireMode}");
|
|
System.Console.WriteLine(" [1] Compact");
|
|
System.Console.WriteLine(" [2] Fast");
|
|
System.Console.WriteLine(" [B] Back");
|
|
System.Console.Write("\nSelection: ");
|
|
|
|
var key = System.Console.ReadKey(intercept: false).KeyChar;
|
|
System.Console.WriteLine();
|
|
|
|
switch (char.ToLower(key))
|
|
{
|
|
case '1':
|
|
Configuration.SelectedWireMode = WireMode.Compact;
|
|
System.Console.WriteLine("✓ WireMode set to Compact");
|
|
return;
|
|
case '2':
|
|
Configuration.SelectedWireMode = WireMode.Fast;
|
|
System.Console.WriteLine("✓ WireMode set to Fast");
|
|
return;
|
|
case 'b':
|
|
return;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prompts the user for an integer with a default (current value). Returns the current value if
|
|
/// the user presses Enter on empty input or if parsing fails / value is below the minimum.
|
|
/// </summary>
|
|
private static int PromptInt(string name, int currentValue, int min)
|
|
{
|
|
System.Console.Write($" {name} [{currentValue}]: ");
|
|
|
|
var input = System.Console.ReadLine()?.Trim() ?? "";
|
|
if (input.Length == 0) return currentValue;
|
|
|
|
if (int.TryParse(input, out var newValue) && newValue >= min) return newValue;
|
|
|
|
System.Console.WriteLine($" ! Invalid value (need int ≥ {min}) — keeping {currentValue}");
|
|
return currentValue;
|
|
}
|
|
}
|