Decisions as a Service
Sign Up Now →Sign Up Now

Decision Runtime results

Measured latency and throughput of runtime 0.3.1 on one machine, three runs per benchmark. Every figure links to the script that produced it and to the raw output of all runs.

Run 2026-10-02Runtime 0.3.1Python 3.11.4

Read these before the numbers

  • Python build. These results measure the current pure-Python runtime. A compiled native runtime is Planned; its results will be published separately when it ships.
  • Not an idle machine. The one-minute load average was 2.7 during the runs, so tail values (p99, max) are noisier than they would be on a quiet host. It was 3.1 to 3.4 during the 0.3.0 runs.
  • One laptop. Use these for order of magnitude and shape. Measure on your own hardware with the published scripts.

Environment#

CPUApple M5 Max, 18 cores (6 performance, 12 efficiency)
Memory48 GB
OSmacOS 26.6.2
SoftwarePython 3.11.4, runtime 0.3.1 (the released wheel, with helixor-constraint-network 1.0.1), pydantic 2.13.5; HTTP: fastapi 0.142.2, starlette 1.7.0, uvicorn 0.54.0, the versions pip installed into a fresh virtual environment
WorkloadFive fixed payloads cycled in order: one clean, one SSN + IP, one card + email, one health record ID, one phone + email. Built-in Community pack, no license file. Single process.

Summary#

Medians of three runs. Metric definitions are on Methodology.

Measurementp50p90p99Throughput
Engine time (latency_us)18.4 µs20.8 µs27.8 µs40,996 evaluations/s (loop)
Call time, evaluate() end to end24.3 µs26.9 µs35.2 µs41,524 calls/s (1 / mean)
Streaming, one push() of 8 characters56.3 µs68.3 µs131.9 µs2 KB stream in 14.4 ms
HTTP round trip, POST /v1/evaluate on loopback427 µs467 µs511 µs2,320 requests/s (one connection, sequential)

Cold start#

StageFresh process (5 runs)
Import helixor_runtime86.4 to 99.6 ms
Construct HelixorEngine()0.37 to 0.51 ms
First evaluate()101.0 to 118.3 µs
Second evaluate()45.5 to 58.0 µs
Import, construct and first evaluate()86.9 to 100.2 ms
Whole process (start, import, construct, two evaluations)0.12 to 0.13 s wall time

Known issue in 0.3.1: cold start at the target, not reliably under it

The target is a cold start under 100 ms. Import, construction and the first evaluation took 86.9 to 100.2 ms, over the target in one of five runs. In a second set of eight runs at a higher load average (4.1 to 4.5) they took 98.2 to 100.4 ms, over the target in three. Import at initialization, not per request.

What changed from 0.3.0#

The 0.3.0 wheel was installed beside 0.3.1 in a second fresh Python 3.11.4 environment with the same dependency versions, and the scripts were run alternating between the two. The raw results have every run.

  • Import is about 30 ms shorter. Side by side, import took 97.7 to 99.9 ms on 0.3.1 and 127.6 to 138.1 ms on 0.3.0. python -X importtime shows why: 0.3.0 imported the sales engine on import helixor_runtime, about 31 to 34 ms of the import. 0.3.1 takes the sales engine out of the runtime, so it is no longer imported, and the license code no longer loads the cryptography library's key-serialization modules. The import loads 281 modules, against 310.
  • The new license search costs nothing measurable. 0.3.1 looks for the license in the explicit path, $HELIXOR_LICENSE_FILE, ./helixor.hxlic and ~/.helixor/helixor.hxlic when you construct the engine. Side by side, construction took 0.41 to 0.45 ms on 0.3.1 and 0.41 to 0.46 ms on 0.3.0.
  • The HTTP round trip did not change with the release. It is 427 µs p50 here against 457 µs in the 0.3.0 run, but the 0.3.0 wheel measured 413 to 424 µs side by side, and 0.3.1 414 to 416 µs. The difference from the 0.3.0 run is the state of the host. The fastapi patch release (0.142.2 here, 0.142.1 in the 0.3.0 run) made no difference either.
  • Engine time, call time and streaming are unchanged within run-to-run noise; side by side the two wheels cannot be told apart.

What the numbers mean#

  • About 25 µs per in-process decision at the median, including license check, receipt hashing and building the result. Budget from this figure, not from latency_us, which is about 6 µs lower because it covers evaluation only.
  • A loopback HTTP hop costs about 18 times the decision. The sidecar pattern adds roughly 0.4 ms; the evaluation inside it is still about 28 µs. Put the runtime in-process when the caller is Python and latency matters. See Performance.
  • Each streaming push costs about three evaluations. The session re-checks its look-ahead buffer on every push, and before it releases text it evaluates the parts on each side of the cut, so that no value is split. Pushing larger fragments means fewer checks.
  • Import time dominates cold start. Import is 86 to 100 ms of a cold start; construction and the first evaluation add well under 1 ms. Most of the import is the runtime's own modules and the validation library (measured with python -X importtime).
  • Warm up once. The first evaluation in a process is about twice as slow as the second, and several times slower than steady state. Run one clean evaluation at startup.

All runs#

Engine time: bench_engine_time.py#

RunEvaluations/sMeanp50p90p99
140,85418.20 µs18.42 µs20.83 µs27.79 µs
240,99618.14 µs18.38 µs20.75 µs28.83 µs
341,18318.00 µs18.25 µs20.54 µs27.67 µs

Call time: bench_evaluate_e2e.py#

Runp50p90p99MaxCalls/s
124.62 µs27.25 µs37.00 µs285.83 µs40,775
224.25 µs26.88 µs35.17 µs85.46 µs41,563
324.33 µs26.83 µs34.62 µs85.58 µs41,524

Streaming: bench_streaming.py#

Runpush p50p90p99Max2 KB stream p50
156.25 µs68.33 µs131.88 µs273.54 µs14.40 ms
256.67 µs70.25 µs134.50 µs296.50 µs14.54 ms
356.12 µs67.88 µs130.75 µs180.62 µs14.34 ms

HTTP: bench_http.py#

Runp50p90p99MaxRequests/sServer engine p50
1427 µs470 µs520 µs611 µs2,31429.0 µs
2423 µs459 µs504 µs580 µs2,35028.1 µs
3427 µs467 µs511 µs665 µs2,32028.0 µs

Cold start: bench_cold_call.py#

RunImportConstructFirst evaluateSecond evaluate
199.56 ms0.51 ms111.8 µs58.0 µs
286.38 ms0.38 ms101.0 µs47.0 µs
386.94 ms0.38 ms101.8 µs49.9 µs
488.52 ms0.37 ms118.3 µs53.5 µs
587.00 ms0.38 ms104.5 µs45.5 µs

Raw results, including the side-by-side runs with 0.3.0: results-2026-10-02.md.

History#

Earlier results, kept as published:

  • results-2026-09-29.md: runtime 0.3.0, Python 3.11.4, fastapi 0.142.1, load average 3.1 to 3.4. Medians: engine time 18.8 µs p50, call time 24.8 µs p50 and 35.5 µs p99 (39,413 to 41,921 calls/s), streaming push 58.8 µs p50, HTTP round trip 457 µs p50, import 111.4 to 128.5 ms. With the web stack of the 0.2.1 runs (fastapi 0.123.0, uvicorn 0.40.0) the same wheel measured 406 to 416 µs HTTP p50.
  • results-2026-09-28.md: runtime 0.2.1, load average 7.5 to 10.5. Medians: engine time 19.6 µs p50, call time 24.9 µs p50 and 48.8 µs p99, streaming push 57.9 µs p50, HTTP round trip 347 µs p50, import 864 to 985 ms.
  • results-2026-09-28-cold-start.md: cold start only, runtime built from source after the lazy-import fix, before the 0.3.0 release. Import 107.0 to 108.6 ms.
  • results-2026-09-27.md: runtime 0.2.0, load average 5.6 to 7.1. Medians: call time 22.3 µs p50, streaming push 19.2 µs p50 (before the 0.2.1 streaming fix), HTTP round trip 339 µs p50, import 684 to 728 ms.

Not measured yet#

  • Multi-process throughput scaling on a server CPU.
  • Payload-length sensitivity (cost against text size and match count).
  • Memory footprint per engine.
  • Concurrent HTTP clients against one service.
  • Linux on x86_64 and aarch64 server hardware.

These are next; they will be added here with their scripts.