Skip to content

Instantly share code, notes, and snippets.

@aliles
Created July 8, 2011 11:30
Show Gist options
  • Save aliles/1071645 to your computer and use it in GitHub Desktop.
Save aliles/1071645 to your computer and use it in GitHub Desktop.
Benchmark repeated calls to a tail call optimisation decorator.
[aliles@macbookpro ~]$ time python2.7 timeit_tco.py 100 60000
Maximum time on CPU: 0.00030600
Minimum time on CPU: 0.00014800
Average time on CPU: 0.00015401
real 0m9.586s
user 0m9.473s
sys 0m0.110s
[aliles@macbookpro ~]$ time pypy timeit_tco.py 100 60000
Maximum time on CPU: 0.00829600
Minimum time on CPU: 0.00003300
Average time on CPU: 0.00006019
real 0m4.557s
user 0m4.427s
sys 0m0.128s
[aliles@macbookpro ~]$ time python2.7 timeit_tco.py 1000 6000
Maximum time on CPU: 0.00230600
Minimum time on CPU: 0.00196600
Average time on CPU: 0.00200732
real 0m13.698s
user 0m13.654s
sys 0m0.033s
[aliles@macbookpro ~]$ time pypy timeit_tco.py 1000 6000
Maximum time on CPU: 0.01351100
Minimum time on CPU: 0.00179300
Average time on CPU: 0.00186320
real 0m19.049s
user 0m18.949s
sys 0m0.090s
from collections import namedtuple
import sys
import time
Stats = namedtuple('Stats', 'maximum minimum average digits')
class tail_recursive(object):
"""Tail recursion decorator by George Sakkis
http://code.activestate.com/recipes/496691-new-tail-recursion-decorator/#c3
"""
def __init__(self, func):
self.func = func
self.firstcall = True
self.CONTINUE = object()
def __call__(self, *args, **kwd):
if self.firstcall:
func = self.func
CONTINUE = self.CONTINUE
self.firstcall = False
try:
while True:
result = func(*args, **kwd)
if result is CONTINUE: # update arguments
args, kwd = self.argskwd
else: # last call
return result
finally:
self.firstcall = True
else: # return the arguments of the tail call
self.argskwd = args, kwd
return self.CONTINUE
@tail_recursive
def factorial(n, acc=1):
"calculate a factorial"
if n == 0:
return acc
res = factorial(n-1, n*acc)
return res
def factorial_loop(depth, loops=1, step=0):
maximum = None
minimum = Ellipsis
total = 0.0
digits = 0
for loop in xrange(loops):
start = time.clock()
value = factorial(depth)
stop = time.clock()
cost = stop - start
maximum = max(maximum, cost)
minimum = min(minimum, cost)
total += cost
digits += len(str(value))
depth += step
average = total / loops
return Stats(maximum, minimum, average, digits)
if __name__ == '__main__':
depth = int(sys.argv[1])
loops = int(sys.argv[2])
stats = factorial_loop(depth, loops, 0)._asdict()
print "Maximum time on CPU: %(maximum).8f" % stats
print "Minimum time on CPU: %(minimum).8f" % stats
print "Average time on CPU: %(average).8f" % stats
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment