Skip to content

Add integer-bench: a standalone bigint comparison benchmark crate - #65

Closed
DRMacIver wants to merge 1 commit into
cmpute:masterfrom
DRMacIver:benchmarks
Closed

Add integer-bench: a standalone bigint comparison benchmark crate#65
DRMacIver wants to merge 1 commit into
cmpute:masterfrom
DRMacIver:benchmarks

Conversation

@DRMacIver

Copy link
Copy Markdown
Contributor

I mentioned I've been doing a bunch of perf work on dashu to try to optimise it for some of our workloads in hegel. Here's the set of benchmarks I've been developing against. I've added a bunch of comparisons to other libraries in it, though those are more because I thought it would illuminating about where there are gains to be had than anything else. My actual use case is to validate various performance improvements on dashu.

First off: Apologies, this is an unreasonable amount of code. I can break it up into multiple pull requests, but I'm not sure that would help much. Feel free to reject it if you'd rather not have this much novel benchmarking code in your library, and if so I'll publish it in a separate repo somewhere instead, but I found it super useful for guiding my perf work and wanted to offer it, and it will be useful for making sense of my upcoming patches.

These are generally focused on integer operations in the "small" integer regime of < 10^4 bits. This makes them look quite flattering to dashu - in larger regions than that, rug and malachite's gmp (and gmp-derived) based algorithms win big and dashu starts to suffer - because those are the regimes I cared most about for my use case. You can start to see this transition in the 10^3 to 10^4 bit region.

I've added these as a separate benchmarking crate (not published) as I didn't want to add features to the main dashu crate (especially ones that would raise the MSRV) and didn't want to interfere with your existing benchmarks. CI gets a smoke-test-integer-bench job that builds the benches and runs each once via criterion --test (no measurement, no numbers reported, since CI is too noisy for real benchmarking), this is just to make sure the benchmarks don't rot.

Here are my local measurements of these benchmarks. You shouldn't consider these too authoritative. They come from a criterion run with a short measurement time (1 s warm-up, 2 s measurement, 100 samples) on my macbook (which wasn't otherwise under heavy load, but certainly wasn't perfectly clean).

Summary

  • Fastest-library tally across 205 comparison cases: dashu 54, ibig 37, num 35, malachite 27, rug 52.
  • dashu vs rug head-to-head (where both ran): dashu faster in 123, rug faster in 82.
  • Restricted to the small-value benches (small_int / workload / shrinker): dashu faster than rug in 98 of 153 cases.
  • Crossover around ~1 kbit. Through ~100 bits dashu (and the other pure-Rust libs) lead, but by 1000–10000 bits rug pulls ahead on add/sub/mul/div, modular arithmetic and base conversion (e.g. ubig_mul at 10⁴ bits: rug ~4.5 µs vs dashu ~12.8 µs), with malachite usually second.

Detailed run results follow:

These were run on an Apple M2 Max, macOS (Darwin 25.5.0, arm64) with rustc 1.92.0 (ded5c06cf 2025-12-08).
I used dashu-int 0.4.2 (path), ibig 0.3.6, num-bigint 0.4.6, malachite-nz 0.9.1, rug 1.30.0 (GMP 6.x).

Criterion settings: --warm-up-time 1 --measurement-time 2 --sample-size 100.

Each cell is the median wall-clock time; bold marks the fastest library in that row.

Details ## primitive (bit-width sweep)

ubig_add

size dashu ibig num malachite rug
10 3.6 ns 1.8 ns 17.8 ns 2.1 ns 17.7 ns
100 3.7 ns 25.7 ns 18.7 ns 18.7 ns 21.9 ns
1000 30.2 ns 28.8 ns 27.3 ns 27.5 ns 21.6 ns
10000 221.0 ns 220.4 ns 211.8 ns 140.5 ns 57.8 ns

ubig_sub

size dashu ibig num malachite rug
10 2.9 ns 1.5 ns 18.9 ns 2.7 ns 18.0 ns
100 2.9 ns 25.0 ns 19.9 ns 20.3 ns 22.3 ns
1000 29.1 ns 28.1 ns 26.9 ns 30.2 ns 22.2 ns
10000 174.9 ns 168.9 ns 131.2 ns 137.2 ns 58.7 ns

ubig_mul

size dashu ibig num malachite rug
10 3.3 ns 2.1 ns 18.5 ns 3.0 ns 18.0 ns
100 22.6 ns 30.8 ns 39.3 ns 27.1 ns 25.1 ns
1000 226.3 ns 226.6 ns 236.6 ns 172.3 ns 116.1 ns
10000 12.76 µs 12.69 µs 13.40 µs 8.28 µs 4.52 µs

ubig_div

size dashu ibig num malachite rug
10 4.9 ns 1.5 ns 37.6 ns 2.7 ns 28.3 ns
100 5.7 ns 65.2 ns 112.0 ns 71.2 ns 32.4 ns
1000 102.2 ns 93.1 ns 159.5 ns 84.5 ns 62.6 ns
10000 440.5 ns 420.6 ns 703.2 ns 250.9 ns 60.0 ns

ubig_gcd

size dashu ibig num malachite rug
10 17.9 ns 87.9 ns 132.0 ns 8.5 ns 20.9 ns
100 205.6 ns 880.7 ns 1.06 µs 440.3 ns 122.4 ns
1000 2.87 µs 16.40 µs 12.77 µs 2.91 µs 3.05 µs
10000 63.85 µs 850.52 µs 554.11 µs 70.35 µs 53.05 µs

ubig_gcd_ext

size dashu ibig num malachite rug
10 28.9 ns 118.8 ns 1.35 µs 25.8 ns 53.7 ns
100 356.8 ns 4.72 µs 13.85 µs 420.9 ns 269.2 ns
1000 4.04 µs 80.63 µs 222.05 µs 3.40 µs 3.18 µs
10000 140.12 µs 7.82 ms 5.68 ms 115.77 µs 70.31 µs

ubig_to_hex

size dashu ibig num malachite rug
10 29.1 ns 37.8 ns 29.1 ns 31.4 ns 32.9 ns
100 42.7 ns 94.9 ns 44.5 ns 155.9 ns 54.6 ns
1000 758.7 ns 760.5 ns 161.5 ns 796.6 ns 281.9 ns
10000 7.35 µs 7.34 µs 1.34 µs 6.18 µs 2.47 µs

ubig_to_dec

size dashu ibig num malachite rug
10 27.7 ns 27.7 ns 44.0 ns 10.1 ns 37.5 ns
100 68.3 ns 79.2 ns 90.1 ns 116.3 ns 80.5 ns
1000 1.06 µs 1.14 µs 1.41 µs 936.2 ns 707.0 ns
10000 31.10 µs 31.93 µs 47.93 µs 21.81 µs 12.67 µs

ubig_from_hex

size dashu ibig num malachite rug
10 7.8 ns 6.0 ns 37.1 ns 5.5 ns 48.0 ns
100 48.3 ns 46.0 ns 76.4 ns 50.2 ns 115.1 ns
1000 267.7 ns 268.3 ns 384.8 ns 340.3 ns 701.3 ns
10000 2.56 µs 2.55 µs 3.95 µs 3.13 µs 6.60 µs

ubig_from_dec

size dashu ibig num malachite rug
10 7.5 ns 5.4 ns 39.7 ns 4.8 ns 48.3 ns
100 51.6 ns 43.0 ns 79.2 ns 65.3 ns 125.3 ns
1000 283.2 ns 270.3 ns 529.9 ns 231.5 ns 871.4 ns
10000 10.38 µs 10.17 µs 12.52 µs 8.37 µs 11.51 µs

ubig_pow

size dashu ibig num malachite rug
10 16.6 ns 11.4 ns 128.8 ns 5.1 ns 41.6 ns
100 55.2 ns 76.0 ns 270.4 ns 57.8 ns 50.6 ns
1000 235.4 ns 406.7 ns 706.9 ns 243.0 ns 159.6 ns
10000 13.93 µs 14.15 µs 17.60 µs 6.01 µs 3.68 µs

ubig_modulo_mul

size dashu ibig num malachite rug
10 7.4 ns 2.1 ns 41.2 ns 4.6 ns 30.3 ns
100 60.9 ns 102.4 ns 160.4 ns 79.2 ns 47.7 ns
1000 785.4 ns 776.7 ns 1.07 µs 708.2 ns 409.2 ns
10000 35.24 µs 34.81 µs 57.70 µs 31.76 µs 14.83 µs

ubig_modulo_pow

size dashu ibig num malachite rug
10 377.3 ns 280.0 ns 4.35 µs 317.8 ns 196.4 ns
100 3.29 µs 5.68 µs 11.42 µs 3.97 µs 2.96 µs
1000 770.50 µs 864.16 µs 1.69 ms 440.39 µs 305.28 µs
10000 398.89 ms 397.67 ms 391.29 ms 250.90 ms 143.02 ms

small_int (small / inline-magnitude values)

ibig_from_i64

size dashu ibig num malachite rug
1.8 ns 1.4 ns 23.7 ns 1.5 ns 18.0 ns

ibig_from_i128

size dashu ibig num malachite rug
1.8 ns 22.1 ns 26.3 ns 16.0 ns 18.9 ns

ubig_from_u64

size dashu ibig num malachite rug
1.8 ns 0.9 ns 20.4 ns 0.7 ns 15.5 ns

ubig_from_u128

size dashu ibig num malachite rug
1.8 ns 21.4 ns 21.2 ns 15.1 ns 15.8 ns

ibig_try_into_i128

size dashu ibig num malachite rug
1.4 ns 2.5 ns 2.9 ns 3.7 ns 2.1 ns

ubig_add_by_class

class dashu ibig num malachite rug
zero 3.3 ns 1.8 ns 4.1 ns 2.1 ns 17.8 ns
one_word 3.3 ns 14.0 ns 39.6 ns 11.0 ns 21.2 ns
two_word 25.1 ns 25.3 ns 51.2 ns 49.9 ns 28.3 ns
just_over_inline 29.0 ns 27.1 ns 56.0 ns 53.8 ns 32.4 ns
mid 32.4 ns 28.7 ns 60.5 ns 57.9 ns 21.3 ns
large 221.0 ns 219.7 ns 207.6 ns 133.1 ns 57.0 ns

ubig_mul_by_class

class dashu ibig num malachite rug
zero 3.3 ns 2.1 ns 1.7 ns 2.4 ns 3.7 ns
one_word 3.3 ns 22.1 ns 51.6 ns 15.7 ns 18.4 ns
two_word 22.2 ns 30.1 ns 39.3 ns 26.5 ns 24.7 ns
just_over_inline 34.0 ns 32.7 ns 45.6 ns 29.3 ns 28.1 ns
mid 221.4 ns 220.9 ns 231.0 ns 169.5 ns 123.7 ns
large 12.51 µs 12.38 µs 13.16 µs 8.12 µs 4.54 µs

ibig_add_by_class

class dashu ibig num malachite rug
zero 4.1 ns 3.1 ns 3.4 ns 2.8 ns 17.9 ns
one_word 5.3 ns 8.2 ns 32.8 ns 8.6 ns 20.5 ns
two_word 14.2 ns 32.1 ns 39.4 ns 40.7 ns 36.3 ns
just_over_inline 37.8 ns 34.3 ns 43.2 ns 43.9 ns 33.8 ns
mid 41.0 ns 38.0 ns 50.8 ns 53.9 ns 24.4 ns
large 202.2 ns 203.5 ns 177.7 ns 146.7 ns 61.7 ns

ubig_add_mixed

class dashu ibig num malachite rug
just_over_inline 26.3 ns 29.2 ns 27.5 ns 23.7 ns 33.9 ns
mid 26.2 ns 25.1 ns 23.0 ns 21.9 ns 24.3 ns
large 43.3 ns 43.8 ns 41.5 ns 42.4 ns 37.9 ns

ubig_add_assign_by_class

class dashu ibig num malachite rug
zero 7.3 ns 3.7 ns 3.9 ns 5.1 ns 17.7 ns
one_word 7.3 ns 14.4 ns 37.9 ns 10.5 ns 37.8 ns
two_word 26.2 ns 25.6 ns 50.7 ns 66.4 ns 49.7 ns
just_over_inline 30.6 ns 27.4 ns 54.8 ns 73.7 ns 38.0 ns
mid 37.5 ns 31.7 ns 60.4 ns 77.0 ns 51.5 ns
large 220.9 ns 220.5 ns 210.7 ns 180.1 ns 87.7 ns

ibig_add_assign_by_class

class dashu ibig num malachite rug
zero 7.7 ns 6.2 ns 7.4 ns 5.4 ns 17.7 ns
one_word 8.5 ns 11.6 ns 33.6 ns 9.8 ns 39.5 ns
two_word 20.4 ns 35.1 ns 43.7 ns 61.1 ns 53.6 ns
just_over_inline 37.7 ns 36.2 ns 43.7 ns 64.4 ns 41.6 ns
mid 44.9 ns 40.4 ns 52.7 ns 71.1 ns 55.7 ns
large 202.3 ns 205.3 ns 175.7 ns 188.0 ns 92.9 ns

ubig_sub_assign_by_class

class dashu ibig num malachite rug
zero 6.7 ns 2.8 ns 4.4 ns 6.3 ns 17.4 ns
one_word 6.7 ns 15.8 ns 20.5 ns 24.3 ns 46.1 ns
two_word 27.0 ns 27.2 ns 23.6 ns 44.9 ns 39.5 ns
just_over_inline 29.8 ns 28.2 ns 24.7 ns 46.7 ns 54.3 ns
mid 36.0 ns 30.0 ns 28.2 ns 49.7 ns 40.7 ns
large 174.1 ns 169.8 ns 130.0 ns 168.4 ns 88.2 ns

ibig_sub_assign_by_class

class dashu ibig num malachite rug
zero 7.8 ns 8.0 ns 7.4 ns 5.7 ns 17.7 ns
one_word 8.8 ns 13.8 ns 35.9 ns 10.6 ns 38.8 ns
two_word 20.6 ns 36.3 ns 43.6 ns 62.2 ns 53.8 ns
just_over_inline 37.9 ns 36.7 ns 49.4 ns 69.1 ns 40.8 ns
mid 44.3 ns 43.8 ns 53.2 ns 72.3 ns 55.9 ns
large 207.7 ns 212.1 ns 181.5 ns 185.8 ns 91.1 ns

ubig_add_assign_heap_acc_small_rhs

class dashu ibig num malachite rug
just_over_inline 28.2 ns 29.8 ns 26.3 ns 44.7 ns 41.5 ns
mid 29.9 ns 26.5 ns 22.4 ns 38.7 ns 52.5 ns
large 43.9 ns 49.4 ns 40.4 ns 87.2 ns 56.9 ns

ibig_add_assign_heap_acc_small_rhs

class dashu ibig num malachite rug
just_over_inline 33.7 ns 35.2 ns 32.6 ns 49.7 ns 42.3 ns
mid 33.7 ns 33.7 ns 30.0 ns 45.3 ns 54.0 ns
large 50.7 ns 56.2 ns 51.6 ns 93.4 ns 59.3 ns

ibig_add_assign_i64_into_heap_acc

size dashu ibig num malachite rug
34.3 ns 34.0 ns 64.7 ns 44.5 ns 41.9 ns

ibig_add_assign_i128_into_heap_acc

size dashu ibig num malachite rug
36.7 ns 56.3 ns 72.7 ns 63.9 ns 56.5 ns

ubig_add_assign_u64_into_heap_acc

size dashu ibig num malachite rug
30.0 ns 28.8 ns 62.2 ns 39.2 ns 52.6 ns

ubig_add_assign_u128_into_heap_acc

size dashu ibig num malachite rug
33.8 ns 48.7 ns 61.6 ns 55.1 ns 53.0 ns

ubig_bitxor_assign_by_class

class dashu ibig num malachite rug
zero 7.2 ns 3.6 ns 4.4 ns 4.4 ns 18.0 ns
one_word 7.2 ns 3.6 ns 17.2 ns 4.4 ns 18.4 ns
two_word 7.3 ns 25.2 ns 17.7 ns 36.2 ns 18.9 ns
just_over_inline 29.5 ns 26.9 ns 23.0 ns 43.9 ns 22.3 ns
mid 30.5 ns 25.8 ns 21.5 ns 38.0 ns 23.3 ns
large 65.0 ns 64.3 ns 55.3 ns 88.8 ns 62.4 ns

ubig_eq

class dashu ibig num malachite rug
zero 3.2 ns 1.1 ns 2.7 ns 1.1 ns 1.3 ns
one_word 3.4 ns 1.1 ns 2.7 ns 1.1 ns 2.1 ns
two_word 3.1 ns 2.6 ns 2.5 ns 2.6 ns 2.6 ns
just_over_inline 3.0 ns 2.3 ns 2.1 ns 2.3 ns 2.8 ns
mid 3.9 ns 3.4 ns 3.2 ns 3.4 ns 4.7 ns
large 18.3 ns 17.7 ns 20.0 ns 20.1 ns 45.9 ns

ubig_cmp

class dashu ibig num malachite rug
zero 2.1 ns 1.0 ns 1.1 ns 1.5 ns 1.3 ns
one_word 2.1 ns 1.0 ns 1.3 ns 1.5 ns 1.8 ns
two_word 2.1 ns 1.8 ns 1.3 ns 2.7 ns 1.8 ns
just_over_inline 2.4 ns 1.8 ns 1.3 ns 2.7 ns 1.8 ns
mid 2.4 ns 1.8 ns 1.3 ns 2.7 ns 1.8 ns
large 2.5 ns 1.8 ns 1.3 ns 2.7 ns 1.8 ns

ubig_hash

class dashu ibig num malachite rug
zero 10.7 ns 11.9 ns 7.3 ns 11.2 ns 9.9 ns
one_word 12.9 ns 12.0 ns 11.7 ns 11.7 ns 12.0 ns
two_word 14.2 ns 13.8 ns 10.9 ns 13.9 ns 13.7 ns
just_over_inline 15.7 ns 15.5 ns 12.7 ns 15.5 ns 15.2 ns
mid 42.7 ns 44.9 ns 38.0 ns 42.7 ns 41.2 ns
large 355.4 ns 356.8 ns 351.8 ns 355.8 ns 353.6 ns

ubig_clone

class dashu ibig num malachite rug
zero 2.1 ns 1.0 ns 2.7 ns 1.0 ns 15.0 ns
one_word 2.1 ns 1.0 ns 15.3 ns 1.0 ns 14.8 ns
two_word 2.1 ns 20.6 ns 16.1 ns 16.0 ns 14.8 ns
just_over_inline 21.5 ns 21.6 ns 20.4 ns 20.3 ns 18.0 ns
mid 18.0 ns 17.4 ns 16.2 ns 16.8 ns 16.8 ns
large 34.7 ns 37.6 ns 33.1 ns 35.5 ns 32.9 ns

ibig_display_small

size dashu ibig num malachite rug
101.4 ns 101.9 ns 114.4 ns 59.8 ns 116.1 ns

ibig_from_str_small

size dashu ibig num malachite rug
39.5 ns 34.1 ns 74.2 ns 48.6 ns 111.3 ns

workload (generator/shrinker scenarios)

running_sum_and_compare

size dashu ibig num malachite rug
74.12 µs 71.89 µs 51.76 µs 219.60 µs 38.51 µs

running_sum_and_compare_small

size dashu ibig num malachite rug
64.62 µs 63.07 µs 45.56 µs 140.23 µs 37.81 µs

running_sum_and_compare_under_1kbit

size dashu ibig num malachite rug
65.40 µs 62.17 µs 47.12 µs 149.40 µs 37.67 µs

string_round_trip

size dashu ibig num malachite rug
2.29 ms 2.33 ms 3.16 ms 1.80 ms 1.97 ms

string_round_trip_under_1kbit

size dashu ibig num malachite rug
711.09 µs 719.28 µs 895.80 µs 682.15 µs 1.05 ms

bounded_arithmetic_mix

size dashu ibig num malachite rug
1.45 ms 1.49 ms 1.61 ms 1.38 ms 704.45 µs

bounded_arithmetic_mix_small

size dashu ibig num malachite rug
112.22 µs 144.55 µs 155.09 µs 136.08 µs 117.69 µs

bounded_arithmetic_mix_under_1kbit

size dashu ibig num malachite rug
117.57 µs 144.98 µs 152.56 µs 136.90 µs 117.95 µs

shrinker (property-based-testing shrinker operations)

ibig_clone

class dashu ibig num malachite rug
zero 2.1 ns 2.4 ns 2.7 ns 1.6 ns 15.1 ns
one_word 2.1 ns 2.4 ns 16.0 ns 1.6 ns 14.8 ns
two_word 2.2 ns 21.2 ns 16.3 ns 16.4 ns 14.8 ns
just_over_inline 22.0 ns 21.9 ns 20.7 ns 20.7 ns 18.0 ns
mid 18.3 ns 18.3 ns 16.8 ns 17.5 ns 17.0 ns
large 38.5 ns 35.9 ns 33.6 ns 36.4 ns 33.2 ns

choice_node_clone

class dashu ibig num malachite rug
one_word 10.0 ns 10.9 ns 50.8 ns 8.5 ns 58.9 ns
two_word 10.0 ns 62.6 ns 53.1 ns 51.5 ns 58.7 ns

ibig_drop

class dashu ibig num malachite rug
zero 2.1 ns 1.8 ns 2.7 ns 1.6 ns 16.9 ns
one_word 2.1 ns 1.8 ns 15.8 ns 1.6 ns 16.8 ns
two_word 2.1 ns 21.0 ns 22.2 ns 18.8 ns 16.7 ns
just_over_inline 21.6 ns 22.1 ns 26.7 ns 21.6 ns 20.1 ns
mid 18.0 ns 18.7 ns 16.9 ns 18.4 ns 19.0 ns
large 34.7 ns 35.6 ns 36.2 ns 38.0 ns 37.4 ns

ibig_sub_magnitude

class dashu ibig num malachite rug
one_word 6.2 ns 10.2 ns 38.1 ns 10.6 ns 23.0 ns
two_word 12.4 ns 34.4 ns 55.7 ns 39.5 ns 27.7 ns
just_over_inline 38.0 ns 35.1 ns 57.3 ns 52.2 ns 27.8 ns

ibig_clamp

class dashu ibig num malachite rug
one_word 10.4 ns 6.9 ns 54.2 ns 9.1 ns 55.0 ns
two_word 11.6 ns 68.1 ns 54.6 ns 58.8 ns 54.5 ns

ibig_double_cmp

class dashu ibig num malachite rug
one_word 2.7 ns 2.0 ns 1.9 ns 3.7 ns 2.8 ns
two_word 2.3 ns 2.6 ns 1.8 ns 4.0 ns 2.6 ns
just_over_inline 3.1 ns 2.6 ns 1.9 ns 4.6 ns 2.8 ns

ibig_from_const

size dashu_minus_one dashu_one dashu_zero ibig_minus_one ibig_one ibig_zero malachite_minus_one malachite_one malachite_zero num_minus_one num_one num_zero rug_minus_one rug_one rug_zero
1.8 ns 1.8 ns 1.8 ns 1.3 ns 1.5 ns 1.4 ns 1.4 ns 1.4 ns 1.4 ns 20.8 ns 20.8 ns 2.0 ns 15.8 ns 15.8 ns 2.8 ns

ubig_cmp_shrinker

class dashu ibig num malachite rug
one_word 2.1 ns 1.0 ns 1.4 ns 1.5 ns 1.6 ns
two_word 2.7 ns 1.8 ns 1.4 ns 2.7 ns 1.7 ns
just_over_inline 2.5 ns 1.9 ns 1.4 ns 2.7 ns 1.7 ns

ibig_shr_descent

class dashu ibig num malachite rug
one_word 41.4 ns 33.3 ns 329.5 ns 62.4 ns 233.6 ns
two_word 53.1 ns 379.4 ns 339.1 ns 359.7 ns 313.6 ns

shrinker_consider

size dashu ibig num malachite rug
4 180.8 ns 414.5 ns 354.1 ns 387.1 ns 495.2 ns
16 556.6 ns 507.7 ns 1.22 µs 573.3 ns 1.72 µs
64 1.90 µs 4.28 µs 5.99 µs 4.87 µs 6.93 µs

ubig_binary_search_step

class dashu ibig num malachite rug
one_word 23.9 ns 14.1 ns 84.3 ns 16.1 ns 79.5 ns
two_word 42.2 ns 104.0 ns 110.4 ns 85.3 ns 94.3 ns
just_over_inline 119.2 ns 111.0 ns 129.3 ns 96.3 ns 93.6 ns

ibig_hashmap_keys

class dashu ibig num malachite rug
one_word 19.7 ns 16.3 ns 17.6 ns 17.3 ns 15.4 ns
two_word 20.4 ns 21.5 ns 18.5 ns 24.2 ns 18.4 ns

from_index_full_search

case dashu ibig num malachite rug
frac_0pct 2.80 µs 6.71 µs 9.80 µs 6.67 µs 11.52 µs
frac_100pct 3.50 µs 14.42 µs 12.36 µs 12.66 µs 14.26 µs
frac_25pct 3.48 µs 14.30 µs 12.36 µs 12.59 µs 14.18 µs
frac_50pct 3.48 µs 14.30 µs 12.37 µs 12.61 µs 14.19 µs
frac_75pct 3.49 µs 14.39 µs 12.37 µs 12.61 µs 14.18 µs

ubig_ref_add

class dashu ibig num malachite rug
one_word 3.6 ns 13.9 ns 39.7 ns 10.7 ns 20.1 ns
two_word 22.9 ns 25.3 ns 51.3 ns 49.7 ns 33.1 ns
just_over_inline 28.7 ns 27.1 ns 55.6 ns 54.0 ns 31.1 ns

ubig_ref_sub

class dashu ibig num malachite rug
one_word 3.3 ns 1.7 ns 18.9 ns 2.9 ns 18.3 ns
two_word 3.3 ns 24.4 ns 19.5 ns 20.2 ns 35.1 ns
just_over_inline 27.1 ns 26.1 ns 24.8 ns 23.1 ns 33.3 ns

ibig_boundary_sort

size dashu ibig num malachite rug
9.74 µs 10.73 µs 19.46 µs 16.03 µs 17.53 µs

ubig_min

class dashu ibig num malachite rug
one_word 1.9 ns 1.0 ns 1.3 ns 1.6 ns 1.6 ns
two_word 1.9 ns 1.8 ns 1.3 ns 2.8 ns 1.6 ns

integer_choice_to_index

case dashu ibig num malachite rug
heap_range 33.8 ns 34.5 ns 57.0 ns 34.3 ns 73.1 ns
i128_range 36.8 ns 113.5 ns 138.3 ns 99.0 ns 148.0 ns

nodes_sort_key_lex_cmp

size dashu_differ_at_zero dashu_same_prefix ibig_differ_at_zero ibig_same_prefix malachite_differ_at_zero malachite_same_prefix num_differ_at_zero num_same_prefix rug_differ_at_zero rug_same_prefix
4 15.3 ns 44.8 ns 54.4 ns 28.1 ns 40.9 ns 31.2 ns 36.2 ns 113.4 ns 61.0 ns 136.3 ns
16 14.6 ns 148.7 ns 56.3 ns 79.4 ns 42.6 ns 73.7 ns 36.2 ns 308.9 ns 56.0 ns 393.2 ns
64 15.1 ns 532.0 ns 54.5 ns 336.0 ns 40.9 ns 307.8 ns 36.1 ns 1.11 µs 58.0 ns 1.43 µs

shrinker_descent_subtract

class dashu ibig num malachite rug
one_word 156.9 ns 104.2 ns 745.1 ns 151.6 ns 624.5 ns
two_word 157.0 ns 542.3 ns 768.5 ns 476.7 ns 723.7 ns

Adds `integer-bench`, a separate crate (excluded from the workspace) that
benchmarks dashu-int against other bigint libraries with criterion. Keeping
it out of the workspace means dashu-int's `--all-features` builds and MSRV
check never pull in the comparison libraries, and the bench crate can carry
its own newer toolchain requirement (malachite needs Rust 1.90).

Each criterion bench body is written once, generic over a `Backend` (see
integer-bench/src/lib.rs), and run for every backend with the backend name
as a `BenchmarkId` dimension — so one `cargo bench` run reports all
libraries side-by-side in one group. This revives the trait-based,
multi-library approach of the top-level `benchmark/` harness while emitting
criterion measurements.

Backends: dashu, ibig, num-bigint and malachite are always built (pure
Rust); rug (GNU GMP) is added under the `gmp` feature. Every backend samples
by drawing a dashu value and converting it, so magnitudes line up
point-for-point across libraries.

The abstraction:

* `BenchInt` — by-ref ops shared by the unsigned and signed types. Several
  libraries' by-ref operators return lazy incomplete values, so each op is a
  method (finalised to an owned value) rather than a std `Add`/`Sub`/...
  bound. The `*_assign` family has portable defaults; backends with a native
  `+=` override.
* `UnsignedInt` / `SignedInt` — primitive constructors / `+=` /
  `TryInto<i128>`. dashu/num/malachite/ibig have a `UBig`/`IBig`-style split;
  rug uses one signed type for both.
* `Backend` — picks the types + samplers, plus the `magnitude`
  (`unsigned_abs`/`abs`) and `unsigned_to_signed` bridges.
* `PrimitiveInt` / `PrimitiveBackend` — the bit-width sweep's extra surface
  (gcd, extended-gcd, pow, radix; each backend uses its native routine) plus
  modular arithmetic. The modular ops are like-for-like: `mod_mul` is plain
  multiply-then-reduce and `mod_pow` is each library's native one-shot modpow,
  with nothing precomputed.

Benches: `primitive` (bit-width sweep up to 10^4 bits), `small_int`,
`workload`, `shrinker`. The bit-width sweep stops at 10^4 bits — enough to
show the crossover where GMP-backed libraries pull ahead, without the very
large sizes. The workload/shrinker benches model a property-based-testing
generator and shrinker; their shapes were drawn from profiling hegel-rust
(https://github.com/DRMacIver/hegel) but are written to stand on their own.

CI gets a `smoke-test-integer-bench` job that builds the benches and runs
each once via criterion `--test` (no measurement, no numbers reported, since
CI is too noisy for real benchmarking), so the crate can't silently rot.
@cmpute

cmpute commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Thanks for putting up this benchmark! Unfortunately I don't plan to include a whole cross-comparison benchmark inside this repo. The benchmark in this repo is all for profiling. Apart from this, it's also greater for your benchmark to be independent, so that the results are more reproducible and creditable (like tczajka's https://github.com/tczajka/bigint-benchmark-rs)

@cmpute cmpute closed this Jun 1, 2026
@cmpute

cmpute commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Besides, I acknowledge that the library is falling short in large number mul/div, since I don't have a o(nlogn) multiplication algorithm implemented (which malachite has). It's in plan, but it takes time. (help on this is welcome :P)

@DRMacIver
DRMacIver deleted the benchmarks branch June 1, 2026 07:20
@DRMacIver

DRMacIver commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for putting up this benchmark! Unfortunately I don't plan to include a whole cross-comparison benchmark inside this repo. The benchmark in this repo is all for profiling. Apart from this, it's also greater for your benchmark to be independent, so that the results are more reproducible and creditable (like tczajka's https://github.com/tczajka/bigint-benchmark-rs)

Sure thing, completely reasonable! I've put it up as a standalone repo on my own github. https://github.com/DRMacIver/rust-bigint-benchmarks

Besides, I acknowledge that the library is falling short in large number mul/div, since I don't have a o(nlogn) multiplication algorithm implemented (which malachite has). It's in plan, but it takes time. (help on this is welcome :P)

Yup, understood. These benchmarks mostly weren't about that - they're about the small-integer regime where dashu already shines (because this was a lot of the regime where my workloads were heavy in, which is a lot of why I chose dashu in the first place!). The upper end is to show the crossover point, not because I think they're highlighting a serious deficiency in dashu.

It's in plan, but it takes time. (help on this is welcome :P)

More than happy to do this if you'd like. I was already considering it (it's not my main workload in hegel, but it does come up in places). It will be almost entirely LLM-generated work, but I'm confident that between testing against strong oracles and my own code review it can be high quality.

@cmpute

cmpute commented Jun 1, 2026

Copy link
Copy Markdown
Owner

@DRMacIver Thanks for your proposal! Let me try myself (It's also a case where I can learn more about agentic coding haha), if I failed I will get back to you for help (:P)

@DRMacIver

Copy link
Copy Markdown
Contributor Author

Sure thing! Good luck, and let me know if you'd like any advice / assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants