moneyphp / money

PHP implementation of Fowler's Money pattern.
http://moneyphp.org
MIT License
4.56k stars 439 forks source link

Optimize result representation for BcMathCalculator #748

Closed bcremer closed 1 year ago

bcremer commented 1 year ago

Optimize the result representation of some BcMathCalculator operations for faster usage in \Money\Money::__construct.

This will provide a 50% performance boost for some operations.

> vendor/bin/phpbench run --retry-threshold=3 --iterations=15 --revs=1000  --warmup=2 'benchmark/MoneyOperationBench.php' '--ref=before_bcmath_scale'
PHPBench (1.2.10) running benchmarks... #standwithukraine
with configuration file: /home/pushapidev/current/moneyphp/phpbench.json
with PHP version 8.1.17, xdebug ✔, opcache ✔
comparing [actual vs. before_bcmatch_scale]

\Benchmark\Money\MoneyOperationBench

    benchAdd................................R4 I9 - [Mo0.298μs vs. Mo0.610μs] -51.12% (±0.63%)
    benchSubtract...........................R1 I5 - [Mo0.298μs vs. Mo0.611μs] -51.34% (±1.04%)
    benchMultiply...........................R1 I12 - [Mo0.622μs vs. Mo0.629μs] -1.16% (±1.30%)
    benchDivide.............................R1 I13 - [Mo0.731μs vs. Mo0.726μs] +0.67% (±1.08%)
    benchSum................................R1 I12 - [Mo0.646μs vs. Mo1.063μs] -39.23% (±0.65%)
    benchMin................................R1 I14 - [Mo0.494μs vs. Mo0.493μs] +0.11% (±1.01%)
    benchMax................................R1 I6 - [Mo0.509μs vs. Mo0.512μs] -0.48% (±0.74%)
    benchAvg................................R1 I3 - [Mo1.462μs vs. Mo1.822μs] -19.79% (±1.40%)
    benchRatioOf............................R1 I0 - [Mo0.365μs vs. Mo0.349μs] +4.68% (±1.99%)
    benchMod................................R6 I13 - [Mo0.382μs vs. Mo0.383μs] -0.48% (±1.06%)
    benchIsSameCurrency.....................R1 I6 - [Mo0.059μs vs. Mo0.060μs] -1.88% (±1.31%)
    benchIsZero.............................R1 I11 - [Mo0.106μs vs. Mo0.105μs] +0.25% (±1.22%)
    benchAbsolute...........................R3 I14 - [Mo0.157μs vs. Mo0.157μs] -0.27% (±1.18%)
    benchNegative...........................R1 I9 - [Mo0.392μs vs. Mo0.710μs] -44.84% (±0.90%)
    benchIsPositive.........................R2 I6 - [Mo0.102μs vs. Mo0.102μs] -0.03% (±0.86%)
    benchCompare............................R3 I14 - [Mo0.133μs vs. Mo0.133μs] +0.06% (±0.98%)
    benchLessThan...........................R2 I3 - [Mo0.149μs vs. Mo0.149μs] -0.07% (±0.75%)
    benchLessThanOrEqual....................R2 I8 - [Mo0.149μs vs. Mo0.149μs] -0.01% (±1.25%)
    benchEquals.............................R1 I4 - [Mo0.169μs vs. Mo0.169μs] +0.13% (±0.93%)
    benchGreaterThan........................R1 I7 - [Mo0.149μs vs. Mo0.149μs] +0.11% (±1.60%)
    benchGreaterThanOrEqual.................R1 I14 - [Mo0.149μs vs. Mo0.149μs] +0.28% (±1.28%)

Subjects: 21, Assertions: 0, Failures: 0, Errors: 0

For full history: https://github.com/moneyphp/money/pull/747

bcremer commented 1 year ago

@Ocramius You implemented Tests\Money\Calculator\LocaleAwareBcMathCalculatorTest::itUsesScaleForSubtract \Tests\Money\Calculator\BcMathCalculatorTest::itUsesScaleForSubtract

Both are currently failing with my changes.

From my understanding \Money\Calculator\BcMathCalculator::add should only be called with int like strings and never with float like strings. Also the \Tests\Money\Calculator\CalculatorTestCase only uses positive-int for inputs.

Ocramius commented 1 year ago

@bcremer changes seem to indicate that removing the scale broke everything in the test suite?

bcremer commented 1 year ago

It's only the explicit itUsesScale* tests that fail. All other real-world tests are running fine. The test was introduced by @frederikbosch in https://github.com/moneyphp/money/pull/528/files but the implementation changed quite a bit some time ago.

frederikbosch commented 1 year ago

@bcremer I cannot recall or see why I would have done that. Maybe it was some preliminary work for PreciseMoney, a project that never made the finish line. If no other fails, I think it is fine to change the scale to zero for add and subtract operations.

frederikbosch commented 1 year ago

Hmm, maybe @Ocramius is right. In the end of the day this is a performance patch. It should deal with all features in the library.

bcremer commented 1 year ago

I see your point. I pushed a solution that will speedup the "real world path" as well as maintain the public api.

This will still result in a 50% improvement for certain operations:

comparing [actual vs. before_bcmath_scale]

\Benchmark\Money\MoneyOperationBench

    benchAdd................................R5 I14 - [Mo0.324μs vs. Mo0.646μs] -49.89% (±0.52%)
    benchSubtract...........................R1 I4 - [Mo0.323μs vs. Mo0.648μs] -50.24% (±0.60%)
    benchMultiply...........................R1 I12 - [Mo0.670μs vs. Mo0.670μs] -0.00% (±1.14%)
    benchDivide.............................R1 I7 - [Mo0.775μs vs. Mo0.780μs] -0.65% (±0.98%)
    benchSum................................R1 I9 - [Mo0.713μs vs. Mo1.072μs] -33.54% (±0.98%)
    benchMin................................R1 I6 - [Mo0.513μs vs. Mo0.518μs] -0.88% (±1.29%)
    benchMax................................R1 I3 - [Mo0.527μs vs. Mo0.530μs] -0.60% (±1.10%)
    benchAvg................................R1 I0 - [Mo1.596μs vs. Mo1.936μs] -17.59% (±1.10%)
    benchRatioOf............................R1 I4 - [Mo0.359μs vs. Mo0.358μs] +0.45% (±0.47%)
    benchMod................................R4 I13 - [Mo0.396μs vs. Mo0.394μs] +0.50% (±1.15%)
    benchIsSameCurrency.....................R1 I6 - [Mo0.061μs vs. Mo0.061μs] +0.01% (±0.97%)
    benchIsZero.............................R1 I3 - [Mo0.108μs vs. Mo0.109μs] -0.72% (±1.07%)
    benchAbsolute...........................R4 I11 - [Mo0.161μs vs. Mo0.163μs] -1.09% (±0.86%)
    benchNegative...........................R2 I10 - [Mo0.422μs vs. Mo0.755μs] -44.15% (±0.81%)
    benchIsPositive.........................R1 I13 - [Mo0.108μs vs. Mo0.107μs] +0.98% (±1.05%)
    benchCompare............................R1 I13 - [Mo0.134μs vs. Mo0.135μs] -1.05% (±1.27%)
    benchLessThan...........................R5 I11 - [Mo0.154μs vs. Mo0.154μs] +0.02% (±1.07%)
    benchLessThanOrEqual....................R2 I5 - [Mo0.154μs vs. Mo0.154μs] +0.34% (±0.99%)
    benchEquals.............................R1 I8 - [Mo0.174μs vs. Mo0.174μs] -0.04% (±1.02%)
    benchGreaterThan........................R5 I13 - [Mo0.154μs vs. Mo0.154μs] +0.07% (±1.07%)
    benchGreaterThanOrEqual.................R1 I12 - [Mo0.154μs vs. Mo0.155μs] -0.88% (±0.70%)
frederikbosch commented 1 year ago

I think this good to go, @Ocramius approved?

frederikbosch commented 1 year ago

Thanks @bcremer for your effort and PR for the optimization. @Ocramius thanks for your feedback!