Skip to content

Performance Overview

Docs-site note (2026-06-25, refreshed 2026-07-11): Part of the planned Vexor documentation site (Anza-style). Vexor is testnet-only, version 0.9.x pre-production. This page describes Vexor's performance philosophy and the headline facts measured on the live testnet validator. Every claim below traces to source code or a live cluster measurement; where a number is not established it is described qualitatively rather than invented.


Philosophy

Vexor is a from-scratch, 100% Zig Solana validator. Its performance posture is shaped by one hard constraint and one design opportunity:

  • The hard constraint — byte-faithfulness. A validator's consensus path is unforgiving: a single wrong byte in a bank hash, lt-hash leaf, vote-state record, or sysvar is a fork divergence, not a slow path. So every optimization on or near the consensus path must be bank-hash-neutral — validated byte-for-byte against the canonical Agave reference implementation (currently anchored to the newest testnet release, v4.2.0-beta.0, with Firedancer and Sig used as engineering references) — or it does not ship armed. Speed is never bought with correctness.
  • The opportunity — total control of layout and scheduling. Because the whole consensus client is one Zig codebase with no Rust FFI on any consensus path — and, since the pure-Zig crypto rewrite (-Dpure_zig, the canonical production backend), no Firedancer code linked at runtime either, with ed25519 / BLAKE3 / BN254/alt_bn128 / Poseidon all running through Vexor's own src/vex_crypto/ — Vexor controls its own memory layout, thread topology, and I/O model end-to-end. That is what makes the techniques below possible.

Three principles fall out of this.

Pinned tiles, not a thread soup

Vexor runs as a set of pinned tiles — dedicated threads, each with a declared home core, Firedancer-style — so latency-critical work never floats or gets preempted by background load. Replay, PoH verification, sigverify workers, the vote/tx-send path, gossip, and repair each own specific cores; cold/background work (the VexLedger persist tile, build relief) is fenced onto a separate Core-Complex (CCX) so it cannot evict the hot working set. The layout is declared in one place (src/vex_topo.zig) and verified at deploy time against /proc — Vexor proves the live thread→core map and flags any floater on a consensus core. No mainstream validator self-verifies its pinning like this. See Tuning and the hardware reference for the live table.

Zero-copy on the hot paths

The two firehoses a validator must keep up with — shred ingest from the network and shred serving to repair — are handled without per-packet copies where it counts:

  • Ingest runs over an AF_XDP zero-copy datapath: shreds land from the NIC directly into userspace ring buffers, bypassing the kernel network stack's per-packet copy. (Proven live; see Enhancements.)
  • Shred serving reads straight out of the VexLedger append-segment files — a lookup returns a slice into the mmap'd segment, so repair/replay get a zero-copy view of the shred bytes.

Byte-faithful without sacrificing speed

The consensus-path SIMD wins are precisely the ones that are provably output-identical:

  • BLAKE3 AVX-512 for the accounts lt-hash — the one consensus-path AVX-512 kernel, boot KAT-gated. Runs through Vexor's own pure-Zig BLAKE3 (-Dpure_zig, canonical); an alternate build option still exists to link Firedancer's ballet BLAKE3 instead.
  • @Vector auto-vectorization on znver4: the lt-hash add/sub folds compile to vpaddw/vpsubw, and the accounts-index probe uses a 16-lane @Vector(16, u8) compare. These produce identical results to the scalar path — they are just faster ways to compute the same bytes.

The build is compiled with -Dcpu=znver4, so the binary uses the full Zen-4 ISA (AVX-512, SHA-NI, VAES, VPCLMULQDQ) that the reference EPYC 9374F advertises.

Rewriting a hot path from scratch when a generic implementation becomes the ceiling

Vote instructions are the dominant transaction type on testnet by volume (roughly 98% of all signatures in a typical window), so their execution cost is nearly all of the per-slot SVM-native execution time. Vexor's original vote-instruction path was built on a general-purpose, reference-derived implementation with a generic serialization round-trip and heap allocation on the hot path — correct, but not shaped for this specific, extremely repetitive workload. The vote-program rewrite is a Vexor-authored, clean-room implementation derived from Agave 4.2 semantics, shaped after Firedancer's flat-buffer approach: zero-allocation, fixed-offset, stack-decoded. A Sig-derived component served as the differential test oracle during development — every instruction ran through both paths and was compared byte-for-byte before the rewrite was trusted to run alone — and has been fully removed from the tree (Stage 8, 2026-07-12) now that the rewrite is the sole, unconditional live executor. This is the same philosophy as the interpreter and the blockstore below: match the canonical behavior first, prove it byte-for-byte, then earn the speed.

The interpreter is Firedancer parity — not a gap

Vexor executes sBPF programs with its own clean-room Zig interpreter (src/vex_bpf2/interpreter.zig), byte- and bank-exact versus the canonical Agave reference (v4.2.0-beta.0). This is the correct comparison point: a JIT is an Agave-only feature. Firedancer also interprets sBPF — so "no JIT" is Firedancer parity, not a Vexor deficiency. Calling it a gap would be measuring Vexor against the wrong baseline. A JIT is a profiling-gated future option, not a correctness or parity requirement.


Headline measured facts

These are the facts established on the live testnet validator (single-socket AMD EPYC 9374F, Zen 4, 503 GiB RAM, Mellanox ConnectX-6 Dx, Gen5 NVMe — see Hardware). Numbers are what was measured; no synthetic benchmarks are claimed.

Fact Detail
Voting CURRENT, bank-exact The node votes in-cluster, stays caught up to the tip, and its bank hash matches the cluster every slot under the full performance configuration (parallel exec + FEC-dedup + AF_XDP composing live).
~98.7% of max vote credits Measured against the theoretical 16-credits-per-slot ceiling — on par with the Agave reference node Vexor operates alongside. See Accomplished.
Block production ~97%+ leader slots Sustained across a full epoch, confirmed via public RPC and independent skip-rate monitoring — currently empty blocks; transaction-bearing production exists behind a gate and is not yet enabled.
AF_XDP zero-copy ingest Kernel-bypass RX is live on the Mellanox ConnectX-6 Dx — shreds arrive into userspace rings with no per-packet kernel copy.
Low write-amp ledger (throughput TBD) VexLedger writes shreds with low write amplification (write-once, no compaction) versus an LSM's multi-× churn; a specific throughput/write-amp figure is not yet published here — see Tuning for live telemetry.
Persist off the consensus path (latency TBD) The VexLedger persist tile runs on a dedicated cold core; per-slot persist (serialize meta + append + fsync) never stalls replay or voting. Exact per-window latency is reported live as persist_us(avg/max) — see Tuning.
Accounts mmap'd, not heap-copied (count/timing TBD) The parallel snapshot loader mmaps the full account set in a multi-threaded boot burst rather than copying it into the heap; exact account count and boot-burst duration are not yet published here.
Vote-instruction execution 4.7× faster, live The Vexor-authored vote-program rewrite executes a vote instruction in ~1,898 ns versus ~8,926 ns for the path it replaced, with byte-identical output verified over 990,000+ live vote instructions. It is now the sole, unconditional live executor on testnet; the Sig-derived path that served as its test oracle during development has been fully removed from the tree (Stage 8, 2026-07-12). See Enhancements.

A note on honesty: as of the Stage-A bake migration, most of the performance features in this section are baked on by default at bootbakeProdEnvDefaults() sets proven-safe values for feature envs including VEX_PARALLEL_EXEC and VEXOR_ED25519_FEC_DEDUP only if the operator hasn't already set them (an explicit =0 still disarms them), and they are bank-hash-neutral either way. AF_XDP (VEX_ENABLE_AFXDP) is the one feature here that still requires an explicit operator flag. The Enhancements page states the live-vs-gated status of each one plainly. Nothing here is a projection — if a capability is gated, it says so.


Where to go next

  • Performance Enhancements — an itemized tour of every shipped performance feature, what it does, why it helps, and whether it is live or gated.
  • Tuning — the operator-tunable knobs (env vars), safe defaults, and the telemetry to watch.
  • VexLedger — the append-segment blockstore and its ~1× write-amp story.
  • Hardware — the reference box and the tile→core map.