jsr354-ri icon indicating copy to clipboard operation
jsr354-ri copied to clipboard

Generic Performance of JavaMoney is really poor.

Open dusinof opened this issue 4 years ago • 7 comments

Hi,

I've wrote simple JMH Benchmark, where i do some basic mathematical operations such as Sum, Subtraction, multiply. As a baseline comparison, I have used Long & BigDecimal. As is it obvious from result JavaMoney is really slow. Autors claiming, that FastMoney is faster then Money, which is correct, but their perf. test was made of combination of several operations and isn't clear which one is slowest. Moreover simple getNumber take way too long time. As of now, current implementation isn't usable with larger data and multiple operation over them. The bigger number in column score = better performance. Test can be downloaded/cloned from: JMH Benchmark jsr354

SUM (ADD)

Tested operation type iterations score ± error units
FastMoneyJMHBenchmark.sumLong thrpt 8 342137320.860 ± 19472436.281 ops/s
FastMoneyJMHBenchmark.sumBigDecima thrpt 8 105907904.881 ± 3427247.163 ops/s
FastMoneyJMHBenchmark.sumFastMoney thrpt 8 4844581.765 ± 34323.583 ops/s
FastMoneyJMHBenchmark.sumMoney thrpt 8 6007129.183 ± 130031.490 ops/s

SUB

Tested operation type iterations score ± error units
FastMoneyJMHBenchmark.subLong thrpt 8 304901576.783 ± 2471383.402 ops/s
FastMoneyJMHBenchmark.subBigDecimal thrpt 8 105429043.648 ± 1002220.596 ops/s
FastMoneyJMHBenchmark.subFastMoney thrpt 8 4616496.583 ± 94780.114 ops/s
FastMoneyJMHBenchmark.subMoney thrpt 8 7794551.863 ± 242923.465 ops/s

Multiply

Tested operation type iterations score ± error units
FastMoneyJMHBenchmark.multiplyLong thrpt 8 248980561.211 ± 7163665.297 ops/s
FastMoneyJMHBenchmark.multiplyBigDecimalDirect thrpt 8 94829894.529 ± 22297255.801 ops/s
FastMoneyJMHBenchmark.multiplyFastMoneyDirect thrpt 8 12481509.586 ± 1552664.606 ops/s
FastMoneyJMHBenchmark.multiplyFastMoneyGetNumber thrpt 8 3562015.108 ± 150713.383 ops/s
FastMoneyJMHBenchmark.multiplyMoneyDirect thrpt 8 5914833.476 ± 2347892.192 ops/s
FastMoneyJMHBenchmark.multiplyMoneyGetNumber thrpt 8 5012949.055 ± 653692.340 ops/s

Not reliable test from jsr354 docs.

Tested operation type iterations score ± error units
FastMoneyJMHBenchmark.javaFastMoneyNotReliableTest thrpt 8 555236.917 ± 1958.258 ops/s
FastMoneyJMHBenchmark.javaMoneyNotReliableTest thrpt 8 73767.930 ± 480.383 ops/s
FastMoneyJMHBenchmark.javaCombinationNotReliableTest thrpt 8 71446.888 ± 6581.344 ops/s

Link to Not reliable test

dusinof avatar Nov 18 '19 09:11 dusinof

There is a lot of places for improvement here but I guess it will be better to fix all bugs and implement needed features first. From what I saw there is a lot of places where can be omitted creation of a garbage. Another problem is that each the Money instance consumes a lot of memory. There is a ticket #260 so maybe your benchmark can be transfered or forked to the JavaMoney organization.

stokito avatar Nov 19 '19 00:11 stokito

Thanks for those performance reports. If you're happy to contribute them we would appreciate integrating them (here or other JSR 354 deliverables require a JCP membership, in most other places of the wider JavaMoney community this should not be necessary)

Note, while updating reports maybe also improvements to classes like FastMoney are certainly possible, the RI Moneta is a free of charge Open Source implementation much like Glassfish for Java EE or Jakarta EE. It does not aim at Real Time Performance or trading, you would require at least a special JVM environment using Java Realtime JSRs or other frameworks like Javolution and possibly a dedicated improved implementation of JSR 354. Also see above, thanks for linking them. A performance optimized JVM may help and for everything beyond that, it likely requires a special implementation by commercial vendors. Similar to what e.g. Payara did with Glassfish or Tomitribe with Apache Tomcat. It is not currently in scope for the RI.

keilw avatar Nov 19 '19 00:11 keilw

Feel free to do whatever you need with them. They are really simple ones. I can run some profiling with Jprofiler or other tools to see, which operation consume more resources than it needed to.

dusinof avatar Nov 19 '19 13:11 dusinof

Ok thanks, but note, this is not relevant for the MR1 which we plan to release before the end of the year (or whenever the newly elected JCP EC can vote) but for a follow-up JSR or service releases of Moneta as well as accompanying tools.

keilw avatar Nov 21 '19 10:11 keilw

Btw, it would be interesting to also compare Moneta to JodaMoney although that seems a bit unmaintained with the last change over 6 months ago, but at least some projects (mostly academic or PoC though it seems) use it and it is probably the only other Java library with a few similar goals. Judging from the Money class being backed by BigMoney internally, I doubt you'll find much difference among them and they are impossible to extend or implement (so you either use them as is or throw away unlike JSR 354) but it would be nice to also include them in a performance measurement if possible.

keilw avatar Nov 21 '19 10:11 keilw

What do you think of switching from BigDecimal to something like Decimal4j https://github.com/tools4j/decimal4j?files=1 I don’t know the library very well but it might be faster than BigDecimal and supports up to 18 decimal points if this kind of precision is required

kevin0x90 avatar Apr 23 '20 20:04 kevin0x90

That's certainly not in scope for the upcoming MR1. We could think of something like extending the "pluggable" type system (with the NumberType abstraction the JSR already is flexible and not tied to BigDecimal unlike JodaMoney ;-) further, but that is for a future version and likely in an even more modular fashion. Whether this Decimal4J or Apache Commons Numbers (which I believe is about to release in the near future) we should evaluate and compare candidates not only for their performance.

keilw avatar Apr 23 '20 21:04 keilw