jsr354-ri
jsr354-ri copied to clipboard
Generic Performance of JavaMoney is really poor.
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
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.
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.
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.
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.
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.
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
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.