david-mollitor-db opened a new pull request, #59067:
URL: https://github.com/apache/spark/pull/59067

   ### What changes were proposed in this pull request?
   
   `Decimal` stores small values in a compact `long` (`decimalVal == null`) and 
only "expands" to a
   `java.math.BigDecimal` beyond 18 digits. Its arithmetic, however, boxed to 
BigDecimal more than
   necessary:
   
   - `Decimal.*` always computed 
`Decimal(toJavaBigDecimal.multiply(that.toJavaBigDecimal, MATH_CONTEXT))`,
     with no compact path.
   - `Decimal.+` / `Decimal.-` had a compact long path, but only when `scale == 
that.scale`; differing
     scales fell back to BigDecimal.
   
   So a row-level `a * b`, or a cross-scale `a + b`, on two compact operands 
allocated two operand
   `BigDecimal`s, a result `BigDecimal`, and its `BigInteger`.
   
   This adds compact long fast paths, mirroring the existing same-scale `+`/`-`:
   - `*` multiplies the unscaled longs directly when the exact product fits the 
18-digit compact
     range, guarded by an overflow-free `Math.multiplyHigh` check.
   - `+`/`-` align the lower-scale operand by `POW_10(diff)` (guarded exactly 
like `changePrecision`'s
     scale-up path) and add/subtract as longs.
   
   Both fall back to the existing BigDecimal path for non-compact operands or 
when the exact result
   leaves the compact range.
   
   ### Why are the changes needed?
   
   The fast paths avoid per-row `BigDecimal`/`BigInteger` allocation for the 
common small-decimal case
   (e.g. `decimal(7,2)` prices/amounts). Profiling a full TPC-DS v1.4 run 
(scale factor 10) with JFR,
   before vs. after:
   
   - `BigDecimal` allocations triggered by `Decimal.*` dropped ~93% (the 
remainder are the
     high-precision / overflow fallbacks).
   - Total sampled allocation dropped ~5.8%.
   
   This is an allocation / GC-pressure reduction (it also replaces 
`BigDecimal.multiply` with a `long`
   multiply on the hot path). On an unconstrained run it did not change 
end-to-end wall-clock beyond
   run-to-run noise; the benefit is reduced allocation, which matters most 
under memory pressure and
   high executor concurrency.
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. Results are byte-identical. The fast path only runs when the exact 
result fits the compact long
   range, where it has far fewer than `MATH_CONTEXT`'s 39 significant digits 
(so no rounding occurs);
   high-precision operands, including the SPARK-45786 multiply/divide case, 
stay on the BigDecimal
   path. Downstream `CheckOverflow` re-normalizes precision/scale exactly as 
before.
   
   ### How was this patch tested?
   
   - New `DecimalSuite` test sweeping a grid of `(unscaled, scale)` operands — 
including values whose
     exact result lands just under and just over the compact range, exercising 
both the fast path and
     the fallback — asserting `+`/`-`/`*` on compact operands match the 
BigDecimal path on both value
     and scale.
   - Existing `DecimalSuite`, `ArithmeticExpressionSuite` (including the 
SPARK-45786 cases), and
     `DecimalExpressionSuite` pass.
   - Allocation impact measured via JFR on a full TPC-DS v1.4 (SF10) run, as 
above.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Isaac
   
   This pull request and its description were written by Isaac.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to