Skip to content

build: link natively on arm64 (Apple Silicon); compile-time profile - #213

Merged
On1x merged 2 commits into
masterfrom
build/native-arm64
Oct 30, 2026
Merged

On1x merged 2 commits into
masterfrom
build/native-arm64

Conversation

@chiliec

@chiliec chiliec commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

Deep-dive into build time and runtime hot paths. The actionable finding: the tree could not link on arm64 at all, which is why every local build on this project's maintainer laptop has gone through amd64 emulation in Docker (~1 h cold) instead of running natively (~10 min). The cause was dead code.

  • thirdparty/fc vendored an SSE-only equihash (Steem proof-of-work) that nothing in VIZ calls (zero references in libraries/, plugins/, programs/, tests/), and linked it unconditionally. Removed in build: drop the unused equihash vendor library; qualify fc::forward fc#4 (merged, bd855b7); this PR bumps the submodule to fc master.
  • fc#4 also qualifies two forward<T>() calls in variant_object.hpp that Apple clang 21 reports as ambiguous.
  • On macOS, Homebrew's static Boost.Iostreams config lists bz2;lzma;zstd;icu* as bare names; the Apple linker does not search the Homebrew prefix and icu4c is keg-only, so the link died with library 'zstd' not found. The APPLE block now adds the brew prefix lib dirs to the link path.
  • tests/consensus_sim/fc-arm64-portability.patch was unreferenced and patched the same dead files; removed.
  • New label-gated CI job build_arm64 (ubuntu-24.04-arm, free for public repos), same shape as build_boost_183, so the arm64 end of the platform range stays covered. The check-arm64 label is on this PR.
  • docs/development/building.md: Apple Silicon note and the compile-time profile below.

What the analysis found (and did not change)

CI wall clock is tests, not compile: with the warm ccache from #202 the build step is ~2 min; the serial consensus_sim run is 18–20 min. #203 already parallelises it, so nothing here touches tests.yml.

Compile-time profile (clang -ftime-trace, Release, native arm64, 74 project TUs ≈ 43 CPU-min):

TU s
libraries/chain/database.cpp 248
libraries/wallet/wallet.cpp 162
libraries/network/dlt_p2p_node.cpp 130
libraries/protocol/operations.cpp 127
plugins/snapshot/plugin.cpp 102

In a typical unit (block_log.cpp: 10 s frontend, 23 s backend) two thirds of the time is the optimizer: every TU that serializes a signed_block instantiates ~1,500 fc::raw pack/unpack visitor functions (one per field per operation) and -O3 optimizes each again. So ENABLE_PCH can only shave the parsing third; the structural fix would be compiling the block/transaction serializers once (explicit instantiation), which fc's inline templates make unreliable — left as a follow-up, not attempted here.

Per-block runtime path (_apply_block and the 25 processors it calls) was read for scans that grow with chain size ahead of 1 s slots: every loop is bounded by an ordered index (by_expiration, by_status, by_next_time, …) or by CHAIN_MAX_VALIDATORS / CHAIN_MAX_BLOCK_POST_VALIDATION_COUNT; the only full-table scan (update_bandwidth_reserve_candidates) is hourly and already scaled by block_interval(). Nothing to change.

Verified

  • Native M-series Mac, Apple clang 21, Homebrew Boost 1.90: vizd and cli_wallet link; vizd --version prints 4.2.0. Cold vizd at -j8: ~10 min.
  • All 14 ctest binaries build natively with ASan/UBSan; ctest -E '^consensus_sim$': 13/13 pass.
  • Full native consensus_sim_tests run: see the comment below (in progress when this was opened).
  • Workflow YAML parses; Linux/amd64 paths are untouched except the submodule pointer (CI proves that).

fc vendored an SSE-only equihash that nothing in VIZ calls, and linked it
unconditionally, so no executable could link on arm64 (Apple Silicon, Graviton,
Ampere); amd64 CI never saw it. The fc submodule now drops it (VIZ-Blockchain/fc#4,
which also qualifies two fc::forward calls Apple clang 21 reports as ambiguous).
The unreferenced tests/consensus_sim/fc-arm64-portability.patch patched the same
dead files and goes with them.

On macOS, Homebrew's static Boost.Iostreams config lists its dependencies as bare
names (bz2, lzma, zstd, icu*); the Apple linker does not search the Homebrew
prefix and icu4c is keg-only, so the link failed with "library 'zstd' not
found". The APPLE block now adds the brew prefix lib dirs to the link path.

docker-pr-build.yml gains a label-gated (check-arm64) build on ubuntu-24.04-arm,
mirroring the Boost 1.83 range check, so the arm64 end of the platform range
stays covered.

docs/development/building.md records the result and the -ftime-trace profile:
a cold vizd is ~10 min natively on an 8-core M-series laptop vs ~1 h under amd64
emulation; five TUs are a third of the compile time and the optimizer, not the
parser, is ~2/3 of a typical unit, which is why PCH alone cannot fix it.
@chiliec chiliec added the check-arm64 Run the label-gated arm64 build (ubuntu-24.04-arm) on this PR label Oct 30, 2026
@chiliec

chiliec commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

Full native consensus_sim_tests run (Apple M1, macOS 26.6, Release, -DBUILD_CONSENSUS_TESTS=ON)

./consensus_sim_tests --log_level=test_suite
*** No errors detected
EXIT 0
109 test cases, 0 failures
42.20s user 8.60s system 5% cpu 14:14.39 total

Wall time is I/O-bound (5 % CPU): every simulated node opens a fresh 64 MB chainbase mmap, and seed_sweep_one_hundred_all_fire alone does 700 of those (100 seeds × 7 nodes). CPU time is under a minute. Same test set as the Docker amd64 run; results match.

@On1x On1x 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.

All checks are green on the current head d5ca0bae, including the new arm64 job. The job is meaningful rather than decorative: it builds on ubuntu-24.04-arm and runs vizd itself, and it carries the same Dockerfile and flag set as the other build jobs, so a green run says the arm64 link actually works. The patch we merged today in VIZ-Blockchain/fc (#4, dropping the unused equihash vendor library) was the blocker for that link; I verified no caller of fc::equihash exists in the node tree, so removing it is dead-code removal. Deleting the obsolete arm64 portability patch is consistent with the same change.

@On1x
On1x merged commit 4bbcf2d into master Oct 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

check-arm64 Run the label-gated arm64 build (ubuntu-24.04-arm) on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants