Skip to content

perf: Improve decimal addition and subtraction when scale is equal #10333

Merged
Jefffrey merged 2 commits into
apache:mainfrom
AdamGS:adamg/improve-i256-decimal-perf
Jul 14, 2026
Merged

perf: Improve decimal addition and subtraction when scale is equal #10333
Jefffrey merged 2 commits into
apache:mainfrom
AdamGS:adamg/improve-i256-decimal-perf

Conversation

@AdamGS

@AdamGS AdamGS commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

  • Closes #NNN.

Rationale for this change

For cases where adding or subtracting decimal values that have the same scale, we end up doing a bunch of extra checked mul operations, and turns out if we don't it improves performance significantly.

What changes are included in this PR?

  1. Specialize add/sub for decimals when they have the same scale.
  2. Benchmark to measure the impact on all decimals types.

Are these changes tested?

Existing tests, 1 additional test I added to i256 which was my original target.

Are there any user-facing changes?

None

@github-actions github-actions Bot added the arrow Changes to the arrow crate label Jul 13, 2026
@AdamGS

AdamGS commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

On my laptop, from 40% improvement for decimal32 and up to 80% on decimal 256:

decimal32_equal_scale/add
                        time:   [630.04 ns 630.58 ns 631.29 ns]
                        thrpt:  [1.6221 Gelem/s 1.6239 Gelem/s 1.6253 Gelem/s]
                 change:
                        time:   [−43.418% −43.295% −43.187%] (p = 0.00 < 0.05)
                        thrpt:  [+76.016% +76.352% +76.736%]
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) low mild
  5 (5.00%) high mild
  2 (2.00%) high severe
decimal32_equal_scale/sub
                        time:   [630.33 ns 630.63 ns 630.98 ns]
                        thrpt:  [1.6229 Gelem/s 1.6238 Gelem/s 1.6245 Gelem/s]
                 change:
                        time:   [−43.643% −43.516% −43.400%] (p = 0.00 < 0.05)
                        thrpt:  [+76.678% +77.042% +77.441%]
                        Performance has improved.
Found 16 outliers among 100 measurements (16.00%)
  13 (13.00%) high mild
  3 (3.00%) high severe

decimal32_different_scale/add
                        time:   [1.1945 µs 1.1951 µs 1.1957 µs]
                        thrpt:  [856.40 Melem/s 856.84 Melem/s 857.23 Melem/s]
                 change:
                        time:   [+0.1629% +0.8429% +1.5190%] (p = 0.02 < 0.05)
                        thrpt:  [−1.4963% −0.8359% −0.1626%]
                        Change within noise threshold.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) low severe
  1 (1.00%) low mild
  1 (1.00%) high mild
  5 (5.00%) high severe
decimal32_different_scale/sub
                        time:   [1.1870 µs 1.1886 µs 1.1900 µs]
                        thrpt:  [860.50 Melem/s 861.53 Melem/s 862.69 Melem/s]
                 change:
                        time:   [+1.5117% +1.9507% +2.3788%] (p = 0.00 < 0.05)
                        thrpt:  [−2.3235% −1.9134% −1.4892%]
                        Performance has regressed.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low severe
  7 (7.00%) high mild
  1 (1.00%) high severe

decimal64_equal_scale/add
                        time:   [639.33 ns 642.21 ns 645.03 ns]
                        thrpt:  [1.5875 Gelem/s 1.5945 Gelem/s 1.6017 Gelem/s]
                 change:
                        time:   [−45.814% −45.629% −45.466%] (p = 0.00 < 0.05)
                        thrpt:  [+83.371% +83.923% +84.549%]
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
decimal64_equal_scale/sub
                        time:   [629.79 ns 630.77 ns 632.16 ns]
                        thrpt:  [1.6198 Gelem/s 1.6234 Gelem/s 1.6259 Gelem/s]
                 change:
                        time:   [−46.014% −45.884% −45.727%] (p = 0.00 < 0.05)
                        thrpt:  [+84.253% +84.790% +85.234%]
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe

decimal64_different_scale/add
                        time:   [1.1947 µs 1.1960 µs 1.1978 µs]
                        thrpt:  [854.92 Melem/s 856.21 Melem/s 857.12 Melem/s]
                 change:
                        time:   [+2.3087% +2.6107% +2.9771%] (p = 0.00 < 0.05)
                        thrpt:  [−2.8910% −2.5443% −2.2566%]
                        Performance has regressed.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  6 (6.00%) high severe
decimal64_different_scale/sub
                        time:   [1.2057 µs 1.2108 µs 1.2157 µs]
                        thrpt:  [842.30 Melem/s 845.74 Melem/s 849.27 Melem/s]
                 change:
                        time:   [+1.6586% +1.9491% +2.2576%] (p = 0.00 < 0.05)
                        thrpt:  [−2.2077% −1.9119% −1.6315%]
                        Performance has regressed.
Found 14 outliers among 100 measurements (14.00%)
  11 (11.00%) high mild
  3 (3.00%) high severe

decimal128_equal_scale/add
                        time:   [763.21 ns 765.54 ns 767.91 ns]
                        thrpt:  [1.3335 Gelem/s 1.3376 Gelem/s 1.3417 Gelem/s]
                 change:
                        time:   [−72.061% −71.976% −71.891%] (p = 0.00 < 0.05)
                        thrpt:  [+255.76% +256.84% +257.92%]
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  9 (9.00%) low mild
  5 (5.00%) high mild
  1 (1.00%) high severe
decimal128_equal_scale/sub
                        time:   [765.55 ns 767.56 ns 769.39 ns]
                        thrpt:  [1.3309 Gelem/s 1.3341 Gelem/s 1.3376 Gelem/s]
                 change:
                        time:   [−72.614% −72.438% −72.274%] (p = 0.00 < 0.05)
                        thrpt:  [+260.68% +262.82% +265.15%]
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

decimal128_different_scale/add
                        time:   [2.7359 µs 2.7407 µs 2.7465 µs]
                        thrpt:  [372.84 Melem/s 373.63 Melem/s 374.28 Melem/s]
                 change:
                        time:   [−1.5850% −1.3380% −1.0742%] (p = 0.00 < 0.05)
                        thrpt:  [+1.0859% +1.3561% +1.6106%]
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  7 (7.00%) high severe
decimal128_different_scale/sub
                        time:   [2.7348 µs 2.7378 µs 2.7412 µs]
                        thrpt:  [373.55 Melem/s 374.03 Melem/s 374.44 Melem/s]
                 change:
                        time:   [−1.8846% −1.6337% −1.3612%] (p = 0.00 < 0.05)
                        thrpt:  [+1.3800% +1.6608% +1.9208%]
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  4 (4.00%) low mild
  3 (3.00%) high severe

decimal256_equal_scale/add
                        time:   [1.5181 µs 1.5189 µs 1.5198 µs]
                        thrpt:  [673.79 Melem/s 674.15 Melem/s 674.52 Melem/s]
                 change:
                        time:   [−86.348% −86.331% −86.315%] (p = 0.00 < 0.05)
                        thrpt:  [+630.71% +631.57% +632.50%]
                        Performance has improved.
decimal256_equal_scale/sub
                        time:   [1.4986 µs 1.5010 µs 1.5041 µs]
                        thrpt:  [680.79 Melem/s 682.20 Melem/s 683.31 Melem/s]
                 change:
                        time:   [−86.498% −86.478% −86.457%] (p = 0.00 < 0.05)
                        thrpt:  [+638.38% +639.55% +640.61%]
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high severe

decimal256_different_scale/add
                        time:   [11.071 µs 11.079 µs 11.090 µs]
                        thrpt:  [92.337 Melem/s 92.429 Melem/s 92.490 Melem/s]
                 change:
                        time:   [−0.9168% −0.6735% −0.4525%] (p = 0.00 < 0.05)
                        thrpt:  [+0.4545% +0.6781% +0.9253%]
                        Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) low severe
  2 (2.00%) low mild
  1 (1.00%) high severe
decimal256_different_scale/sub
                        time:   [11.095 µs 11.101 µs 11.109 µs]
                        thrpt:  [92.178 Melem/s 92.247 Melem/s 92.291 Melem/s]
                 change:
                        time:   [−0.5163% −0.3530% −0.2031%] (p = 0.00 < 0.05)
                        thrpt:  [+0.2035% +0.3542% +0.5190%]
                        Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
  1 (1.00%) low severe
  3 (3.00%) high mild
  2 (2.00%) high severe

@Jefffrey Jefffrey merged commit e097ebe into apache:main Jul 14, 2026
15 checks passed
@Jefffrey

Copy link
Copy Markdown
Contributor

thanks @AdamGS

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

Labels

arrow Changes to the arrow crate performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants