This project is the BenchmarkDotNet scaffold for FixedMathSharp hot paths.
The runner, alias catalog, deterministic fixture helpers, and first-pass hot-path benchmark classes are in place. The initial suite covers scalar arithmetic, fixed trigonometry, vector operations, quaternion rotations, matrix transforms, and bounds checks.
- .NET 8 SDK
Releaseconfiguration for meaningful measurements
Avoid measuring Debug builds except when diagnosing benchmark setup failures.
Build the benchmark runner first, then execute the compiled DLL through the
configured dotnet host:
dotnet build tests/FixedMathSharp.Benchmarks/FixedMathSharp.Benchmarks.csproj -c Release -f net8.0On Linux/WSL this avoids dotnet run launching a generated apphost that does
not inherit capabilities such as cap_sys_nice. When the dotnet host is
configured for elevated process priority, run the built DLL so BenchmarkDotNet
can use that capability.
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll listdotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll allAliases are derived from benchmark class names. Benchmarks or Benchmark is stripped, and the remaining words are joined with -.
For a class named Vector3dBenchmarks, the selection alias is vector3d:
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll vector3dMultiple aliases can run together:
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll fixed64-arithmetic vector3dArguments after the selection are forwarded to BenchmarkDotNet:
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll all --list flatUse BenchmarkDotNet's short in-process job for quick local smoke runs. This verifies benchmark code compiles and produces plausible output without a full run:
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll all -j Short -iDo not treat short-run numbers as canonical measurements.
Start with hot paths that can be isolated and repeated deterministically:
Fixed64arithmetic, division, square root, and trigonometry.Vector2d,Vector3d, andVector4darithmetic, dot/cross products, normalization, distance, interpolation, and transforms.FixedQuaternioncreation, multiplication, interpolation, and vector rotation.Fixed3x3andFixed4x4creation, multiplication, inversion, and point/vector transforms.- Bounds containment/intersection checks and projection/clamping helpers.
- Serialization roundtrips for standard builds when payload size and allocation behavior matter.
- Diagnostics formatting when repeated display, logging, or editor polling
needs the allocation-free
TryFormatpath.
- Put benchmark classes in the
FixedMathSharp.Benchmarksnamespace. - Prefer one benchmark class per subsystem or scenario group.
- Apply
[MemoryDiagnoser]to benchmark classes unless there is a specific reason not to. - Use deterministic fixtures and fixed seeds. Do not use ambient randomness in measured paths.
- Reset or dispose context between benchmark cases so measurements do not depend on previous cases.
- Capture both throughput and allocation impact when changing hot-path arithmetic, normalization, transforms, bounds dispatch, serialization, or fixture generation.
Keep support helpers specific. Remove copied template helpers when they stop serving a FixedMathSharp benchmark scenario.
Before starting optimization work, capture a baseline:
dotnet tests/FixedMathSharp.Benchmarks/bin/Release/net8.0/FixedMathSharp.Benchmarks.dll all --exporters jsonBenchmarkDotNet writes results to BenchmarkDotNet.Artifacts/results/ by default. Archive the JSON or markdown reports before changing algorithms so regressions can be compared against known results.
Use full Release BenchmarkDotNet artifacts for performance claims. Short
in-process runs are useful for smoke checks, alias validation, and quick
allocation diagnostics, but they are not stable enough for release notes or
regression gates.
When comparing a branch against a baseline:
- Build the benchmark runner in
Release. - Run the selected benchmark group with JSON export before changing runtime code.
- Preserve the baseline artifact outside
BenchmarkDotNet.Artifacts/if it needs to survive cleanup. - Make one focused runtime change.
- Re-run the same benchmark group with the same command, SDK, OS, CPU power mode, and configuration.
- Compare mean/median timing, error range, allocation bytes, GC counts, and benchmark method semantics.
Do not treat a single faster local run as proof. Prefer a repeatable trend, especially for very small methods where noise can be larger than the measured delta.
Use this checklist before turning a benchmark result into an optimization task or release note:
- Scenario: the benchmark represents a real public API path or a documented synthetic stress case.
- Environment: OS, CPU, .NET SDK/runtime, configuration, and BenchmarkDotNet job are recorded.
- Timing: mean, error, and standard deviation are compared against the same baseline command.
- Allocation: allocated bytes and GC counts are explained, including intentional payload allocations such as serialization output.
- Complexity: operation count, loop shape, branch shape, duplicated work, data movement, and algorithmic complexity are considered.
- Determinism: optimized code preserves fixed-point semantics across
ReleaseandReleaseLean. - Correctness: focused tests cover any runtime behavior touched by the optimization.
- Scope: public API changes are avoided unless the measured benefit is large enough to justify the compatibility cost.
- Reporting: release notes include measured deltas and environment, not unsourced claims like "faster" or "zero allocation."
Performance release notes should be proportional and evidence-backed. Include:
- The affected API or scenario.
- The baseline and optimized commands or artifact names.
- The measured timing/allocation delta.
- The environment used for measurement.
- Any compatibility or determinism caveat.
Example:
Improved FixedMath.Sin valid-input hot path by removing eager exception-message
allocation. In a .NET 8 Release BenchmarkDotNet run on <CPU/OS>, the focused
fixed64-arithmetic suite reported 0 B allocated for Sin/Cos/Tan after the
change, with correctness tests passing for FixedMath and FixedTrigonometry.
CI should at minimum compile the benchmark project in Release. The normal
FixedMathSharp.slnx build already includes tests/FixedMathSharp.Benchmarks; use this
direct command when isolating benchmark compilation locally:
dotnet build tests/FixedMathSharp.Benchmarks/FixedMathSharp.Benchmarks.csproj --configuration ReleaseRunning full benchmarks in CI is optional until local variance is understood. When performance gates are introduced, prefer BenchmarkDotNet comparison support or stored baseline artifacts over raw timing thresholds, which are sensitive to runner hardware. A future smoke job should compile benchmarks first and, if it runs benchmarks at all, use a short alias-scoped job that verifies selection and basic execution without claiming a performance delta.