2.5 slower than 2.4 for some things?
I've had a report from a user that Plex runs about half as fast in 2.5 as it did in 2.4. In particular, the NFA-to-DFA conversion phase, which does a lot of messing about with dicts representing mappings between sets of states. Does anyone in the Ministry for Making Python Blazingly fast happen to know of some change that might have pessimised things in this area? -- Greg
I've had a report from a user that Plex runs about half as fast in 2.5 as it did in 2.4. In particular, the NFA-to-DFA conversion phase, which does a lot of messing about with dicts representing mappings between sets of states.
Does anyone in the Ministry for Making Python Blazingly fast happen to know of some change that might have pessimised things in this area?
Hello, I investigated. On my environment, consumed time is E:\Plex-1.1.5>py24 plex_test2.py 0.710999965668 E:\Plex-1.1.5>py25 plex_test2.py 0.921999931335 And after I applied this patch to Plex/Machines, (make `Node' new style class) 62c62 < class Node: ---
class Node(object):
E:\Plex-1.1.5>py24 plex_test2.py 0.401000022888 E:\Plex-1.1.5>py25 plex_test2.py 0.350999832153 So, probably hash, comparation mechanizm of old/new style class has changed. # improved for new style class, worse for old style class. Maybe optimized for new style class? Try this for minimum test. import timeit init = """ class Class: pass c1 = Class() c2 = Class() """ t1 = timeit.Timer(""" c1 < c2 """, init) t2 = timeit.Timer(""" hash(c1) hash(c2) """, init) print t1.timeit(1000) print t2.timeit(1000)
ocean wrote:
So, probably hash, comparation mechanizm of old/new style class has changed. # improved for new style class, worse for old style class. Maybe optimized for new style class?
Thanks -- it looks like there's a simple solution that will make Plex even faster! I'll pass this on to the OP. -- Greg
ocean wrote:
I've had a report from a user that Plex runs about half as fast in 2.5 as it did in 2.4. In particular, the NFA-to-DFA conversion phase, which does a lot of messing about with dicts representing mappings between sets of states.
That was me.
Does anyone in the Ministry for Making Python Blazingly fast happen to know of some change that might have pessimised things in this area?
Hello, I investigated. On my environment, consumed time is
E:\Plex-1.1.5>py24 plex_test2.py 0.710999965668
E:\Plex-1.1.5>py25 plex_test2.py 0.921999931335
And after I applied this patch to Plex/Machines, (make `Node' new style class)
62c62 < class Node: ---
class Node(object):
E:\Plex-1.1.5>py24 plex_test2.py 0.401000022888
E:\Plex-1.1.5>py25 plex_test2.py 0.350999832153
Nice!. Meanwhile I tried to replace the parsing I did with Plex by re.Scanner. And again there is a remarkable speed difference. Again python2.5 is slower: try: from re import Scanner except: from sre import Scanner pars = {} order = [] count = 0 def par(scanner,name): global count, order, pars if name in ['caller','e','pi']: return name if name not in pars.keys(): pars[name] = ('ns', count) order.append(name) ret = 'a[%d]'%count count += 1 else: ret = 'a[%d]'%(order.index(name)) return ret scanner = Scanner([ (r"x", lambda y,x: x), (r"[a-zA-Z]+\.", lambda y,x: x), (r"[a-z]+\(", lambda y,x: x), (r"[a-zA-Z_]\w*", par), (r"\d+\.\d*", lambda y,x: x), (r"\d+", lambda y,x: x), (r"\+|-|\*|/", lambda y,x: x), (r"\s+", None), (r"\)+", lambda y,x: x), (r"\(+", lambda y,x: x), (r",", lambda y,x: x), ]) import profile import pstats def run(): arg = '+amp*exp(-(x-pos)/fwhm)' for i in range(100): scanner.scan(arg) profile.run('run()','profscanner') p = pstats.Stats('profscanner') p.strip_dirs() p.sort_stats('cumulative') p.print_stats() Christian
Meanwhile I tried to replace the parsing I did with Plex by re.Scanner. And again there is a remarkable speed difference. Again python2.5 is slower:
try: from re import Scanner except: from sre import Scanner
pars = {} order = [] count = 0
def par(scanner,name): global count, order, pars
if name in ['caller','e','pi']: return name if name not in pars.keys(): pars[name] = ('ns', count) order.append(name) ret = 'a[%d]'%count count += 1 else: ret = 'a[%d]'%(order.index(name)) return ret
scanner = Scanner([ (r"x", lambda y,x: x), (r"[a-zA-Z]+\.", lambda y,x: x), (r"[a-z]+\(", lambda y,x: x), (r"[a-zA-Z_]\w*", par), (r"\d+\.\d*", lambda y,x: x), (r"\d+", lambda y,x: x), (r"\+|-|\*|/", lambda y,x: x), (r"\s+", None), (r"\)+", lambda y,x: x), (r"\(+", lambda y,x: x), (r",", lambda y,x: x), ])
import profile import pstats
def run(): arg = '+amp*exp(-(x-pos)/fwhm)' for i in range(100): scanner.scan(arg)
profile.run('run()','profscanner') p = pstats.Stats('profscanner') p.strip_dirs() p.sort_stats('cumulative') p.print_stats()
Well, I tried this script, there was no big difference. Python2.4 0.772sec Python2.5 0.816sec Probably I found one reason comparation for classic style class is slower on Python2.5. Comparation function instance_compare() calls PyErr_GivenExceptionMatches(), and it was just flag operation on 2.4. But on 2.5, probably related to introduction of BaseException, it checks inherited type tuple. (ie: PyExceptionInstance_Check)
On 6/13/07, ocean <ocean@m2.ccsnet.ne.jp> wrote:
Meanwhile I tried to replace the parsing I did with Plex by re.Scanner. And again there is a remarkable speed difference. Again python2.5 is slower:
try: from re import Scanner except: from sre import Scanner
pars = {} order = [] count = 0
def par(scanner,name): global count, order, pars
if name in ['caller','e','pi']: return name if name not in pars.keys(): pars[name] = ('ns', count) order.append(name) ret = 'a[%d]'%count count += 1 else: ret = 'a[%d]'%(order.index(name)) return ret
scanner = Scanner([ (r"x", lambda y,x: x), (r"[a-zA-Z]+\.", lambda y,x: x), (r"[a-z]+\(", lambda y,x: x), (r"[a-zA-Z_]\w*", par), (r"\d+\.\d*", lambda y,x: x), (r"\d+", lambda y,x: x), (r"\+|-|\*|/", lambda y,x: x), (r"\s+", None), (r"\)+", lambda y,x: x), (r"\(+", lambda y,x: x), (r",", lambda y,x: x), ])
import profile import pstats
def run(): arg = '+amp*exp(-(x-pos)/fwhm)' for i in range(100): scanner.scan(arg)
profile.run('run()','profscanner') p = pstats.Stats('profscanner') p.strip_dirs() p.sort_stats('cumulative') p.print_stats()
Well, I tried this script, there was no big difference. Python2.4 0.772sec Python2.5 0.816sec
Probably I found one reason comparation for classic style class is slower on Python2.5. Comparation function instance_compare() calls PyErr_GivenExceptionMatches(), and it was just flag operation on 2.4. But on 2.5, probably related to introduction of BaseException, it checks inherited type tuple. (ie: PyExceptionInstance_Check)
I'm curious about the speed of 2.6 (trunk). I think this should have become faster due to the introduction of fast subtype checks (he says without looking at the code). n
Probably I found one reason comparation for classic style class is slower on Python2.5. Comparation function instance_compare() calls PyErr_GivenExceptionMatches(), and it was just flag operation on 2.4. But on 2.5, probably related to introduction of BaseException, it checks inherited type tuple. (ie: PyExceptionInstance_Check)
I'm curious about the speed of 2.6 (trunk). I think this should have become faster due to the introduction of fast subtype checks (he says without looking at the code).
n
Yes, I confirmed trunk is faster than 2.5. /////////////////////////////////////// // Code import timeit t = timeit.Timer(""" f1 < f2 """, """ class Foo: pass f1 = Foo() f2 = Foo() """) print t.timeit(10000) /////////////////////////////////////// // Result release-maint24 0.337sec release-maint25 0.625sec trunk 0.494sec ////////////////////////////////////// // Result of plex_test2.py release-maint24 2.944sec release-maint25 4.026sec trunk 3.625sec
participants (4)
-
Christian K -
Greg Ewing -
Neal Norwitz -
ocean