Verify semantics before performance

Chapter 7 connects differential tests, generated-code checks, and repeated whole-algorithm measurements.

Chapter 6 selected static primitive backends and runtime complete-algorithm boundaries. First compare results with the scalar reference backend. Then inspect emitted code and measure complete work.

Compare available backends with the scalar reference

alr exec -- gprbuild -p -P tests/tests.gpr
./bin/simd_tests
./bin/family_tests
./bin/conversion_tests
./bin/guard_page_tests

The deterministic suites compare native operations with the scalar backend. They cover fixed edge cases, randomized inputs, every lane position, tail counts, and representative byte algorithms.

Equal results from one example are not sufficient evidence. The scalar backend defines semantics, and executable differential tests check optimized implementations against it.

Inspect both the dot-product caller and primitive bodies

Before you inspect the maintained example's object, build the example with optimization. The path below is for the recorded AArch64 build with AVX2 disabled. For another selected architecture, substitute its object-directory path.

alr exec -- gprbuild -f -p -P examples/examples.gpr -cargs:Ada -O3
objdump -dr obj/examples/aarch64/disabled/dot_product.o

The code-generation script inspects the instantiated Native floating algorithm object. At each precision, it requires two selected partial-load sites and one selected multiplication, addition, reduction, and zero-construction route. It rejects portable, scalar, and runtime routes.

Static composition removes runtime backend selection. GNAT can retain selected primitive calls in the complete-array loop, so benchmark the complete operation rather than inferring its cost from primitive disassembly.

The maintained dot-product benchmark has no recorded performance claim yet.

Run it on the target host and preserve its environment and diagnostics before drawing a crossover conclusion.

Build and run the byte-count benchmark crate

cd benchmarks
alr build --release
FLYOLOGY_BENCH_OUTPUT=terminal alr run --skip-build simd_benchmark
FLYOLOGY_BENCH_OUTPUT=terminal alr run --skip-build dot_product_benchmark

Alire detects an AArch64 or x86-64 host. For a scalar-only measurement, rebuild with -XFLYOLOGY_SIMD_ARCH=scalar.

Both benchmarks compare ordinary Ada with matching semantics, the scalar reference composition, static native composition, and runtime dispatch. The dot-product program measures binary32 and binary64 inputs on both sides of their vector boundaries and at 4,096 and 1,048,576 elements.

Use repeated and balanced measurements

The program calls Flyology_Bench.Compare_Many. It warms each candidate for 250 ms. It then calibrates iteration counts so each candidate receives equal measurement time.

The run collects 75 samples during three seconds of measurement per comparison. It rotates candidates equally through each execution position.

The report keeps raw samples and calculates bootstrap confidence intervals. It shows timing effects associated with candidate position and correlation between adjacent samples. It does not remove outliers automatically or subtract estimated timer cost.

A checksum makes each result observable. The report includes the compiler, build switches, selected architecture, and selected backend.

Keep the byte-count observation within its environment

On 2026-08-10, an Apple Mac15,9 AArch64 host used GNAT FSF 16.1.0. Library objects used -O2 -ftree-vectorize. Benchmark code used -O3.

BytesOrdinary AdaScalar referenceStatic NEONRuntime
167.07 ns14.20 ns5.86 ns7.25 ns
4,0961,349.29 ns3,130.04 ns661.40 ns665.77 ns
1,048,576336,895 ns799,979 ns167,006 ns166,945 ns

The values are medians from that run. Static NEON had the lowest median at 16 and 4,096 bytes. Runtime and static NEON had nearly equal medians at 1,048,576 bytes.

Measure small-set scans at short lengths

The focused benchmark compares Algorithms.Runtime.Find_First_Of with an ordinary Ada loop over a precomputed 256-entry membership table. It uses a four-byte set and measures no-match and last-match inputs.

cd benchmarks
alr build --release
FLYOLOGY_BENCH_OUTPUT=terminal alr run --skip-build class_scan_benchmark

On 2026-08-14, the ordinary Ada table loop won below 32 bytes on the recorded Apple Mac15,9 AArch64 host. Static NEON first clearly won at 32 bytes for no-match input and at 48 bytes for last-match input. Runtime NEON first clearly won at 48 bytes in both scenarios.

The dated journal entry records the full environment, method, selected medians, downloadable summary data, tail effect, and limits.

Check required instruction classes

# AArch64 host
./scripts/check_codegen.py aarch64

# x86-64 baseline host
./scripts/check_codegen.py x86_64 disabled

The PEP 723 script uses uv to provide its pinned regular-expression engine. It checks primitive, floating-array, and whole-byte-algorithm objects. It requires the applicable vector load, multiplication, addition, byte comparison, and mask extraction or reduction instruction classes.

The script also verifies baseline isolation and rejects selected unresolved primitive calls from the native complete-algorithm objects. It matches instruction classes instead of complete disassembly text.

Check build equivalence before interpretation

An earlier large-buffer result favored the ordinary loop because imported library code lacked optimization. The benchmark unit used release optimization. Verbose compiler commands exposed the mismatch.

Do not generalize the recorded byte-count table to another host or to the dot product. Repeat the applicable measurement, keep diagnostics, and inspect generated code. The flyology_bench method guide explains the statistical procedure.