bench(blocksync): per-block stage timing and a no-fsync switch for profiling - #1430
bench(blocksync): per-block stage timing and a no-fsync switch for profiling#1430PastaPastaPasta wants to merge 2 commits into
Conversation
TD_BLOCK_PERF=1 reports the mean cost of each ApplyBlock stage every 100 blocks. TD_UNSAFE_NOSYNC=1 drops the fsync from block-store and state-store writes: on macOS Go's File.Sync issues F_FULLFSYNC (~7ms here versus 0.23ms for a plain fsync), which otherwise swamps a block-sync profile and does not represent a Linux node.
…tage apply_gap is the time the applier spends waiting for the next block to arrive, which is what limits the sync rate when the application is fast: 2.2-3.5 ms/block with one peer, 0.003 ms with two. Splitting verify shows the whole stage is one BLS threshold verification (1.90 ms) and that ValidateBlock is free (0.009 ms).
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🕓 Ready for review — 22 ahead in queue (commit aefda6c) |
Block sync reports
partset,verify,saveandexecper block, butexecis a single number covering the two ABCI calls, our own durable writes, the mempool update and the event publish. That is most of a block, and it was opaque.This adds two things, both off unless switched on.
TD_BLOCK_PERF=1— stage timingTimes each stage of
ApplyBlockand reports the means every 100 blocks. It also splitsverifyand recordsapply_gap, the time the applier spends waiting for the next block to arrive.Two findings that came straight out of it:
The
verifystage is a single BLS threshold verification. Splitting it:ValidateBlockis free; the whole stage is the signature. That is what #1427 and #1428 act on.A single peer costs a third of the sync.
apply_gapis 2.2–3.5 ms/block with one peer and 0.003 ms with two — the applier is waiting on block fetch, not executing:Worth knowing when reading any block-sync benchmark, and worth telling operators.
TD_UNSAFE_NOSYNC=1— drop the fsync from store writesThis is a benchmarking correction rather than a tuning knob.
Go's
os.File.Sync()on darwin issuesF_FULLFSYNC, notfsync. Measured on an M-series Mac:Tenderdash does three synchronous writes per block during block sync —
BlockStore.SaveBlock,saveABCIResponses,state.Save— so on macOS it spends about 20 ms a block that a Linux node does not. Same binaries, same chain:verifysaveexecTD_UNSAFE_NOSYNC=1fb_save_abci_resp6.60 → 0.03 ms,fb_save_state6.03 → 0.05 ms. Leaving it on hides everything else in a profile taken on macOS.The name is deliberate. It removes durability: a power loss can leave the block store behind the application, which the replayer rejects with
ErrAppBlockHeightTooHigh. Never set it on a node whose data matters.How this was tested
Used throughout a full mainnet Platform replay, genesis to height 424,981, and for every A/B measurement behind #1427 and #1428.
internal/state/...andinternal/blocksync/...pass.🤖 Generated with Claude Code