# LibHFT / llfix fixed-duration capacity sweep on SCAN

Date: 2026-09-29

## Result

The diagnostic single-host loopback campaign probed C++ LibHFT and llfix from
10,000 through 1,000,000 offered messages/s. Under the declared gate (100%
completion, at least 98% of offered rate achieved, and p99 no greater than
100 microseconds), LibHFT's last passing point was **100,000/s** and llfix's was
**10,000/s**.

This is evidence for the recorded fixture, not a universal maximum-throughput
claim. The public chart stops at LibHFT's 100,000/s passing point. Failed probes
from 150,000 through 1,000,000/s remain in the retained campaign for saturation
analysis and are not presented as sustained performance.

## Contract

- Host: `scan`, client and server on loopback.
- CPU affinity: server core 18, client core 19.
- Workload: FIX 4.4 NewOrderSingle to ExecutionReport.
- Per rate and engine: three fresh process pairs.
- Warm-up: 0.1 seconds represented by `rate * 0.1` messages.
- Measurement: 1 second represented by `rate * 1.0` messages.
- Gates: 100% completion, no deficit/overload, achieved rate at least 98% of
  offered rate, p99 at most 100 microseconds, and complete retained raw samples.

## Published window

| Engine | Offered/s | Achieved/s | Completion | p99 us | Gate |
|---|---:|---:|---:|---:|---|
| LibHFT C++ | 10,000 | 9,999.802 | 100% | 18.086 | PASS |
| llfix | 10,000 | 9,928.022 | 100% | 28.311 | PASS |
| LibHFT C++ | 25,000 | 24,999.471 | 100% | 18.045 | PASS |
| llfix | 25,000 | 23,560.265 | 100% | 58.494 | FAIL |
| LibHFT C++ | 50,000 | 49,999.020 | 100% | 18.164 | PASS |
| llfix | 50,000 | 46,286.752 | 100% | 38.019 | FAIL |
| LibHFT C++ | 75,000 | 74,999.476 | 100% | 27.135 | PASS |
| llfix | 75,000 | 54,444.624 | 100% | 41.535 | FAIL |
| LibHFT C++ | 100,000 | 99,995.411 | 100% | 92.786 | PASS |
| llfix | 100,000 | 53,721.461 | 100% | 39.079 | FAIL |

The llfix failures from 25,000/s through 100,000/s are achieved-rate failures;
their latency percentiles are not passing capacity results.

## Evidence status

The retained campaign is
`artifacts/llfix-levelup/scan-20260929-1m-fixed-duration`. It contains the full
1M/s probe ladder, invocation logs, runtime manifests, raw HFTBRW1 samples and
SHA-256 hashes. Promotion is blocked because this was a same-host diagnostic,
the runtime profiles warned, and the LibHFT working tree contained unrelated
uncommitted work.

## Later finding (2026-10-15): two harness defects held llfix back

Two defects in the harness, not in llfix, apply to this campaign's llfix rows; neither is
corrected here.

- **Nagle on the server's ExecutionReports.** llfix 1.0.8's server does not apply
  `disable_nagle` to the sockets it accepts (the reactor's accept path never reads the
  option; only the client connector sets TCP_NODELAY). The adapter asked for the setting
  and did not get it. It now sets TCP_NODELAY on each accepted socket itself.
- **Unpinned local pairs.** In local mode the Stage 5 runner started the server and the
  client without `taskset`, so `--server-core`/`--client-core` had no effect; inside an
  isolated CPU set both processes stayed on one CPU and time-sliced. Local pairs are now
  pinned when the cores are given. On a Xeon Gold 6254 host before that fix, llfix met about half its offered
  rate at a p50 near 1.6 ms; run by hand on two cores it met 96% of 10,000/s at p50 35 us.

Measured on that host after both fixes (loopback, two process pairs per rate, the same gate):
LibHFT C++ passes through 150,000/s (p99 11.5-17.5 us to 100,000/s, 72 us at 150,000/s)
and llfix through 50,000/s (p99 17.3-17.8 us); from 75,000/s llfix fails on achieved rate.
That is a diagnostic, same-host result, as this one is; it is not a promoted row.
