int128_t 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 (32, 64, 96, or 128 bits, e.g. 2x1 words, 1x2 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.

On most platforms we use the builtin __int128 as the reference benchmark. When this is unavailable (such as on 32-bit architectures) we use boost::multiprecision::int128_t (abbreviated as boost::mp::int128_t) as it is widely used, and known to be portable. On MSVC platforms we use as reference std::_Signed128 from the header <__msvc_int128.hpp> since this is bundled with their compiler. Lastly, when available, the benchmarks are also run with absl::int128 which is the 128-bit signed integer from the Abseil Libraries.

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_i128.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/int128/test/benchmark_i128.cpp -o benchmark_i128
./benchmark_i128 --json i128.json

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 both drivers 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 both drivers 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

x86_64

Measured with GCC 14.2 (C++20): 5 passes over 20,000,000 element pairs (100,000,000 operations per cell).

Operation __int128 int128_t boost::mp::int128_t absl::int128

Comparisons

575,065

500,451

1,703,153

503,204

Addition

65,874

60,371

176,054

60,901

Subtraction

65,944

72,082

569,596

71,309

Multiplication

86,629

74,522

196,324

74,967

Division

999,372

978,885

985,280

970,981

Modulo

940,401

963,188

1,010,396

918,835

x64 Relative Performance

ARM64

Measured with GCC 14.2 (C++20): 5 passes over 20,000,000 element pairs (100,000,000 operations per cell).

Operation __int128 int128_t boost::mp::int128_t absl::int128

Comparisons

1,548,448

978,632

2,358,441

1,576,854

Addition

86,459

87,101

221,898

88,399

Subtraction

87,087

85,946

455,419

86,913

Multiplication

84,919

84,091

187,422

83,956

Division

814,967

767,734

966,484

812,755

Modulo

839,380

767,831

953,283

841,903

ARM64 Relative Performance

S390x

Measured with GCC 12.2 (C++20): 5 passes over 2,000,000 element pairs (10,000,000 operations per cell).

Operation __int128 int128_t boost::mp::int128_t absl::int128

Comparisons

785,777

708,911

2,059,404

525,305

Addition

50,685

44,057

258,246

37,090

Subtraction

50,668

41,357

303,965

41,352

Multiplication

53,734

36,512

150,617

36,708

Division

752,827

682,729

919,962

752,655

Modulo

802,322

720,485

851,901

796,760

s390x Relative Performance

PPC64LE

Measured with GCC 12.2 (C++20): 5 passes over 2,000,000 element pairs (10,000,000 operations per cell).

Operation __int128 int128_t boost::mp::int128_t

Comparisons

428,645

462,487

1,021,098

Addition

24,939

16,225

118,021

Subtraction

104,630

14,546

172,685

Multiplication

16,136

16,268

88,742

Division

614,489

509,815

629,501

Modulo

627,865

686,382

642,930

ppc64le Relative Performance

x86_32

This platform has no hardware type so we compare relative to boost::mp::int128_t

Measured with GCC 14.2 (C++20): 5 passes over 10,000,000 element pairs (50,000,000 operations per cell).

Operation int128_t boost::mp::int128_t

Comparisons

1,803,323

2,166,376

Addition

159,907

1,198,244

Subtraction

178,360

1,416,733

Multiplication

213,890

1,726,368

Division

1,711,915

2,680,645

Modulo

1,706,134

2,539,888

x86 Relative Performance

ARM32

This platform has no hardware type so we compare relative to boost::mp::int128_t

Measured with GCC 12.2 (C++20): 5 passes over 2,000,000 element pairs (10,000,000 operations per cell).

Operation int128_t boost::mp::int128_t

Comparisons

1,199,464

1,149,576

Addition

90,313

1,105,341

Subtraction

83,826

1,065,408

Multiplication

128,179

1,710,617

Division

3,477,343

5,506,901

Modulo

3,495,645

5,094,644

ARM32 Relative Performance

Windows

x86_64

Measured with MSVC 14.51 (C++20): 5 passes over 20,000,000 element pairs (100,000,000 operations per cell).

Operation std::_Signed128 int128_t boost::mp::int128_t

Comparisons

1,361,518

1,271,189

4,315,263

Addition

115,135

107,633

2,089,612

Subtraction

108,885

105,990

2,265,849

Multiplication

196,081

113,761

3,024,735

Division

1,031,262

1,241,974

4,191,052

Modulo

1,080,810

1,327,820

4,139,305

x64 Relative Performance

ARM64

Measured with MSVC 14.44 (C++20): 5 passes over 20,000,000 element pairs (100,000,000 operations per cell).

Operation std::_Signed128 int128_t boost::mp::int128_t

Comparisons

1,191,566

1,125,261

2,871,780

Addition

86,160

84,055

1,598,093

Subtraction

88,263

87,934

1,769,736

Multiplication

505,934

81,566

2,395,038

Division

1,506,403

1,480,602

3,622,476

Modulo

1,722,778

1,447,734

3,555,076

ARM64 Relative Performance

x86_32

Measured with MSVC 14.51 (C++20): 5 passes over 10,000,000 element pairs (50,000,000 operations per cell).

Operation std::_Signed128 int128_t boost::mp::int128_t

Comparisons

2,084,732

1,947,041

2,898,710

Addition

131,344

128,063

1,325,852

Subtraction

447,258

128,145

1,454,691

Multiplication

877,318

149,394

2,018,981

Division

3,479,471

3,113,092

3,948,298

Modulo

2,683,535

3,157,295

3,620,409

x86 Relative Performance

macOS

ARM64 (Apple Silicon)

Measured with Apple Clang 21.0 (C++20): 5 passes over 20,000,000 element pairs (100,000,000 operations per cell).

Operation __int128 int128_t boost::mp::int128_t absl::int128

Comparisons

479,219

358,275

1,035,078

405,457

Addition

152,489

90,873

444,144

72,358

Subtraction

51,306

75,991

383,429

87,675

Multiplication

60,826

49,480

205,901

64,798

Division

1,363,999

1,378,656

1,893,255

1,372,411

Modulo

1,534,656

1,435,001

2,223,197

1,490,100

ARM64 Relative Performance