Skip to content

Opteryx: rebuild the entry after the engine refactor, add native-format variant, refresh results - #1416

Open
joocer wants to merge 2 commits into
ClickHouse:mainfrom
joocer:opteryx-refresh
Open

Opteryx: rebuild the entry after the engine refactor, add native-format variant, refresh results#1416
joocer wants to merge 2 commits into
ClickHouse:mainfrom
joocer:opteryx-refresh

Conversation

@joocer

@joocer joocer commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

The previous entry targeted Python 3.11 and no longer ran. Opteryx has changed substantially since: the planning engine is largely as it was, still in Python, while the execution engine has been significantly refactored. It now ships as opteryx-core (previously opteryx), with a different execution API.

  • opteryx/ — rebuilt for opteryx-core on CPython 3.14. install, check and query rewritten; 8 queries adapted to the dialect; renamed to Opteryx (Parquet, partitioned) and tagged C++.
  • opteryx-skene/ — new entry for skene, Opteryx's native format, so it takes the unqualified name (as duckdb does against duckdb-parquet-partitioned). Shares the harness; the load step converts the Parquet corpus, so Load time is that conversion.

Results: 0.9.69, nine machines, three tries per query, 387 results with no nulls. Hot totals run from 25.9 s (skene, c8g.4xlarge) and 38.7 s (Parquet, same box) to 2821 s on t3a.small. The previous 0.26.x runs nulled 17 of 43 on t3a.small, 15 on c6a.large and 12 on c6a.xlarge; all now return numbers. The c8g.* results are the first AArch64 numbers for this entry.

Notes:

  • The 8 query adaptations are syntactic — explicit casts on the EventDate/EventTime comparisons, TRUNC for DATE_TRUNC, b''/r'' regex literals. Both READMEs document them.
  • Historical result files keep "system": "Opteryx"; they were accurate when recorded. c6a.metal and c7a.metal-48xl still appear under it until re-run.
  • Coverage is instances of ≤32 vCPUs — the account is capped at 32 concurrent on-demand vCPUs, so the 192-vCPU metals could not be launched.
  • index.html untouched; the website workflow regenerates it.

joocer added 2 commits August 16, 2026 10:32
…ive-format variant

The previous entry targeted Python 3.11 and no longer ran. Opteryx has
changed substantially since: the planning engine is largely as it was,
still in Python, while the execution engine has been significantly
refactored. It now ships as `opteryx-core` (previously `opteryx`), with a
different execution API.

install: stock CPython 3.14 and opteryx-core. Not the free-threaded
3.14t build -- the free-threaded experiment was abandoned in June 2026
(the parallelism target is native C++ threads under a released GIL) and
opteryx-core stopped publishing cp314t wheels after 0.9.16, so a 3.14t
interpreter falls through to the sdist and tries to build Rust/C++ on
the box. The wheel has no runtime dependencies, so this is a single
binary download. Ends with a version banner so a fallback to a source
build fails loudly there rather than 43 queries later.

check: `version()` is no longer a function -- the version is the system
variable `@@version` -- and the old `python -m opteryx` path caught the
resulting error and still exited 0, a false green that let a broken
install through. Probe `@@version` through the Python API and assert the
shape of the result. This matters because bench_load() calls ./check
unconditionally, after the ~14 GB download.

query: rewritten for the current surface (session.execute_to_morsels);
opteryx.query() / Cursor.arrow() are gone. Times the morsel drain, which
is the execution, and emits the full result as TSV afterwards.

queries.sql: adapt 8 queries to the dialect -- explicit casts on the
EventDate/EventTime comparisons, TRUNC for DATE_TRUNC, and b''/r''
literals in the REGEXP_REPLACE. Syntactic only; the unadapted forms
produce null rows for exactly those 8 rather than wrong numbers.

template.json: rename the system to "Opteryx (Parquet, partitioned)",
following duckdb-parquet-partitioned and chdb-parquet-partitioned, which
frees the unqualified name for the native-format entry. Historical
result files keep "Opteryx": they were accurate when recorded and are
not rewritten. Add the "C++" tag, matching the implementation-language
tag carried by comparable embedded engines.

opteryx-skene/ is that native-format entry. skene is Opteryx's own
columnar format, so it takes the unqualified name, as `duckdb` does
against `duckdb-parquet-partitioned`. install, check, query,
queries.sql, start and stop are shared with the Parquet entry verbatim
-- query needs no change at all, since a skene dataset is addressed by
the same directory resolution and `FROM hits` finds ./hits/*.skene.

What differs is the load. ClickBench distributes Parquet, so the dataset
must be converted before it can be queried, and that conversion is the
load step -- Load time is its wall-clock, as for any entry ingesting
source data into a native store. convert.py is self-contained rather
than reusing the engine repo's dev tooling, which a ClickBench run does
not have; everything it needs (skene, draken, rugo) is in the one wheel.
Conversion runs across processes, which costs layout: row groups do not
span chunk boundaries, so a 12-worker build holds 28 files against 24
for a single worker and measures ~7% slower to query. Row count is
verified per chunk and in total, and a mismatch fails the run.

Written lz4 with read acceleration, the engine's read-first posture.
opteryx-core 0.9.69 on CPython 3.14, three tries per query with the page
cache dropped before each first try, run through the shared driver.

Parquet, eight machines spanning 2 to 16 vCPUs on both architectures:
c6a.large, c6a.xlarge, c6a.2xlarge, c6a.4xlarge, c8g.large, c8g.xlarge,
c8g.2xlarge, t3a.small. skene on c8g.4xlarge.

Every query returns on every machine -- 387 results, no nulls. The
published 0.26.x runs nulled 17 of 43 on t3a.small, 15 on c6a.large and
12 on c6a.xlarge; those all now produce numbers. The smaller instances
are slow rather than failing: the heavy GROUP BYs run out of swap (10 GB
against 2 GB of RAM on t3a.small) using the 16 GB swapfile ClickBench's
cloud-init configures for every system.

The c8g.* machines are the first AArch64 results for this entry, which
0.9.69 made possible by publishing manylinux aarch64 wheels. Measured at
matched sizes, Graviton4 leads the equivalent c6a by 50% at 16 vCPU, 30%
at 8, 25% at 4 and 18% at 2 -- the advantage narrowing as the workload
moves from CPU-bound to memory-bound.

Machines above 32 vCPUs are absent: the account running these is capped
at 32 concurrent on-demand vCPUs, so the 192-vCPU metal instances could
not be launched. Both READMEs say so.
@joocer
joocer requested a deployment to benchmark-approval August 16, 2026 09:33 — with GitHub Actions Waiting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant