Skip to content

perf(l1): add BOLT post-link optimization setup#5981

Open
Oppen wants to merge 13 commits into
mainfrom
perf/bolt-optimization-setup
Open

perf(l1): add BOLT post-link optimization setup#5981
Oppen wants to merge 13 commits into
mainfrom
perf/bolt-optimization-setup

Conversation

@Oppen

@Oppen Oppen commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Motivation

BOLT (Binary Optimization and Layout Tool) is an LLVM post-link optimizer that rearranges binary code layout based on runtime profiling data. It improves performance by placing hot code paths contiguously in memory, reducing instruction cache (I-cache) misses and branch mispredictions. This is particularly beneficial for Ethereum execution clients where hot paths include:

  • EVM opcode dispatch
  • Keccak hashing (trie operations)
  • RLP encoding/decoding
  • State trie merkelization
  • Database read/write operations

Description

This PR adds the build configuration, Makefile targets, and documentation needed to use BOLT optimization on Linux x86-64 production builds. The entire workflow is automated via make bolt-full.

Changes

Build configuration:

  • Cargo.toml: Added release-bolt profile (inherits release, adds debug = 1 for symbols, uses lto = "fat" for BOLT compatibility) and release-pgo-bolt profile
  • .cargo/bolt.toml (new): Isolated BOLT-specific rustflags (--emit-relocs, -Wl,-q, -Cforce-frame-pointers=yes, -Cllvm-args=-hot-cold-split=false) loaded only via cargo build --config .cargo/bolt.toml — this ensures BOLT flags never affect regular builds
  • Makefile: Added targets for the full BOLT workflow (see table below)

Makefile targets:

Target Description
make bolt-full Full automated workflow: build → instrument → profile → optimize → verify
make bolt-bench Benchmark baseline vs BOLT-optimized (3 runs each)
make build-bolt Build BOLT-compatible binary with fat LTO and relocations
make bolt-instrument Create instrumented binary for profiling
make bolt-profile Run instrumented binary with benchmark fixture to collect profiles
make bolt-optimize Apply BOLT optimization using collected profiles
make bolt-verify Check that optimized binary has BOLT markers
make bolt-perf2bolt Convert perf.data to BOLT format (alternative to instrumentation)
make bolt-clean Remove all BOLT artifacts and profiles

Prerequisite validation (bolt-check) runs automatically before build-bolt, verifying x86_64 Linux, llvm-bolt installed, and Git LFS fixture files present.

BOLT compatibility fixes:

  • crates/vm/backends/levm/mod.rs: Renamed warm_blockpreheat_block — BOLT's split-function regex matches .warm inside Rust's legacy-mangled ::warm_block (which becomes ..warm_block..), causing "parent function not found" errors during BOLT analysis
  • crates/blockchain/blockchain.rs: Updated call site to use preheat_block
  • crates/common/crypto/kzg.rs: Extracted KZG warmup closure into a standalone function pointer (do_kzg_warmup) — closures in std::thread::spawn produce complex drop_in_place specialization symbols that BOLT can't analyze. Using Builder::new().name("kzg-warmup").spawn(do_kzg_warmup) preserves the thread name while generating simpler symbols

Documentation:

  • docs/developers/bolt-optimization.md (new): Comprehensive guide with example output for every step, troubleshooting, and the Rust symbol naming pitfalls

Why fat LTO?

Thin LTO can create cross-module function fragments (.lto_priv.* suffixes) that BOLT 19 can't match to parent functions. Fat LTO produces a single compilation unit with contiguous function bodies, eliminating this issue. Build time increases slightly (~50s) but BOLT compatibility is guaranteed.

Why disable hot-cold splitting?

LLVM's HotColdSplitting pass creates .cold function fragments for rarely-executed paths (e.g., drop_in_place specializations). BOLT 19's relocation mode can't match these fragments to their parent functions. The -Cllvm-args=-hot-cold-split=false flag in .cargo/bolt.toml prevents this.

Why rename warm_block to preheat_block?

BOLT's split-function detection uses a regex that matches .warm and .cold anywhere in ELF symbol names. Rust's legacy mangling scheme converts :: to .., so ::warm_block becomes ..warm_block.. in the symbol table — which contains .warm as a substring. This triggered BOLT's split-function regex for all 7 rayon-generated symbols involving warm_block. Renaming to preheat_block eliminated all 7 false matches (reducing split-symbol warnings from 21 to 14, with the remaining 14 being jemalloc .cold symbols that BOLT handles gracefully).

Testing

Tested end-to-end on ethrex-office-3 (Debian Trixie, x86_64, 128-core AMD EPYC):

Environment

  • BOLT version: BOLT 19 (bolt-19 package, Debian Trixie)
  • Rust: 1.90.0-nightly
  • Build time: ~2m 20s (fat LTO, release-bolt profile)

BOLT Workflow Verification

  1. Build: make build-bolt — compiled successfully with fat LTO and BOLT flags
  2. Instrument: make bolt-instrument — processed 25,271 functions, 403,378 branch counters, 790,788 total counters
  3. Profile: make bolt-profile — imported 1,110 ERC20 blocks (~1.5M transactions), collected 15MB of profile data
  4. Optimize: make bolt-optimize — 4,504 functions (17.6%) had non-empty profiles, 63.3% of profiled functions had layout modified
  5. Verify: make bolt-verify — confirmed BOLT markers present
  6. Benchmark: make bolt-bench — results below

BOLT Optimization Statistics (dynostats)

Metric Before After Change
Taken forward branches 4.52B 0.72B -84.0%
Taken conditional branches 7.67B 3.79B -50.6%
Total taken branches 9.95B 4.62B -53.6%
Unconditional branches 2.28B 0.83B -63.8%
Executed instructions 1117.6B 1116.0B -0.1%
ICF folded functions 360 64.3KB saved

Benchmark Results

Workload: Import 1,110 blocks containing ~1.5M ERC20 transfer transactions (2.4-2.9 Ggas/s throughput), using perf-ci.json genesis.

Binary Run 1 Run 2 Run 3 Run 4 Run 5 Run 6 Avg (2-6)
Baseline (release-bolt) 18,153 17,732 17,823 17,722 17,646 17,608 17,706 ms
BOLT-optimized 17,620 17,534 17,504 17,428 17,409 17,452 17,465 ms

Improvement: ~1.4% (241 ms faster on average, excluding warmup run 1).

The improvement is modest because:

  1. The block import benchmark is partially I/O-bound (RocksDB writes)
  2. BOLT primarily improves I-cache locality, which matters more for large working sets (live node with networking, mempool, and consensus running concurrently)
  3. The profile was collected from a single import run; a production profile from a running node would capture more diverse hot paths

Key Findings During Testing

  1. Rust symbol mangling + BOLT is fragile: BOLT's split-function regex matches .warm and .cold substrings anywhere in mangled symbol names. This means Rust function names containing warm or cold (e.g., warm_block, cold_start) will trigger false positives. The fix is to rename such functions.

  2. Closures in thread::spawn cause BOLT errors: Complex closures produce deeply nested drop_in_place specialization symbols that BOLT can't analyze in relocation mode. Using function pointers instead produces simpler symbols.

  3. Fat LTO is required for BOLT compatibility: Thin LTO creates .lto_priv fragments that BOLT 19 can't resolve. Fat LTO increases build time but produces a single compilation unit.

  4. Profile quality matters: BOLT with a snap-sync profile showed 0% improvement on block import. BOLT with a block-import profile showed 1.4% improvement. For production use, profile with the actual production workload.

  5. libbolt_rt_instr.a location: On Debian Trixie with bolt-19, the library is at /usr/lib/llvm-19/lib/libbolt_rt_instr.a but BOLT looks for it at /usr/local/lib/libbolt_rt_instr.a. A symlink is needed: sudo ln -sf /usr/lib/llvm-19/lib/libbolt_rt_instr.a /usr/local/lib/libbolt_rt_instr.a

How to Test

# Install BOLT tools (Debian/Ubuntu)
sudo apt install bolt-19 libbolt-19-dev
sudo ln -sf /usr/bin/llvm-bolt-19 /usr/local/bin/llvm-bolt
sudo ln -sf /usr/bin/perf2bolt-19 /usr/local/bin/perf2bolt
sudo ln -sf /usr/bin/merge-fdata-19 /usr/local/bin/merge-fdata
sudo ln -sf /usr/lib/llvm-19/lib/libbolt_rt_instr.a /usr/local/lib/libbolt_rt_instr.a

# Fetch LFS fixtures (l2-1k-erc20.rlp is in Git LFS)
git lfs pull

# Full automated workflow: build → instrument → profile → optimize → verify
make bolt-full

# Benchmark
make bolt-bench

See docs/developers/bolt-optimization.md for detailed step-by-step instructions
with example output for every step.

Checklist

  • Cargo.toml profiles added (release-bolt with fat LTO)
  • BOLT flags isolated in .cargo/bolt.toml
  • Makefile targets added (bolt-full, bolt-bench, bolt-profile, etc.)
  • Prerequisite validation (bolt-check)
  • BOLT compatibility fixes (preheat_block rename, kzg function pointer)
  • Documentation with example output (docs/developers/bolt-optimization.md)
  • Tested on Linux x86-64 with BOLT 19
  • Benchmarked: ~1.4% improvement on block import (1,110 blocks, ~1.5M txs)

@github-actions github-actions Bot added L1 Ethereum client performance Block execution throughput and performance in general labels Jan 21, 2026
@Oppen Oppen force-pushed the perf/bolt-optimization-setup branch from 6043adc to 5f86afd Compare January 26, 2026 15:03
@greptile-apps

greptile-apps Bot commented Jan 29, 2026

Copy link
Copy Markdown

Greptile Overview

Greptile Summary

This PR adds LLVM BOLT (Binary Optimization and Layout Tool) post-link optimization infrastructure to ethrex. BOLT can improve binary performance by 2-15% through profile-guided code layout optimization without source code changes.

Key Changes

  • Build configuration (Cargo.toml): Added release-bolt and release-pgo-bolt profiles with minimal debug symbols (debug=1) needed for BOLT analysis
  • Linker flags (.cargo/config.toml): Added --emit-relocs, -Wl,-q, and frame pointers to preserve relocation info for post-link optimization
  • Makefile targets: Comprehensive BOLT workflow with build-bolt, bolt-instrument, bolt-optimize, and cleanup targets
  • Code refactoring: Renamed functions containing "warm" to "preheat" to avoid BOLT's false positive split-function detection (affects warm_blockpreheat_block in blockchain.rs and levm/mod.rs, plus KZG warmup refactoring)
  • Documentation: Extensive 293-line guide covering installation, usage, troubleshooting, and PGO+BOLT combination

Issues Found

  • ARM64 configuration contradiction: .cargo/config.toml adds BOLT flags to aarch64-unknown-linux-gnu despite documentation stating ARM64 "currently fails during BOLT emission phase" with .Ltmp symbol errors
  • Global flag application: BOLT linker flags applied to all x86_64 Linux builds regardless of profile, potentially increasing binary size for non-BOLT builds
  • Missing error handling: KZG warmup thread spawn failures are silently ignored

Testing Status

PR is marked as draft with testing incomplete. The configuration needs validation on Linux x86-64 with full BOLT toolchain (LLVM 19+) and performance benchmarking.

Confidence Score: 3/5

  • This PR is safe to merge for experimental x86_64 Linux use, but requires ARM64 configuration fix and testing validation
  • Score reflects that this is a draft PR with untested configuration and a critical ARM64 config contradiction. The x86_64 implementation appears sound with well-documented workflows and proper function renaming to avoid BOLT issues. However, applying BOLT flags to ARM64 builds despite known incompatibility could cause build failures. Since this is infrastructure for optional optimization (not affecting default builds), the risk is contained.
  • Pay close attention to .cargo/config.toml (ARM64 configuration must be fixed before merging)

Important Files Changed

