Captured 2026-07-30T22:32:21+00:00 by python benchmark/run_benchmark.py.
- Container: 2 vCPU, 7.8 GB RAM, Linux-6.18.5-x86_64-with-glibc2.39
- Python 3.11.15, DuckDB 1.5.5, numpy 2.4.4, pandas 3.0.2
- Local DuckDB file on the container filesystem. No network, no warehouse.
- Fit is measured once per dataset; check is measured over 15 repeats; suppression over 15 repeats.
- The benchmark container is shared with other builds and variance was not controlled for. Treat these as order of magnitude, not as a regression gate.
| Scale | Datasets | History days | Arrival events | Fit wall (s) | Fit events/s | Fit p50/p95/p99 per dataset (ms) | Check p50/p95/p99 (ms) |
|---|---|---|---|---|---|---|---|
| small | 15 | 60 | 5,040 | 0.65 | 7,753.1 | 21.124 / 137.311 / 150.603 | 34.146 / 62.55 / 70.674 |
| medium | 50 | 240 | 67,200 | 2.798 | 24,012.9 | 25.309 / 236.914 / 257.882 | 134.336 / 170.611 / 173.97 |
| large | 150 | 480 | 403,200 | 12.355 | 32,634.9 | 31.438 / 298.214 / 459.354 | 421.263 / 460.007 / 460.405 |
512 datasets, all of them late, arranged in the given number of layers.
| Depth | Nodes | Edges | Incidents | Suppressed | Suppression % | p50 (ms) | p99 (ms) |
|---|---|---|---|---|---|---|---|
| 2 | 512 | 511 | 256 | 256 | 50.0 | 4.131 | 6.484 |
| 4 | 512 | 765 | 128 | 384 | 75.0 | 4.173 | 10.018 |
| 8 | 512 | 889 | 64 | 448 | 87.5 | 5.734 | 6.426 |
| 16 | 512 | 945 | 32 | 480 | 93.8 | 9.809 | 12.322 |
| 32 | 512 | 961 | 16 | 496 | 96.9 | 15.677 | 20.558 |
| 64 | 512 | 945 | 8 | 504 | 98.4 | 16.673 | 23.064 |
Fit is the expensive half and it scales with total arrival events, not dataset count: 403,200 events took 12.355s (32,634.9 events/s), and the p99 per dataset (459.354 ms) is set by the hourly datasets, which carry twenty four times the history of a daily one and populate up to 96 calendar cells each. That is why fitting is a nightly batch job. Check is unaffected by history length because it reads cached models and one recent slice of arrivals: p99 stayed at 460.405 ms at the largest scale. Lineage suppression is the one place where a pathological shape hurts: cost grows with depth because ancestor and descendant walks get longer, and at depth 64 over 512 all-late datasets it reached 23.064 ms p99 against 6.484 ms at depth 2. Real warehouse lineage is rarely deeper than about ten layers, so this is headroom rather than a problem, but a 64 layer DAG with every node late is where it would start to be felt.