uint256 Benchmarks
Methodology
Every cell below is the total time in microseconds that one operation takes over a whole vector of random values, so lower is better.
The vector holds operands of random width (64, 128, 192, or 256 bits, that is one to four significant words), each operation is evaluated as op(vec[i], vec[i + 1]) across the vector, and the whole vector is walked several times.
Each platform states its element count and pass count, and therefore how many operations a cell covers.
The Comparisons row is the total of all six relational operators (==, !=, <, ⇐, >, >=) over that same vector, which is why it costs roughly six arithmetic rows.
No platform has a hardware 256-bit integer, so there is no builtin reference to compare against.
The baseline is boost::multiprecision::uint256_t (abbreviated as boost::mp::uint256 in the tables), which is widely used and portable, and is also the oracle the library’s differential tests use.
The second comparison is wide-integer's math::wide_integer::uintwide_t<256U, std::uint32_t> (uintwide_t<256> in the tables), an independent header-only implementation that is also the reference for the library’s fuzzers.
It is used in its default configuration, with 32-bit limbs.
The driver measures it whenever <math/wide_integer/uintwide_t.h> is on the include path, and the CI runs always provide it, pinned to one commit so that runs stay comparable.
There is no 256-bit type in Abseil, so unlike the Boost.Int128 benchmarks there is no Abseil column.
| Each platform reports a single run, several of them from shared CI runners, so treat small differences as noise. |
Running the Benchmarks
The driver is test/benchmark_u256.cpp. From a Boost tree with its headers staged (b2 headers), build it in release mode and pass --json to have it write out a data set:
g++ -std=c++20 -O2 -DNDEBUG -I . libs/int256/test/benchmark_u256.cpp -o benchmark_u256
./benchmark_u256 --json u256.json
Add -I <path to wide-integer> to the command line to include the wide-integer column.
Timings are printed to stderr as they are measured, so a run is readable without the data set.
--elements and --repetitions shrink the run, which is what the emulated platforms use.
From the root of a Boost tree, .github/scripts/run_benchmarks.sh --compiler g++ --out <dir> builds and runs the driver exactly as CI does and leaves a complete data set folder behind. It takes its include path from the checked out libraries, so it needs no staged headers.
The benchmarks.yml workflow runs the driver on every platform documented here and uploads one benchmarks-<os>-<arch> artifact per platform.
It runs on every pull request, and each job’s summary compares its fresh numbers against the published ones, so a regression is visible without downloading anything.
To refresh this page, unpack those artifacts into doc/modules/ROOT/data and run doc/render_benchmarks.py, which rewrites every table and plot below from the data sets.
Linux
Numbers are published here once the benchmarks.yml workflow has run and its artifacts have been rendered by doc/render_benchmarks.py.
Windows
Numbers are published here once the benchmarks.yml workflow has run and its artifacts have been rendered by doc/render_benchmarks.py.