Skip to content

execution: reduce interpreter, syscall and runtime overhead - #281

Open
7layermagik wants to merge 22 commits into
7layer/review-performance-corefrom
7layer/execution-performance
Open

7layermagik wants to merge 22 commits into
7layer/review-performance-corefrom
7layer/execution-performance

Conversation

@7layermagik

@7layermagik 7layermagik commented Sep 16, 2026 •

Copy link
Copy Markdown

Reduce CPU work and allocations during transaction execution: speed up the sBPF interpreter, remove SHA-256 and memory-syscall overhead, and accelerate LtHash account updates. Exact timing remains unchanged.

This PR targets 7layer/review-performance-core so the earlier validator-performance changes stay outside its diff. Retarget to alpenglow-dev after those prerequisites merge.

Implementation

  • Interpreter: keep hot operations together, use fixed register storage, pre-resolve internal calls, and reduce metering and memory-translation overhead. Account for the call-target table in program-cache memory usage.
  • SHA-256: decode slice descriptors directly and write the digest without temporary allocations. Include the VM bounds-overflow correction required by differential testing.
  • Memory syscalls: remove temporary copy buffers and accelerate comparison/fill operations. Preserve CU charges, error precedence, zero-length behavior, memcpy overlap rejection, memmove overlap support, and copy-on-write/growing regions.
  • LtHash: use runtime-gated AVX2 with portable and purego fallbacks, preserving 16-bit wrapping and aliased operands.
  • Fix the VASA test call signatures and Noop fixture's compute meter. Retain reusable differential tests and benchmarks; remove the abandoned SHA buffering prototype and investigation narration.

Claude's original commits retain their authorship. ARSH/verifier semantics changes, incremental execution and account prefetch are outside this PR. Timing sampling is deferred because its implementation introduced measurable overhead even in exact mode.

Measurements

Zen 5 / Ryzen 7 9700X, Go 1.26.4, GOMAXPROCS=1, CPU affinity and alternating-order repeated runs on a shared validator host:

Component Before → after
Interpreter: Token-2022 transfer 19.52 → 13.70 µs (1.42×)
Interpreter: arithmetic, 5,000 iterations 167.24 → 94.55 µs (1.77×)
Interpreter: CPI to System Allocate 16.75 → 13.77 µs (1.22×)
SHA syscall in captured hash loop 234.5 → 165.9 ns/hash
Memory syscalls: Token-2022 allocations 4 fewer allocations / 192 fewer bytes per invocation
LtHash MixIn: portable → AVX2 approximately 310 → 15 ns, zero allocations

These are separate component comparisons, not cumulative speedups. Interpreter measurements compare 9db7dcb plus the same harness against its interpreter-patched counterpart 2ed5e533; SHA compares the frozen original syscall with the optimized implementation. Memory/LtHash measurements use staged commits e791b7bb and e4100766.

Whole replay did not establish an additional latency improvement. The later live baseline, f6e3fab1, already includes the interpreter and SHA optimizations. Replaying the same 233 blocks took 34.256 and 33.872 seconds for candidate 60d8e96b; four baseline runs ranged 33.378–34.273 seconds. Candidate mean was 0.82% higher. Shared-host variation and single-core tests do not establish improved multicore contention or voting speed.

Three post-deployment five-minute windows had combined FAST inclusion of 96.00% versus 96.70% before; observed completion-to-local-vote-enqueue p99 was 105.9 versus 111.9 ms. Leaders, workloads and host activity were unmatched, so neither difference establishes causation.

Correctness and reproduction

  • 100,000 generated programs match reference return values, errors, CU usage and memory; pool-reuse checks pass.
  • All 233 replayed Alpenglow blocks have identical normalized slot sets and bank hashes.
  • Affected unit suites, targeted race tests and vet pass. LtHash randomized, wrapping, aliased, unaligned, runtime-fallback and purego checks pass, as do ARM64 compilation and native ARM64 LtHash tests.
  • Legacy BPF-loader fixture failures reproduce on both baseline and candidate; this is not a full sealevel-suite pass.
  • Final cleanup changes only documentation/test code. Targeted SHA/program tests, SHA race tests and benchmark smoke checks pass.

See execution benchmark instructions and SHA benchmark instructions for commands, pinned fixtures and measurement boundaries. Raw run outputs remain outside the merge diff.

The earlier candidate measurements above predate this regrouping. The new base aggregates the separately reviewed prerequisite branches; it is a testing/integration branch, not another merge PR. This PR now also owns boolean CLI/TOML default resolution, retained vote-deque ownership, SBPF v2 opcode/differential coverage, the pooled-heap dirty-bitmap bound, zero-length memcpy handling, and sibling-header write tracking. Claude's authored commits remain intact.

Current regrouping validation: affected SBPF/LtHash tests and focused memory/SHA/sibling/deque/config tests pass, as do build and vet. Broader sealevel fixture selection still hits legacy missing-compute-meter/setup failures; no full sealevel pass is claimed. No new Zen 5 measurement or deployment was performed for this regrouping. The former PR head is preserved on 7layer/archive-execution-before-regroup-20260924.

Review dependencies

One of four grouped reviews: Turbine/production #287 and voting #288 form the integration base for this PR; replay/recovery/streaming #292 builds on this PR. The integration base is not an additional PR. All 22 execution commits are unchanged by range-diff; the rebased execution binary builds.

@7layermagik
7layermagik force-pushed the 7layer/execution-performance branch from faf2771 to 05ca7ae Compare September 16, 2026 05:10
@7layermagik
7layermagik force-pushed the 7layer/execution-performance branch 2 times, most recently from 52a1aad to 05ca7ae Compare September 24, 2026 05:25
@7layermagik
7layermagik changed the base branch from 7layer/review-performance-combined to 7layer/review-performance-foundation September 24, 2026 05:31
@7layermagik
7layermagik force-pushed the 7layer/execution-performance branch from 05ca7ae to 52a1aad Compare September 24, 2026 05:32
7layermagik and others added 22 commits September 24, 2026 00:35
…en transfer)

Consensus-neutral performance changes to pkg/sbpf, validated against the
unmodified interpreter with a 100k-program differential corpus (identical
return values, errors/PCs, CU consumed, meter remaining, memory contents,
input-region state) plus the package's unit tests:

- meter instructions with a local due/budget pair synced around syscalls
  and on exit (Agave's due_insn_count scheme) instead of calling
  ComputeMeter.Consume per instruction
- move cold opcodes to executeCold so Run drops below the compiler's
  "big function" threshold and Consume/Read*/Push/Pop/fast paths inline
- zero only the dirty range of the pooled stack/heap in Finish (page
  bitmap on the fast path, byte range on the translate path) instead of
  256 KiB + HeapMax per execution
- per-window fast-path address translation table (Agave aligned mapping
  layout, branch-free v0 frame gaps, one-entry cache for VASA input regions)
- 16-wide register file (no bounds checks on r[dst]/r[src]), in-place
  call-frame Push/Pop, precomputed internal call targets per Program

pooling_test writes through the VM's translation layer now, since the pool
only re-zeroes memory the VM saw written (all production writes go through
translation).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ctTQDHudYoF3FhmgmvY2y
- perf_bench_test.go: synthetic ALU / load-store / call loops and
  interpreter setup+teardown
- loader/token_perf_bench_test.go: real SPL Token Transfer through the
  loader/verifier/interpreter with sealevel-equivalent syscalls, in the
  aligned and VASA input layouts
- perf_differential_test.go: deterministic random program corpus; run on
  two builds with SBPF_DIFF_OUT=<file> and diff the outputs;
  SBPF_CHECK_POOL_ZERO=1 asserts pooled buffers come back zeroed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ctTQDHudYoF3FhmgmvY2y
…TowerSync)

Measured through ExecutionCtx.ProcessInstruction so instruction-context
push/pop, lamport-sum checks and timing metrics are included; each has a
NoTiming variant (SkipTimingMetrics) to quantify instrumentation cost, plus
a vote-state (de)serialization round trip. NOTE: written without a local
build of pkg/sealevel (sandbox cannot fetch its dependencies); expect to
fix compile errors on first run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ctTQDHudYoF3FhmgmvY2y
…e loops

sol_memcpy_/sol_memmove_ read the source into a fresh heap buffer and wrote
it back; the copy now goes directly between the two translated slices with
Go's memmove-semantics copy (overlap handled, source translated first so
error precedence is unchanged, and a copy-on-write/growth of the
destination region still reads the pre-write bytes because the source slice
keeps the previous backing buffer alive). sol_memcmp_ uses bytes.Equal for
the common equal case and word-skips to the first differing byte otherwise;
sol_memset_ uses clear for zero and a doubling copy for other values. An
SPL Token transfer issues two memcpy and four memcmp calls, so this is a
small, allocation-free win rather than a large one.

Tests: memcmpResult against the previous byte loop on 100k random inputs,
memsetBytes over sizes and values, and VM-level memmove/memcpy overlap,
error-ordering, copy-on-write-region and memcmp/memset checks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ctTQDHudYoF3FhmgmvY2y
LtHash.MixIn/MixOut are 1024-lane uint16 add/subtract loops that run twice
per modified account in the accounts delta hash (once for the old value,
once for the new). The scalar loop costs ~560 ns per call in the sandbox
and roughly 350 ns on Zen 5, so a block with ~10k modified accounts spends
several milliseconds of worker CPU on lane arithmetic alone.

On amd64 with AVX2 the lanes are now mixed with VPADDW/VPSUBW, 16 lanes per
instruction, four vectors per iteration, unaligned loads and stores
(28 ns per call here, 20x). Dispatch is a package variable set from
cpu.X86.HasAVX2 (golang.org/x/sys is already a direct dependency); other
architectures, CPUs without AVX2 and the purego build tag keep the
portable loops, which remain the reference. Equals now compares the two
arrays directly (runtime memequal) instead of a lane loop.

Tests compare the assembly and the dispatched functions against the
portable loops on random lanes including wrap-around values, check that
MixOut inverts MixIn, that aliased operands behave, and that the generic
fallback is selectable; go vet's asmdecl check passes and the package
builds under -tags purego and GOARCH=arm64.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ctTQDHudYoF3FhmgmvY2y
@7layermagik
7layermagik force-pushed the 7layer/execution-performance branch from 52a1aad to a317eb6 Compare September 24, 2026 05:37
@7layermagik 7layermagik changed the title execution: reduce interpreter, syscall and LtHash overhead execution: reduce interpreter, syscall and runtime overhead Sep 24, 2026
@7layermagik
7layermagik changed the base branch from 7layer/review-performance-foundation to 7layer/review-performance-core September 24, 2026 05:37
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.

2 participants