[IronPython] More Performance comparisons - dictionary updates and tuples

Michael Foord fuzzyman at voidspace.org.uk
Wed Apr 16 10:32:36 PDT 2008


Hello guys,

I've been looking at performance in Resolver One. (Object creation in 
IronPython seems to be really good whereas dictionary lookups not so 
good when we compare against CPython.)

It turns out that we are getting bitten quite badly by the performance 
of hashing tuples (fixing this for IP 1.1.2 would be *great*). I did 
some profiling and have some comparisons - and can also show a 
regression in performance in IP 2 (Beta 1) when using ints as dictionary 
keys in an update operation. I thought I would post the results as they 
may be useful.

(Dictionary update in IP 1 with tuple keys is an order of magnitude 
slower than CPython. So is IP 2 but still twice as good as IP 1 - two 
times *worse* than IP 1 for tuple creating and unpacking though.)

Results first:

CPython
e:\Dev>timeit1.py
tuple_create_and_unpack took 220.999956131 ms
dict_update took 541.000127792 ms


IP 1.1.1
e:\Dev>e:\Dev\ironpython1\ipy.exe timeit1.py
tuple_create_and_unpack took 680.9792 ms
dict_update took 7891.3472 ms


IP 2 Beta 1
e:\Dev>e:\Dev\ironpython2\ipy.exe timeit1.py
tuple_create_and_unpack took 1341.9296 ms
dict_update took 4756.84 ms


If we switch to using integers rather than tuples for the dictionary 
keys, the performance changes:

CPython
e:\Dev>timeit1.py
tuple_create_and_unpack took 200.000047684 ms
dict_update took 230.999946594 ms


IP 1.1.1
e:\Dev>e:\Dev\ironpython1\ipy.exe timeit1.py
tuple_create_and_unpack took 911.3104 ms
dict_update took 420.6048 ms


IP 2 Beta 1
e:\Dev>e:\Dev\ironpython2\ipy.exe timeit1.py
tuple_create_and_unpack took 971.3968 ms
dict_update took 1582.2752 ms


With ints as keys, IP 1 is only half the speed of CPython - but IP 2 is 
four times slower than IP 1!

The code used - which runs under both CPython and IronPython


from random import random

try:
    import clr
    from System import DateTime
   
    def timeit(func):
        start = DateTime.Now
        func()
        end = DateTime.Now
        print func.__name__, 'took %s ms' % (end - start).TotalMilliseconds
       
except ImportError:   
    import time

    def timeit(func):
        start = time.time()
        func()
        end = time.time()
        print func.__name__, 'took %s ms' %  ((end - start) * 1000)


def tuple_create_and_unpack():
    for val in range(1000000):
        a, b = val, val + 1

d1 = {}
for x in range(100):
    for y in range(100):
        d1[x, y] = random()
       
d2 = {}
for x in range(1000):
    for y in range(1000):
        d2[x, y] = random()

def dict_update():
    d1.update(d2)
   
timeit(tuple_create_and_unpack)
timeit(dict_update)


Michael Foord
http://www.ironpythoninaction.com/


More information about the Users mailing list