leonardo ([info]leonardo_m) wrote,
@ 2009-02-03 14:56:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Entry tags:benchmark, java, programming, python

Multiprecision integers
Built-in Python multiprecision integers (long) are handy but they aren't know for their speed. If you want speed you usually go with GMPY (http://gmpy.sourceforge.net/ ). I was curious to see how much slower are such numbers compared to the BigInteger of a common JavaVM.

So I have compared the multiplication efficienty (I think mutiplications aren't done much efficiently in Python long) with a basic program:

// Java code
import java.math.BigInteger;
public class Fact {
    public static void main() {
        BigInteger n = BigInteger.ONE;
        for (int i = 1; i <= 20000; i++)
            n = n.multiply(BigInteger.valueOf(i));
    }
}


// Python code #1
def main():
    n = 1
    for i in xrange(1, 20000+1):
        n *= i
main()


// Python code #2
from gmpy import mpz
def main():
    n = mpz(1)
    for i in xrange(1, 20000+1):
        n *= i
main()


// Python code #3
from gmpy import mpz
import psyco
def main():
    n = mpz(1)
    for i in xrange(1, 20000+1):
        n *= i
psyco.bind(main)
main()


// Python code #4
from gmpy import fac
fac(20000)


// D + Tango
import tango.math.BigInt: BigInt;
void main() {
    BigInt n = "1";
    for (int i = 1; i <= 20_000; i++)
        n *= i;
}

Timings:
  Java:    15.59 s
  Python1:  4.51 s
  D:        4.20 s 
  Python2:  1.66 s
  Python3:  1.23 s  
  Python4:  0.31 s

Notes on the D code:
- At the end the number 'n' is represented in 32116 bytes.
- I'd like to initialize n with a normal integral value, and not a string: BigInt n = 1;
- To print n you have to use (on Tango) something like: Cout(n.toDecimalString).newline; this is ugl, it needs a toString() for simple purposes (plus other things for more complex purposes).

CPU used: Pentium III 500 MHz.

VM/compiler/libs used:
- Python 2.5.2
- GMPY V.1.02
- java version "1.6.0_10"
- LDC D compiler with V.0.9 (rev 877) based on DMD v1.039 and llvm 2.4, with Tango.

The results of Python1 vs Java have surprised me, is someone able to explain them?



(7 comments) - (Post a new comment)


(Anonymous)
2009-02-03 04:51 pm UTC (link)
Can you please provide full sources of the benchmark (in particular, Java timing code)? Do you use server or client VM? How much times is this test executed? For Java JIT to work, you have to warm it up.

(Reply to this) (Thread)


[info]leonardo_m
2009-02-03 05:04 pm UTC (link)
The code I have shown is all the source code I have used.
To time the source code I have just used (on Ubuntu 8.10):
time java Fact
So I presume it's client.
I have run it 3+ times, but I have seen no much difference in timing from the first to the last run.
Nearly all the running time is spent in the BigInteger.multiply so I presume jitting the main doesn't change results much.
If you have Python and Java installed you can use that code to reproduce (or not reproduce) those timings in 3 minutes, about the time you need to read my answer :-)
Note that I hope to be in some way wrong, because I'd like to use Java too for such purposes.

(Reply to this) (Parent)(Thread)


(Anonymous)
2009-02-05 10:37 pm UTC (link)
Well a little tip here is that to make the hotspot compiler run right you'd have to loop over your factorial code giving it several passes to work with. My results and in this case I exclude the runtime start up and shut down by timing within Java (because honestly who gives a crap about vm startup in production code) and on a single processor of my arguably fast machine it ran with an average of 998 milliseconds for the client 1.6.0_10 VM and 997 milliseconds for the server 1.6.0_10 VM.

I'll have to try the factorial using phobos on dmd 1.39 soonish.

(Reply to this) (Parent)(Thread)


[info]leonardo_m
2009-02-05 11:15 pm UTC (link)
(because honestly who gives a crap about vm startup in production code)

Generalizations are often silly or wrong. If my 'production code' works correctly and it has a running time of 5 minutes or 5 hours, then I agree that startup time isn't interesting.

But if I want to create some utility program that may have 5-10 seconds of total running time, then a fast start up is important. I have created many of such programs.

A fast start up is also useful for unit testing: I have a "large" D code (about 60000 lines or more) that has thousands of unit tests. Despite their number, all such such tests run in a bit more than on second on a 2 GHz Core Duo CPU. The DMD D compiler is also quite fast, compiling all such code in very few seconds. In such situation having a slow startup time isn't good, it may slow down your unit testing.

(Reply to this) (Parent)


(Anonymous)
2009-02-03 06:04 pm UTC (link)
It would be interesting to see how fast D/tango performs when using the optimized asm version, which isn't used with the 0.9 release of ldc (I hear it is supported in the most recent ldc revisions).

(Reply to this) (Thread)


[info]leonardo_m
2009-02-03 06:19 pm UTC (link)
I agree. But I've used the version they have offered me, when they will release something better I'll use it... I may also try DMD (on Ubuntu still) that probably uses the ASM code.

(Reply to this) (Parent)


[info]h3r3tic.myopenid.com
2009-02-03 06:46 pm UTC (link)
I'm getting 1.09 sec for "Python2" (with GMPY 1.04, Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]) and 1.18 sec for the D version on Centrino 1.7 @ 594MHz, WinXP, DMD 1.039, Tango rev. 4277.

(Reply to this)


(7 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…