Filename Overview
.cargo/config.toml Adds BOLT compatibility linker flags for x86_64 and ARM64, but ARM64 config contradicts known BOLT incompatibility
Makefile Adds comprehensive BOLT workflow targets with instrumentation, profiling, and optimization steps
crates/common/crypto/kzg.rs Refactors KZG warmup function to avoid .warm in symbol names, addresses BOLT detection issue

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant Make as Makefile
    participant Cargo as Cargo Build
    participant BOLT as LLVM BOLT
    participant Binary as ethrex Binary

    Note over Dev,Binary: BOLT Optimization Workflow

    Dev->>Make: make build-bolt
    Make->>Cargo: cargo build --profile release-bolt<br/>with CXXFLAGS
    Note over Cargo: Applies linker flags:<br/>--emit-relocs, -Wl,-q<br/>force-frame-pointers
    Cargo->>Binary: target/release-bolt/ethrex<br/>(with relocations)

    Dev->>Make: make bolt-instrument
    Make->>BOLT: llvm-bolt -instrument
    BOLT->>Binary: ethrex-instrumented<br/>(instrumented binary)

    Dev->>Binary: Run ./ethrex-instrumented<br/>with workload
    Binary->>Binary: Collect profile data
    Binary-->>Make: /tmp/bolt-profiles/prof.*.fdata

    Dev->>Make: make bolt-optimize
    Make->>BOLT: llvm-bolt with profile data<br/>-reorder-blocks=ext-tsp<br/>-reorder-functions=cdsort<br/>-split-functions
    BOLT->>Binary: ethrex-bolt-optimized<br/>(optimized binary)

    Dev->>Binary: Deploy optimized binary
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment thread .cargo/config.toml Outdated
Comment on lines 22 to 28
[target.aarch64-unknown-linux-gnu]
rustflags = [
# BOLT compatibility flags - preserves relocation info for post-link optimization
"-Clink-arg=-Wl,--emit-relocs",
"-Clink-arg=-Wl,-q",
"-Cforce-frame-pointers=yes", # Better profiling accuracy
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ARM64 BOLT flags conflict with documented limitations. Line 10 notes ARM64 "currently fails during BOLT emission phase" and Makefile line 24 states "ARM64: Fails with 'Undefined temporary symbol .Ltmp0'", yet these flags are still applied to aarch64-unknown-linux-gnu builds.

Suggested change
[target.aarch64-unknown-linux-gnu]
rustflags = [
# BOLT compatibility flags - preserves relocation info for post-link optimization
"-Clink-arg=-Wl,--emit-relocs",
"-Clink-arg=-Wl,-q",
"-Cforce-frame-pointers=yes", # Better profiling accuracy
]
# [target.aarch64-unknown-linux-gnu]
# rustflags = [
# # BOLT compatibility flags - preserves relocation info for post-link optimization
# # DISABLED: ARM64 currently fails during BOLT emission phase (LLVM bug with .Ltmp symbols)
# "-Clink-arg=-Wl,--emit-relocs",
# "-Clink-arg=-Wl,-q",
# "-Cforce-frame-pointers=yes", # Better profiling accuracy
# ]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .cargo/config.toml
Line: 22:28

Comment:
ARM64 BOLT flags conflict with documented limitations. Line 10 notes ARM64 "currently fails during BOLT emission phase" and Makefile line 24 states "ARM64: Fails with 'Undefined temporary symbol .Ltmp0'", yet these flags are still applied to `aarch64-unknown-linux-gnu` builds.

```suggestion
# [target.aarch64-unknown-linux-gnu]
# rustflags = [
#     # BOLT compatibility flags - preserves relocation info for post-link optimization
#     # DISABLED: ARM64 currently fails during BOLT emission phase (LLVM bug with .Ltmp symbols)
#     "-Clink-arg=-Wl,--emit-relocs",
#     "-Clink-arg=-Wl,-q",
#     "-Cforce-frame-pointers=yes",  # Better profiling accuracy
# ]
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread crates/common/crypto/kzg.rs Outdated
.spawn(|| {
std::hint::black_box(c_kzg::ethereum_kzg_settings(KZG_PRECOMPUTE));
});
std::thread::spawn(do_kzg_warmup);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing error handling - spawned thread error is silently ignored. If do_kzg_warmup panics or the spawn fails, it won't be logged or reported.

Consider adding basic error handling:

std::thread::spawn(do_kzg_warmup).ok();

or logging spawn failures.

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/common/crypto/kzg.rs
Line: 29:29

Comment:
Missing error handling - spawned thread error is silently ignored. If `do_kzg_warmup` panics or the spawn fails, it won't be logged or reported.

Consider adding basic error handling:
```rust
std::thread::spawn(do_kzg_warmup).ok();
```
or logging spawn failures.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread .cargo/config.toml Outdated
Comment on lines +17 to +19
"-Clink-arg=-Wl,--emit-relocs",
"-Clink-arg=-Wl,-q",
"-Cforce-frame-pointers=yes", # Better profiling accuracy

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

BOLT flags applied globally to all x86_64 Linux builds. This adds --emit-relocs to all builds regardless of profile, increasing binary size even for debug builds.

Consider: Are these flags needed for non-BOLT profiles? Document how to conditionally apply them only for release-bolt profile builds if needed.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: .cargo/config.toml
Line: 17:19

Comment:
BOLT flags applied globally to all x86_64 Linux builds. This adds `--emit-relocs` to all builds regardless of profile, increasing binary size even for debug builds.

Consider: Are these flags needed for non-BOLT profiles? Document how to conditionally apply them only for `release-bolt` profile builds if needed.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Oppen and others added 3 commits February 6, 2026 16:36
Add build configuration and Makefile targets for LLVM BOLT optimization,
which can improve binary performance by 2-15% through better code layout
based on runtime profiling.

Changes:
- Add release-bolt and release-pgo-bolt profiles to Cargo.toml
- Add --emit-relocs linker flags to .cargo/config.toml for BOLT compatibility
- Add Makefile targets: build-bolt, bolt-instrument, bolt-optimize, bolt-clean
- Add cargo-pgo workflow targets: pgo-bolt-build, pgo-bolt-optimize, pgo-full-*

Usage requires LLVM 16+ with BOLT tools on Linux x86-64.
…nges

Move BOLT linker flags (--emit-relocs, -Wl,-q, frame pointers) from the
global .cargo/config.toml into a dedicated .cargo/bolt.toml loaded only
by `make build-bolt` via --config. This prevents BOLT flags from affecting
normal dev/release/test builds (larger binaries, extra register used).

Also:
- Remove [target.aarch64-unknown-linux-gnu] section (BOLT unsupported on ARM64)
- Revert warm_block -> preheat_block rename (BOLT's .warm detection matches
  LLVM-generated suffixes, not Rust function names in mangled symbols)
- Restore kzg.rs thread name ("kzg-warmup") lost by the original refactor
- Add bolt-perf2bolt and bolt-verify to .PHONY
- Fix docs to use actual ethrex CLI flags and reference bolt.toml
- Trim Makefile comment block (details now in docs/developers/bolt-optimization.md)
@ilitteri ilitteri force-pushed the perf/bolt-optimization-setup branch from 9e26076 to de34876 Compare February 6, 2026 19:39
BOLT 19 fails with "parent function not found" when analyzing the
drop_in_place specialization for the closure inside spawn_unchecked.
Using a function pointer instead of an inline closure produces a simpler
symbol that BOLT can analyze without hitting this error.

The thread name "kzg-warmup" is preserved via Builder::new().name().
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Lines of code report

Total lines added: 2
Total lines removed: 0
Total lines changed: 2

Detailed view
+------------------------------------+-------+------+
| File                               | Lines | Diff |
+------------------------------------+-------+------+
| ethrex/crates/common/crypto/kzg.rs | 251   | +2   |
+------------------------------------+-------+------+

BOLT 19 fails with "parent function not found" when it encounters
.cold fragments of drop_in_place specializations for complex Rust
closure types (e.g., rayon iterators). Disable the hot-cold split
pass via -Cllvm-args=-hot-cold-split=false in the BOLT config.

BOLT itself will handle hot/cold splitting during its optimization
phase using the runtime profile data, which is more effective since
it's based on actual execution patterns rather than static heuristics.
Thin LTO creates cross-module function fragments that BOLT 19 can't
match to their parent functions. Complex monomorphized symbols
(e.g., rayon parallel iterators) end up as disjoint address ranges
that BOLT interprets as orphaned split fragments.

Fat LTO produces a single compilation unit with contiguous function
bodies, avoiding this issue entirely. The additional compile time is
acceptable since BOLT builds are infrequent (only for production
optimization workflows).
BOLT 19's split-function detection regex matches '.warm' anywhere in
mangled symbol names. Rust's legacy mangling turns '::warm_block' into
'..warm_block', which contains '.warm' as a substring. This causes BOLT
to misidentify drop_in_place specializations for rayon closures inside
warm_block as orphaned split-function fragments, producing a hard error.

Confirmed by testing on ethrex-office-3: the original name causes
"BOLT-ERROR: parent function not found" during both instrumentation
and perf2bolt conversion.
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

Benchmark Block Execution Results Comparison Against Main

Command Mean [s] Min [s] Max [s] Relative
base 64.966 ± 0.354 64.598 65.885 1.00
head 65.089 ± 0.228 64.704 65.369 1.00 ± 0.01

- Fix libbolt_rt_instr.a symlink path (/usr/local/lib/, not /usr/lib/)
- Add symlink instructions for llvm-bolt/perf2bolt/merge-fdata binaries
- Add ICF and use-gnu-stack flags to bolt-optimize Makefile target
- Document SIGINT requirement for instrumented binary profile flushing
- Add detailed troubleshooting for Rust symbol mangling + BOLT conflicts
- Add profile quality warning (snap-sync profile = 0% gain on block exec)
- Add measured benchmark results (1.4% on 1,110-block ERC20 import)
- Document hot-cold-split and fat LTO in implementation notes
- Add Rust source constraints section (function naming, closure patterns)
…ands

The Quick Start now walks through the full BOLT workflow using ethrex's
actual fixture files (l2-1k-erc20.rlp + perf-ci.json), including exact
profiling, optimization, and benchmarking commands. Also adds a table
of available benchmark fixtures and replaces the generic hyperfine
snippet with the real benchmark loop used during testing.
An agent (or developer) can now run the entire BOLT workflow with:

  make bolt-full   # build → instrument → profile → optimize → verify
  make bolt-bench  # 3-run benchmark comparison

New targets:
- bolt-check: validates prerequisites (x86_64, Linux, llvm-bolt, LFS fixtures)
- bolt-profile: runs instrumented binary with l2-1k-erc20.rlp benchmark
- bolt-full: chains instrument → profile → optimize → verify
- bolt-bench: 3 runs each of baseline vs BOLT-optimized

Also adds BOLT_GENESIS and BOLT_BLOCKS variables so custom fixtures can
be used via: make bolt-full BOLT_BLOCKS=path/to/blocks.rlp
Each step now shows what success looks like (actual output from testing),
what warnings are safe to ignore, and what errors mean with how to fix
them. An agent or developer can now compare their terminal output against
the examples to know if the workflow is working correctly.
@ilitteri ilitteri marked this pull request as ready for review February 6, 2026 22:16
Copilot AI review requested due to automatic review settings February 6, 2026 22:16
@ethrex-project-sync ethrex-project-sync Bot moved this to In Review in ethrex_l1 Feb 6, 2026
@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

🤖 Kimi Code Review

Security Review

No security vulnerabilities found in this PR. The changes are limited to build tooling, optimization profiles, and documentation.

Bug Review

No logic bugs found in the changes. The code changes are minimal and focused on BOLT compatibility:

  1. Function rename (warm_blockpreheat_block) - This is intentional to avoid BOLT's split-function detection regex
  2. Thread spawn changes - Using named function pointers instead of closures to simplify symbols for BOLT analysis

Performance Review

No significant performance issues found. The changes are actually performance-oriented:

  • The BOLT optimization workflow can provide 2-15% performance improvements
  • The function rename and thread spawn changes are specifically designed to enable BOLT optimization without affecting runtime performance
  • The new build profiles (release-bolt, release-pgo-bolt) are additive and don't affect existing release builds

Minor Observations

  1. Line 6 in .cargo/config.toml - Added an extra newline at the end, which is harmless
  2. Makefile targets - The new BOLT-related targets are well-documented and follow the existing pattern

Automated review by Kimi (Moonshot AI)

@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

🤖 Codex Code Review

I found no security vulnerabilities, bugs, or significant performance issues in the PR diff.


Automated review by OpenAI Codex

@github-actions

github-actions Bot commented Feb 6, 2026

Copy link
Copy Markdown

🤖 Claude Code Review

Based on my review of this PR, here is my security, bug, and performance analysis:


PR #5981 Review: BOLT Post-Link Optimization Setup

Summary

This PR adds LLVM BOLT optimization infrastructure for Linux x86-64 builds. Overall, the implementation is well-designed and low-risk. The changes are primarily build configuration, documentation, and minor refactoring for BOLT compatibility.


Issues Found

🟡 Medium: Unhandled Thread Spawn Error in KZG Warmup

File: crates/common/crypto/kzg.rs:31-33

let _ = std::thread::Builder::new()
    .name("kzg-warmup".into())
    .spawn(do_kzg_warmup);

Issue: The thread spawn result is explicitly ignored with let _ =. If thread creation fails (e.g., out of resources, system limits), the KZG trusted setup won't load, but the code will silently continue. This could cause performance degradation or panics on first KZG operation.

Recommendation:

if let Err(e) = std::thread::Builder::new()
    .name("kzg-warmup".into())
    .spawn(do_kzg_warmup)
{
    // Log the error but don't panic - KZG will still work, just with first-call overhead
    eprintln!("Warning: Failed to spawn KZG warmup thread: {}", e);
}

Or at minimum:

let _ = std::thread::Builder::new()
    .name("kzg-warmup".into())
    .spawn(do_kzg_warmup)
    .inspect_err(|e| eprintln!("Warning: KZG warmup thread spawn failed: {}", e));

🟢 Low: Temporary Directory Cleanup Race Condition

File: Makefile:109,115,128,137,143

Issue: Multiple targets use /tmp/bolt-data and /tmp/bolt-bench-db which are cleaned up with rm -rf without checking if they're in use by another process. If a user runs make bolt-bench while another user/process is using the same temp directory, data corruption or test failures could occur.

Recommendation: Use unique temp directories with mktemp -d or add a process-specific suffix (e.g., /tmp/bolt-data-$$).


🟢 Low: Shell Wildcard Expansion Without Quotes

File: Makefile:63-64

merge-fdata $(BOLT_PROFILE_DIR)/prof.* > $(BOLT_PROFILE_DIR)/merged.fdata

Issue: If prof.* doesn't match any files, the shell will pass the literal string prof.* to merge-fdata. While this is handled by the ls check on line 63, it's still a potential source of confusion.

Recommendation: The existing ls $(BOLT_PROFILE_DIR)/prof.* 1>/dev/null 2>&1 check on line 63 already handles this, so this is mostly a style concern. Consider adding quotes for consistency, though it's not strictly necessary here.


Non-Issues (False Alarms)

✅ BOLT Profile Directory in /tmp

Using /tmp/bolt-profiles is acceptable for build artifacts. These are ephemeral profiling data, not sensitive user data. The paths are configurable via BOLT_PROFILE_DIR ?= /tmp/bolt-profiles.

✅ rm -rf Usage

The rm -rf commands target well-defined build artifact directories and temporary databases. There's no user input injection risk since all paths are controlled by Makefile variables.

✅ Debug Symbols in Release Build

The debug = 1 setting in release-bolt profile is intentional for BOLT's needs and is isolated to the BOLT-specific profile. Normal release builds are unaffected.

✅ Function Rename (warm_block → preheat_block)

This is purely a workaround for BOLT's regex limitations and has no functional impact. The rename is correctly applied in both definition and call site.


Security Assessment

No Critical or High Severity Issues Found

  • ✅ No command injection vectors (all Makefile commands use controlled variables)
  • ✅ No arbitrary code execution risks
  • ✅ No privilege escalation concerns
  • ✅ Build flags are properly isolated to BOLT-specific profile
  • ✅ No sensitive data exposure

Performance Notes

Expected Impact

  • Build time: +~50s for fat LTO (documented)
  • Runtime: +1-2% improvement (measured at 1.4% on test workload)
  • Binary size: Slightly larger due to debug symbols and relocations (BOLT-only builds)

No Performance Regressions Expected

The BOLT flags are isolated to .cargo/bolt.toml and only loaded explicitly. Normal builds via cargo build --release are completely unaffected.


Conclusion

Approval Status:Approve with minor recommendations

This PR is well-implemented and low-risk. The only actionable issue is the unhandled thread spawn error in the KZG warmup code, which should be logged rather than silently ignored. The temp directory collision risk is minor but could be addressed for robustness.

The code is well-documented, the BOLT workflow is properly isolated from normal builds, and the testing appears thorough.


Automated review by Claude (Anthropic)

@greptile-apps

greptile-apps Bot commented Feb 6, 2026

Copy link
Copy Markdown

Greptile Overview

Greptile Summary

Added comprehensive BOLT (Binary Optimization and Layout Tool) post-link optimization setup for Linux x86_64 production builds. BOLT rearranges binary code layout based on runtime profiling to reduce instruction cache misses and improve branch prediction.

Key changes:

  • Added release-bolt profile in Cargo.toml with fat LTO (thin LTO creates fragments incompatible with BOLT) and debug symbols for BOLT analysis
  • Created .cargo/bolt.toml with BOLT-specific rustflags (--emit-relocs, frame pointers, disabled hot-cold splitting) loaded only via --config flag to avoid affecting regular builds
  • Implemented full BOLT workflow in Makefile: bolt-full automates build → instrument → profile → optimize → verify, with bolt-bench for performance comparison
  • Renamed warm_block to preheat_block in crates/vm/backends/levm/mod.rs because BOLT's split-function regex incorrectly matches .warm inside Rust's mangled symbol ..warm_block..
  • Extracted KZG warmup closure into do_kzg_warmup function pointer in crates/common/crypto/kzg.rs to generate simpler symbols that BOLT can analyze
  • Added 432-line comprehensive documentation with step-by-step examples, troubleshooting, and performance validation

Benchmark results: ~1.4% improvement on block import (1,110 blocks, ~1.5M transactions) with significant branch prediction improvements (84% reduction in taken forward branches). BOLT workflow has been end-to-end tested on Debian Trixie x86_64 with BOLT 19.

Critical issue found: release-pgo-bolt profile missing lto = "fat" setting required for BOLT compatibility.

Confidence Score: 4/5

  • Safe to merge after fixing the missing fat LTO setting in release-pgo-bolt profile
  • Score reflects excellent implementation quality with comprehensive testing and documentation, but one critical configuration issue prevents the release-pgo-bolt profile from working correctly with BOLT. The core BOLT functionality is properly implemented and thoroughly tested.
  • Pay attention to Cargo.toml - the release-pgo-bolt profile needs lto = "fat" added to work correctly with BOLT

Important Files Changed

Filename Overview
.cargo/bolt.toml New file with BOLT-specific rustflags for x86_64 Linux, properly isolated from regular builds
Cargo.toml Added release-bolt profile with fat LTO and release-pgo-bolt profile, but pgo-bolt profile missing lto configuration
Makefile Comprehensive BOLT workflow targets with prerequisite validation, automated profiling, and benchmarking
crates/vm/backends/levm/mod.rs Renamed warm_block to preheat_block to avoid BOLT false-positive split-function detection
docs/developers/bolt-optimization.md Comprehensive documentation with step-by-step examples, troubleshooting, and performance validation guidance

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant Make as Makefile
    participant Cargo as Cargo Build
    participant BOLT as llvm-bolt
    participant Binary as ethrex Binary
    
    Dev->>Make: make bolt-full
    Make->>Make: bolt-check (validate prereqs)
    
    rect rgb(200, 220, 255)
        Note over Make,Cargo: Step 1: Build
        Make->>Cargo: build --profile release-bolt --config .cargo/bolt.toml
        Cargo->>Cargo: Apply fat LTO + BOLT rustflags
        Cargo->>Binary: target/release-bolt/ethrex (with relocations)
    end
    
    rect rgb(255, 220, 200)
        Note over Make,BOLT: Step 2: Instrument
        Make->>BOLT: llvm-bolt --instrument
        BOLT->>Binary: ethrex-instrumented (with counters)
    end
    
    rect rgb(220, 255, 200)
        Note over Make,Binary: Step 3: Profile
        Make->>Binary: Run ethrex-instrumented with fixture
        Binary->>Binary: Execute workload & collect profiles
        Binary->>Make: /tmp/bolt-profiles/prof.*.fdata
    end
    
    rect rgb(255, 255, 200)
        Note over Make,BOLT: Step 4: Optimize
        Make->>BOLT: llvm-bolt with profile data
        BOLT->>BOLT: Reorder blocks & functions
        BOLT->>Binary: ethrex-bolt-optimized (optimized layout)
    end
    
    rect rgb(220, 220, 255)
        Note over Make,Binary: Step 5: Verify & Bench
        Make->>Binary: readelf -S (check .note.bolt_info)
        Make->>Binary: Run baseline vs optimized benchmarks
        Binary->>Dev: Performance comparison results
    end
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread Cargo.toml
Comment on lines +64 to +66
[profile.release-pgo-bolt]
inherits = "release"
debug = 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

release-pgo-bolt profile missing lto setting. According to line 428 in docs/developers/bolt-optimization.md, fat LTO is required for BOLT compatibility because "thin LTO creates .lto_priv fragments incompatible with BOLT". The release-bolt profile (line 61) correctly sets lto = "fat", but release-pgo-bolt doesn't specify this.

Suggested change
[profile.release-pgo-bolt]
inherits = "release"
debug = 1
[profile.release-pgo-bolt]
inherits = "release"
debug = 1
lto = "fat"
Prompt To Fix With AI
This is a comment left during a code review.
Path: Cargo.toml
Line: 64:66

Comment:
`release-pgo-bolt` profile missing `lto` setting. According to line 428 in `docs/developers/bolt-optimization.md`, fat LTO is required for BOLT compatibility because "thin LTO creates `.lto_priv` fragments incompatible with BOLT". The `release-bolt` profile (line 61) correctly sets `lto = "fat"`, but `release-pgo-bolt` doesn't specify this.

```suggestion
[profile.release-pgo-bolt]
inherits = "release"
debug = 1
lto = "fat"
```

How can I resolve this? If you propose a fix, please make it concise.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an automated LLVM BOLT post-link optimization workflow for Linux x86_64 production builds, including build profiles/config, Makefile automation, and documentation, plus a couple of Rust symbol-compatibility adjustments needed for BOLT analysis.

Changes:

  • Add BOLT-oriented Cargo profiles and an isolated .cargo/bolt.toml config for BOLT-only rustflags.
  • Add Makefile targets to run the full BOLT workflow (build → instrument → profile → optimize → verify) and benchmarking/cleanup helpers.
  • Add BOLT documentation and make small Rust source changes to avoid BOLT split-function/symbol-analysis pitfalls (warm_block rename, KZG warmup thread closure → function pointer).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
docs/developers/bolt-optimization.md New end-to-end guide for running BOLT (and PGO+BOLT) with troubleshooting and example outputs.
crates/vm/backends/levm/mod.rs Rename warm_blockpreheat_block and document why (BOLT symbol regex interaction).
crates/blockchain/blockchain.rs Update callsite to renamed LEVM::preheat_block.
crates/common/crypto/kzg.rs Replace thread::spawn closure with function pointer to simplify symbols for BOLT.
Makefile Add bolt-* and pgo-* targets implementing the BOLT workflow, plus prerequisite checks.
Cargo.toml Add release-bolt and release-pgo-bolt build profiles for BOLT usage.
.cargo/config.toml No functional change (trailing newline).
.cargo/bolt.toml New isolated config containing BOLT-specific rustflags and linker args.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +333 to +346
## Makefile Targets Reference

| Target | Description |
|--------|-------------|
| `make bolt-full` | Full automated workflow: build → instrument → profile → optimize → verify |
| `make bolt-bench` | Benchmark baseline vs BOLT-optimized (3 runs each) |
| `make build-bolt` | Build BOLT-compatible binary with fat LTO and relocations |
| `make bolt-instrument` | Create instrumented binary for profiling |
| `make bolt-profile` | Run instrumented binary with benchmark fixture to collect profiles |
| `make bolt-optimize` | Apply BOLT optimization using collected profiles |
| `make bolt-verify` | Check that optimized binary has BOLT markers |
| `make bolt-perf2bolt` | Convert `perf.data` to BOLT format (alternative to instrumentation) |
| `make bolt-clean` | Remove all BOLT artifacts and profiles |

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

This Makefile targets table uses || at the start of rows, which renders as an extra empty first column in GitHub Markdown. Switch to standard | Target | Description | formatting.

Copilot uses AI. Check for mistakes.
Comment on lines +380 to +385
| Binary | Avg time (5 runs) |
|--------|-------------------|
| Baseline (release-bolt) | 17,706 ms |
| BOLT-optimized | 17,465 ms |
| **Improvement** | **~1.4%** |

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

The measured-results table also uses a leading || in rows, which adds an unintended empty column in GitHub Markdown. Use standard | Binary | Avg time (5 runs) | table formatting.

Copilot uses AI. Check for mistakes.
Comment thread Makefile
@if [ ! -s $(BOLT_BLOCKS) ]; then \
echo "ERROR: $(BOLT_BLOCKS) missing or empty. Run 'git lfs pull' to fetch fixture files."; \
exit 1; \
fi

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

bolt-check verifies the blocks fixture exists, but the workflow also depends on $(BOLT_GENESIS) (default fixtures/genesis/perf-ci.json). If that file is missing, failures happen later during profiling/bench. Consider adding a similar -s $(BOLT_GENESIS) check here for earlier, clearer errors.

Suggested change
fi
fi
@if [ ! -s $(BOLT_GENESIS) ]; then \
echo "ERROR: $(BOLT_GENESIS) missing or empty. Run 'git lfs pull' to fetch fixture files."; \
exit 1; \
fi

Copilot uses AI. Check for mistakes.
Comment thread Makefile
Comment on lines +107 to +115
bolt-profile: ## 📊 Run instrumented binary with benchmark blocks to collect profile data
@test -f ethrex-instrumented || { echo "ERROR: Run 'make bolt-instrument' first."; exit 1; }
@rm -rf /tmp/bolt-data $(BOLT_PROFILE_DIR)/prof.*
@echo "Profiling with $(BOLT_BLOCKS) (this may take a few minutes)..."
./ethrex-instrumented \
--network $(BOLT_GENESIS) \
--datadir /tmp/bolt-data \
import $(BOLT_BLOCKS)
@rm -rf /tmp/bolt-data

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

In bolt-profile, /tmp/bolt-data is cleaned up only after the instrumented import completes successfully. If the command fails or is interrupted, the directory may be left behind and grow large over repeated runs. Consider using a shell trap (or running the recipe in a single set -e; ...; trap ... block) to ensure cleanup happens on error/interrupt as well.

Copilot uses AI. Check for mistakes.
Comment thread Cargo.toml
# For PGO + BOLT combined (maximum optimization)
[profile.release-pgo-bolt]
inherits = "release"
debug = 1

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

release-pgo-bolt inherits release, which sets lto = "thin", but the PR rationale/docs state fat LTO is required for BOLT compatibility. As-is, release-pgo-bolt will still use thin LTO and may reintroduce .lto_priv.* fragments / BOLT analysis failures. Consider explicitly setting lto = "fat" (and any other BOLT-required settings) on release-pgo-bolt as well.

Suggested change
debug = 1
debug = 1
lto = "fat"

Copilot uses AI. Check for mistakes.
Comment thread Makefile
Comment on lines +35 to +42
bolt-check:
@uname -m | grep -q x86_64 || { echo "ERROR: BOLT requires x86_64 (current: $$(uname -m))"; exit 1; }
@uname -s | grep -q Linux || { echo "ERROR: BOLT requires Linux (current: $$(uname -s))"; exit 1; }
@command -v llvm-bolt >/dev/null 2>&1 || { echo "ERROR: llvm-bolt not found. See docs/developers/bolt-optimization.md for install instructions."; exit 1; }
@if [ ! -s $(BOLT_BLOCKS) ]; then \
echo "ERROR: $(BOLT_BLOCKS) missing or empty. Run 'git lfs pull' to fetch fixture files."; \
exit 1; \
fi

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

bolt-check validates llvm-bolt but later recipes also require merge-fdata (instrumentation workflow) and perf2bolt (perf workflow). Without checking these here, make bolt-* can fail later with less actionable tool-not-found errors. Consider extending bolt-check (or adding per-target checks) to validate merge-fdata and perf2bolt when needed.

Copilot uses AI. Check for mistakes.
Comment thread Makefile Outdated
Comment on lines +47 to +48
bolt-perf2bolt: ## 📊 Convert perf.data to BOLT profile format
@mkdir -p $(BOLT_PROFILE_DIR)

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

bolt-perf2bolt assumes $(BOLT_BINARY) exists, but it doesn't depend on build-bolt/bolt-check and doesn't validate the binary path. This can lead to confusing failures if the user runs make bolt-perf2bolt first. Consider adding a dependency on build-bolt (or at least bolt-check) and/or an explicit test -f $(BOLT_BINARY) guard with a clear error message.

Suggested change
bolt-perf2bolt: ## 📊 Convert perf.data to BOLT profile format
@mkdir -p $(BOLT_PROFILE_DIR)
bolt-perf2bolt: build-bolt ## 📊 Convert perf.data to BOLT profile format
@mkdir -p $(BOLT_PROFILE_DIR)
@if [ ! -f "$(BOLT_BINARY)" ]; then \
echo "ERROR: BOLT binary '$(BOLT_BINARY)' not found. Run 'make build-bolt' first."; \
exit 1; \
fi

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +246
**Available benchmark fixtures:**

| Fixture | Genesis | Blocks | Transactions | Best for |
|---------|---------|--------|-------------|----------|
| `l2-1k-erc20.rlp` | `perf-ci.json` | 1,110 | ~1.5M ERC20 transfers | EVM execution |
| `2000-blocks.rlp` | `perf-ci.json` | 2,004 | ~0 per block | Storage/merkle |

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

Several tables use a leading double pipe (||) in the header and separator rows (e.g., the fixtures and Makefile target tables). In GitHub Markdown this renders as an extra empty first column and looks broken. Use standard table syntax with single leading/trailing | per row.

Copilot uses AI. Check for mistakes.
Comment thread Makefile
Comment on lines +51 to +56
bolt-optimize: ## ⚡ Apply BOLT optimization using collected profiles
@if [ -f $(BOLT_PROFILE_DIR)/perf.fdata ]; then \
llvm-bolt $(BOLT_BINARY) -o ethrex-bolt-optimized \
-data=$(BOLT_PROFILE_DIR)/perf.fdata \
-reorder-blocks=ext-tsp \
-reorder-functions=cdsort \

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

bolt-optimize invokes llvm-bolt $(BOLT_BINARY) but doesn't depend on build-bolt/bolt-check and doesn't validate that $(BOLT_BINARY) exists before running. If the user runs make bolt-optimize directly, the error will come from llvm-bolt and may be unclear. Consider adding a dependency on build-bolt (or at least a test -f $(BOLT_BINARY) check with a clear message).

Copilot uses AI. Check for mistakes.
Comment thread docs/developers/bolt-optimization.md Outdated
#### Option 2: Latest from apt.llvm.org (BOLT 22+)
```bash
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/unstable/ llvm-toolchain main" | sudo tee /etc/apt/sources.list.d/llvm.list

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

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

The apt repository in the apt.llvm.org example uses http://apt.llvm.org/.... Using HTTPS avoids MITM risk during package index download (even though packages are signed). Consider switching that URL to https://apt.llvm.org/... in the instructions.

Suggested change
echo "deb http://apt.llvm.org/unstable/ llvm-toolchain main" | sudo tee /etc/apt/sources.list.d/llvm.list
echo "deb https://apt.llvm.org/unstable/ llvm-toolchain main" | sudo tee /etc/apt/sources.list.d/llvm.list

Copilot uses AI. Check for mistakes.
- Add lto = "fat" to release-pgo-bolt profile (Copilot, Greptile)
- Add bolt-check and bolt-bench to .PHONY (Copilot)
- Validate BOLT_GENESIS in bolt-check (Copilot)
- Add binary existence guard to bolt-optimize and bolt-perf2bolt (Copilot)
- Use HTTPS for apt.llvm.org in docs (Copilot)
Comment thread .cargo/bolt.toml
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Ctarget-cpu=x86-64-v3",
"-Ctarget-feature=+avx2,+sse2,+ssse3,+sse4.1,+sse4.2,+bmi1,+lzcnt,+pclmulqdq",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lines 9-10 duplicate the target CPU flags from .cargo/config.toml (lines 3-4). If someone adds a new target feature to config.toml (e.g., +fma), they'll need to remember to update bolt.toml too — and there's no CI check to catch drift.

Consider either:

  1. Removing these two lines from bolt.toml so the base config.toml flags apply and bolt.toml only adds the BOLT-specific flags (--emit-relocs, frame pointers, hot-cold-split), or
  2. Adding a comment like # Keep in sync with .cargo/config.toml to make the dependency explicit.

Comment thread Makefile
@echo "BOLT optimization complete. Optimized binary: ethrex-bolt-optimized"
@echo "Benchmark with: make bolt-bench"

bolt-bench: ## 📈 Benchmark baseline vs BOLT-optimized binary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: The benchmark loop discards all output except lines matching "Import completed" via grep. If the import fails (e.g., missing fixture, wrong genesis), all error output is silently eaten and the loop reports nothing for that run. Consider | grep "Import completed" || echo "ERROR: import failed (run $i)" so failures are visible.

Comment thread Makefile

# cargo-pgo workflow (requires: cargo install cargo-pgo)
# NOTE: cargo-pgo doesn't pass CXXFLAGS, so use the manual Makefile targets instead
pgo-bolt-build: ## 🔨 Build with cargo-pgo for BOLT instrumentation (use build-bolt instead)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: This target's ## help text says (use build-bolt instead) and the first line of the recipe is an echo saying the same. If it's not recommended, consider removing the ## help annotation so it doesn't show up in make help (keep the echo for anyone who calls it directly).

/// be used by the sequential execution phase.
pub fn warm_block(
///
/// Named `preheat_block` instead of `warm_block` because BOLT's split-function

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The rename is well-motivated, but this doc comment ties a public API name to an external tool's implementation detail. If BOLT fixes its regex matching in a future version, the name preheat_block and this comment become confusing relics.

Consider: keep the rename (it's a fine name regardless), but move the BOLT rationale to the docs page (bolt-optimization.md, which already has a "Rust source constraints" section) rather than embedding it in the function's doc comment. A one-line // See docs/developers/bolt-optimization.md would suffice here if you want a breadcrumb.

@github-project-automation github-project-automation Bot moved this from In Review to In Progress in ethrex_l1 Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client performance Block execution throughput and performance in general

Projects

Status: In Progress
Status: Todo

Development

Successfully merging this pull request may close these issues.

4 participants