AyCode.Core/AyCode.Core.Serializers.Con.../README.md

90 lines
6.4 KiB
Markdown
Raw Permalink 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.

# AyCode.Core.Serializers.Console
Interactive console runner for the serializer benchmark suite. Targets .NET 9.
> **Companion**: shares its workload + reporting infrastructure with the BDN runner in [`AyCode.Benchmark/`](../AyCode.Benchmark/README.md) via `<ProjectReference>`. See that project's README for the full dual-runner architecture.
## Role
This is the **fast-iteration** half of the benchmark stack — a custom adaptive measure engine optimized for short turnaround (~1-3 min full run) during micro-optimization loops. The BDN half lives in `AyCode.Benchmark` and produces statistically tighter numbers (~5-15 min full run) for before-commit validation. Both runners emit the **same** `.log` / `.LLM` / `.output` triplet to `Test_Benchmark_Results/Benchmark/` — Console prefixes with `Console.`, BDN with `Bdn.`.
## Compared serializers
- **AcBinary** — multiple options presets: `FastMode` (Compact wire, no ref handling, no interning), `Default` (with ref handling + interning), plus SGen / Runtime dispatch variants and Compact / Fast wire modes.
- **MemoryPack** — SOTA baseline, wire-mode-aligned with AcBinary for apples-to-apples encoding comparison (UTF-8 ↔ Compact, UTF-16 ↔ Fast).
- **MessagePack** — JIT-only (AOT incompatible due to dynamic resolver).
- **System.Text.Json** — reference comparison (commented out in `CreateSerializers` by default).
## Key files
- [`Program.cs`](Program.cs) — entry point. Parses CLI args (`Core` / `Comprehensive` / `Edge` / per-cell / op-mode / serializer-set) or falls into interactive `Menu`.
- [`Menu.cs`](Menu.cs) — interactive layer/serializer-set selection + nested settings (iteration counts, wire mode, charset).
- [`BenchmarkLoop.cs`](BenchmarkLoop.cs) — custom adaptive measure engine. CPU 0 affinity pin + High priority for stabilization, JIT pre-warmup, phase-isolated Ser/Des warmup→measure with `GC.Collect` at every boundary, 10-sample median + pilot discard, adaptive iter calibration to ~250ms/cell wall-clock, dedicated allocation-only sample.
- [`Configuration.cs`](Configuration.cs) — Console-side state (`SelectedWireMode`, `WarmupIterations`, `BenchmarkSamples`, `TargetSampleMs`, charset selection, `BuildConfiguration` const from `#if DEBUG/RELEASE/AYCODE_NATIVEAOT`).
Workload + reporting types — `ISerializerBenchmark`, `BenchmarkResult`, `BenchmarkOptions`, `BenchmarkEnums`, `BenchmarkReportWriter`, `ReportingContext`, the 12 concrete `*Benchmark<T>` classes (`AcBinaryBenchmark`, `MemoryPackBenchmark`, `AcBinaryBufferWriterBenchmark`, ...), `RoundTripValidator` — live in [`AyCode.Benchmark/Workloads/Scenarios/`](../AyCode.Benchmark/Workloads/Scenarios/) and [`AyCode.Benchmark/Reporting/`](../AyCode.Benchmark/Reporting/).
## Test data
5 cells, provided by `AyCode.Core.Tests.TestModels.BenchmarkTestDataProvider*`:
- **Small** (2×2×2×2)
- **Medium** (3×3×3×4)
- **Large** (5×5×5×10)
- **Repeated Strings** (10 items, string-deduplication stress)
- **Deep Nested** (2×4×4×8, depth stress)
20% IId reference rate by default. Two graph variants (`TestOrder_All_False` / `_All_True`) are built per cell — AcBinary's option preset picks which variant gets fed to it (`UsesAllFalseVariant` rule in `BenchmarkLoop`).
## Charset profiles (Menu → Settings → Charset)
Controls the `BenchmarkTestDataProvider.LongStringSuffix` — the string-tail appended to property values. Influences string-marker selection on the wire (FixStrAscii vs StringSmall / Medium / Big / StringAscii), interning hit rates, and UTF-8 encode cost.
**Consistent length across all charsets** (UTF-16 char count): every `*Short` = 40 char, every `*Long` = 280 char (= Short × 7). Isolates the workload variable to UTF-8 byte content per charset (1-byte ASCII vs 2-byte Latin1 / Cyrillic vs 3-byte CJK vs mixed) — wire-size and encode/decode cost differences are pure charset effects, not length effects.
| Profile | UTF-16 char | UTF-8 byte (approx) | Tier |
|---|---|---|---|
| `Latin1FixAscii` | 0 | 0 | FixStrAscii / FixStr-equivalent (baseline-only) |
| `AsciiShort` | 40 | 40 | StringAscii (167) |
| `AsciiLong` | 280 | 280 | StringAscii (167) |
| `Latin1Short` | 40 | ~72 | StringSmall (91) |
| `Latin1Long` (**default**) | 280 | ~504 | StringMedium (94) |
| `CjkBmpShort` | 40 | ~104 | StringSmall |
| `CjkBmpLong` | 280 | ~728 | StringMedium |
| `CyrillicShort` | 40 | ~72 | StringSmall |
| `CyrillicLong` | 280 | ~504 | StringMedium |
| `MixedShort` | 40 | ~88 | StringSmall |
| `MixedLong` | 280 | ~616 | StringMedium |
## CLI
```
dotnet run -c Release --project AyCode.Core.Serializers.Console -- [arg]
```
| Arg | Result |
|---|---|
| _(no args)_ | Interactive menu — pick layer (Core / Comprehensive / Edge / Small / Medium / Large / Repeated / Deep / All) × serializer-set (Standard / FastestByte ["F"] / AsyncPipe ["P"]). |
| `Core` / `Comprehensive` / `Edge` / `Small` / `Medium` / `Large` / `Repeated` / `Deep` / `All` | Run that layer at `Standard` serializer-set, `All` op-mode. |
| `FastestByte` / `AsyncPipe` / `Standard` | Run that serializer-set, `All` layer, `All` op-mode. |
| `Serialize` / `Deserialize` / `All` | Run that op-mode, `All` layer, `Standard` serializer-set. |
| `quick` | Single-sample fast mode (Debug-equivalent — very loose numbers, smoke-test only). |
Output: `Test_Benchmark_Results/Benchmark/Console.FullBenchmark_<Build>_<timestamp>.{log,LLM,output}`.
## Dependencies
| Dependency | Purpose |
|---|---|
| `AyCode.Core` (ProjectReference) | AcBinary serializer |
| `AyCode.Core.Tests` (ProjectReference) | Test data factory + test models |
| `AyCode.Benchmark` (ProjectReference) | Shared workload + reporting (`ISerializerBenchmark`, `BenchmarkResult`, `BenchmarkReportWriter`, `ReportingContext`, the 12 concrete benchmark classes) |
| `MemoryPack` | Comparison target (also via Workloads) |
| `MessagePack` | Comparison target |
| `Newtonsoft.Json` | Comparison target (currently disabled) |
## Build & publish notes
- `<StartupObject>AyCode.Core.Serializers.Console.Program</StartupObject>` in the csproj explicitly disambiguates the entry point — necessary because this Exe references another Exe (`AyCode.Benchmark`), and the build would otherwise complain about multiple `Main` methods.
- AOT publish (`dotnet publish -c Release`) is configured via `'$(_IsPublishing)' == 'true'` PropertyGroup. The Benchmark project's BDN-stack (BenchmarkDotNet, Iced disassembler, MongoDB.Bson) is pulled in transitively — accepted tradeoff for the unified workload sharing.