Visitar URL original
perf(native): stop using page_allocator for short-lived allocations by GrapeBaBa · Pull Request #10612 · ChainSafe/lodestar · GitHub
Skip to content

perf(native): stop using page_allocator for short-lived allocations - #10612

Merged
GrapeBaBa merged 5 commits into
unstablefrom
GrapeBaBa/zig-zapi-page-allocator-f79aa9de
Nov 13, 2026
Merged

GrapeBaBa merged 5 commits into
unstablefrom
GrapeBaBa/zig-zapi-page-allocator-f79aa9de

Conversation

@GrapeBaBa

@GrapeBaBa GrapeBaBa commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

std.heap.page_allocator maps at least one page per allocation and unmaps it on free, with no reuse. It fits large, long-lived buffers, but a few places in the Zig code use it for small per-call allocations.

Description

  • bindings/napi/pubkeys.zig: keep page_allocator for the long-lived pubkey cache storage, including pkix.load, since pkix.install swaps the loaded storage and its allocator into the live cache. Per-call allocations (path strings, aggregate indices, syncPubkeys pointer arrays) now use c_allocator.
  • PubkeyCache.syncPubkeys takes a scratch allocator for its prepared and batch_errors arrays instead of borrowing the cache allocator.
  • era.getShortEraRoot takes an allocator from the caller instead of hardcoding page_allocator.

The same issue in zapi's shared std.Io.Threaded (which allocates every async/concurrent/group task closure through its gpa) is fixed in ChainSafe/zapi#92. The zapi bump to 4.4.0 will land in a separate PR.

Testing

  • zig build test:state_transition test:era test:tidy
  • pnpm --filter @lodestar/native prepare-mainnet, then binding tests pubkeys, rewards, proposerRewards, attestationRewards

This PR was written primarily by Claude Code.

…allocator

The pubkeys binding used page_allocator for everything, so every per-call
scratch allocation (path strings, aggregate indices, syncPubkeys pointer
arrays) cost an mmap/munmap and at least one page.

Keep page_allocator only for the long-lived cache storage, including
pkix.load, whose result is swapped into the live cache by pkix.install.
Route binding scratch through c_allocator.

PubkeyCache.syncPubkeys now takes a scratch allocator for its prepared
keys and batch error slots instead of borrowing the cache allocator.
The function hardcoded page_allocator. Take the allocator from the caller instead; Writer.writeState already has one.
@GrapeBaBa
GrapeBaBa marked this pull request as ready for review November 12, 2026 14:43
@GrapeBaBa
GrapeBaBa requested a review from a team as a code owner November 12, 2026 14:43
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-12T14:45:08.243256Z 09657a1 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.


/// Populate the cache from the missing suffix of a validator list. Existing
/// entries are trusted as the application's unforkable singleton history.
/// `allocator` backs per-call scratch only; cache storage stays on the cache allocator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we dont call cache allocator at all here so this seems redundant

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 05fc2c9. Small note: syncPubkeys does still grow the map through the cache allocator (ensureTotalCapacityAmortizedUnlocked), but the param already reads clearly without the doc line.

@matthewkeil matthewkeil moved this from In Progress to Awaiting Author in Lodestar Team Coordination Nov 12, 2026
@matthewkeil matthewkeil moved this from Awaiting Author to Review Requested in Lodestar Team Coordination Nov 13, 2026

@spiral-ladder spiral-ladder left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@matthewkeil matthewkeil moved this from Review Requested to Awaiting Author in Lodestar Team Coordination Nov 13, 2026
@GrapeBaBa
GrapeBaBa merged commit dc21d14 into unstable Nov 13, 2026
54 checks passed
@GrapeBaBa
GrapeBaBa deleted the GrapeBaBa/zig-zapi-page-allocator-f79aa9de branch November 13, 2026 07:15
@github-project-automation github-project-automation Bot moved this from Awaiting Author to Done in Lodestar Team Coordination Nov 13, 2026
GrapeBaBa added a commit that referenced this pull request Nov 13, 2026
**Motivation**

zapi 4.4.0 includes ChainSafe/zapi#92: the shared `std.Io.Threaded`
behind `js.io()` now allocates its `async`/`concurrent`/group task
closures with `c_allocator` instead of `page_allocator`, so each task no
longer costs an mmap/munmap pair. Follow-up to #10612.

**Description**

- Pin zapi to the `zapi-v4.4.0` tag commit `0cc6b2c`.
- zapi 4.2.0 renamed `Number.toU64Exact` to `toSafeInteger`
(ChainSafe/zapi#81) with unchanged semantics. Update the binding call
sites.

Other changes since the previous pin (4.1.0) are additive
(`js.scratch()`, exact BigInt conversions). 4.2.0 also requires
`setEnv`/`restoreEnv` to be paired; lodestar does not call them
directly.

**Testing**

- `zig build test:tidy`, bindings build
- `pnpm --filter @lodestar/native prepare-mainnet` and the full binding
test suite: 26 files passed, 1 skipped (506 tests passed, 11 skipped)

> This PR was written primarily by Claude Code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants