ops/bench/measure-node.sh records a running node before and after a window (how the tool works). We ran it once on an xOneRS net2040 follower on 2026-11-15, with an 8-minute window and 20 calls per method, on a host with a load average near 40 on 20 cores (it also runs builds). This post gives the numbers and what they do and do not show. One finding about the tool itself became issue #1222.
The node: build fc9a8e9e of 2026-11-13, following net2040 from block 852,064 to 852,162 during the window. It was not started with --debug.logslowblock, so the block import rows are empty.
What latency did each call have?
Milliseconds, nearest-rank, 20 calls each:
| Call | Before p50 / p95 | After p50 / p95 | Errors before / after |
|---|---|---|---|
eth_blockNumber |
0.69 / 2.66 | 0.62 / 7.60 | 0 / 0 |
eth_chainId |
0.53 / 1.04 | 0.93 / 5.42 | 0 / 0 |
eth_getBlockByNumber |
0.58 / 1.13 | 0.90 / 2.89 | 0 / 0 |
eth_getBlockByNumber, full |
2.09 / 6.24 | 0.54 / 1.14 | 0 / 0 |
eth_getBlockReceipts |
2.51 / 5.15 | 0.83 / 10.26 | 11 / 11 |
eth_getBalance |
0.56 / 1.14 | 1.94 / 48.46 | 18 / 8 |
eth_gasPrice |
0.51 / 1.12 | 3.81 / 61.27 | 14 / 0 |
The medians stay near 1 ms, as in our 33-node sample. The 95th percentiles move between snapshots by a factor of up to 50; with 20 calls on a busy host, one slow call sets them.
Why are there errors?
We do not know, and the tool cannot tell us. It counts a failed call but does not record the error code, the message or the HTTP status, and it keeps the failed call's time in the percentiles. Right after the run, 60 calls of eth_getBalance and eth_gasPrice made one at a time all succeeded. The tool sends its 140 calls per snapshot back to back, so a refusal by the node's rate bucket (-32005) is one candidate; a timeout is another. Issue #1222 asks the tool to record the reason, to keep failed calls out of the percentiles, and to allow a pause between calls.
Until then, read the latency rows of a method with errors as unreliable.
What did memory and I/O do?
| Before | After | |
|---|---|---|
| RSS | 96.0 MB | 88.7 MB |
| of which anonymous | 77.6 MB | 77.3 MB |
| of which file-backed | 18.4 MB | 11.3 MB |
| Peak (VmHWM) | 391.7 MB | 391.7 MB |
Over the 480-second window the process wrote 137.9 MB through system calls (wchar) and 19.9 MB reached the disk (write_bytes); it read 4.6 MB from disk. The datadir grew by 187,668 bytes for 98 blocks, about 1,900 bytes per block, close to the 1,950 bytes per block we saw over nine hours (datadir growth).
What does a useful run need?
- Start the node with
--debug.logslowblock 0, so the import rows have data. - Run on a quiet host, or record the load as we did.
- Use more samples, and a longer window for growth numbers.
- Until #1222 is fixed, check the node's log for refused calls during the run.
Frequently asked questions
Is xOne slow because the p95 reached 61 ms?
Not from this run. The medians are near 1 ms; the tails come from a busy host and 20 samples, and some of the slow calls may be failed ones.
Why did eth_getBalance fail 18 times?
The tool does not record why. Later single calls succeeded. Issue #1222 asks for the reason to be recorded.
How much memory does a net2040 xOneRS follower use?
In this run, about 77 MB of its own memory and 89 to 96 MB in all, with a peak of 392 MB since it started.
Sources
- One run of ops/bench/measure_node.py from
main, 2026-11-15, read-only; the host name in its JSON is not published. - Issue #1222.
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/measure-node-first-run/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.