2009-03-19 02:25:20 +00:00
|
|
|
from __future__ import with_statement
|
|
|
|
import os
|
2009-03-18 19:44:36 +00:00
|
|
|
import timeit
|
2009-03-19 02:25:20 +00:00
|
|
|
import random
|
|
|
|
from optparse import OptionParser
|
|
|
|
from tempfile import mktemp
|
2009-03-18 19:44:36 +00:00
|
|
|
from pq_classes import *
|
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
TESTID = os.getpid()
|
|
|
|
|
2009-03-19 12:04:19 +00:00
|
|
|
TESTCASES = (
|
2009-03-18 19:44:36 +00:00
|
|
|
("heapq", PriorityQueue1),
|
2009-03-19 04:09:24 +00:00
|
|
|
#("heapq+int", PriorityQueue1b),
|
2009-03-18 19:44:36 +00:00
|
|
|
("dict+deque", PriorityQueue2),
|
|
|
|
("deque+heapq", PriorityQueue3),
|
2009-03-19 04:09:24 +00:00
|
|
|
#("deque+heapq+int", PriorityQueue3b),
|
2009-03-18 19:44:36 +00:00
|
|
|
("deque+defaultdict+deque", PriorityQueue4),
|
2009-03-19 13:11:27 +00:00
|
|
|
("deque+defaultdict+deque+cache", PriorityQueue4b),
|
2009-03-19 04:09:24 +00:00
|
|
|
#('list+deque', PriorityQueue5),
|
|
|
|
('list+deque+cache', PriorityQueue5b),
|
|
|
|
#('list+deque+cache+islice', PriorityQueue5c),
|
2009-03-19 12:04:19 +00:00
|
|
|
)
|
2009-03-18 19:44:36 +00:00
|
|
|
|
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
stmt_fmt = """
|
|
|
|
for n, prio in enumerate(randomprio):
|
|
|
|
q.push(n, prio)
|
2009-03-18 19:44:36 +00:00
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
try:
|
|
|
|
while True:
|
|
|
|
q.pop()
|
|
|
|
except IndexError:
|
|
|
|
pass
|
2009-03-18 19:44:36 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
setup_fmt = """
|
2009-03-19 02:25:20 +00:00
|
|
|
from collections import deque
|
2009-03-18 19:44:36 +00:00
|
|
|
from __main__ import %(PriorityClass)s as PriorityQueue
|
|
|
|
q = PriorityQueue(%(priorities)i)
|
2009-03-19 02:25:20 +00:00
|
|
|
|
|
|
|
randomprio = deque()
|
2009-03-19 13:11:27 +00:00
|
|
|
for line in open('%(samplefile)s'):
|
|
|
|
prio = int(line.strip())
|
|
|
|
randomprio.append(prio)
|
2009-03-18 19:44:36 +00:00
|
|
|
"""
|
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
|
2009-03-19 12:04:19 +00:00
|
|
|
def _distribution(priorities, distribution):
|
|
|
|
half = priorities // 2
|
|
|
|
prio = -priorities
|
|
|
|
while not (-half <= prio <= half):
|
|
|
|
prio = round(distribution())
|
|
|
|
return min(max(prio, -half), half)
|
2009-03-18 19:44:36 +00:00
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
def normal_priority(priorities):
|
2009-03-19 12:04:19 +00:00
|
|
|
sigma = priorities / 4.0
|
|
|
|
dist = lambda: random.normalvariate(mu=0, sigma=sigma)
|
|
|
|
return _distribution(priorities, dist)
|
|
|
|
|
|
|
|
def gauss_priority(priorities):
|
|
|
|
sigma = priorities / 4.0
|
|
|
|
dist = lambda: random.gauss(mu=0, sigma=sigma)
|
|
|
|
return _distribution(priorities, dist)
|
|
|
|
|
|
|
|
def triangular_priority(priorities):
|
|
|
|
half = priorities // 2
|
|
|
|
return random.triangular(-half-1, half+1, 0)
|
|
|
|
|
|
|
|
def uniform_priority(priorities):
|
|
|
|
return int(random.random() * priorities) - (priorities / 2)
|
2009-03-19 02:25:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
PRIORITY_DISTRIBUTIONS = {
|
|
|
|
'uniform': uniform_priority,
|
|
|
|
'normal': normal_priority,
|
2009-03-19 12:04:19 +00:00
|
|
|
'gauss': gauss_priority,
|
|
|
|
'triangular': triangular_priority,
|
2009-03-19 02:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def gen_samples(count, priorities, priority_distribution=uniform_priority):
|
|
|
|
fn = '/tmp/pq-%i-%i-%i' % (TESTID, priorities, count)
|
|
|
|
|
|
|
|
with open(fn, 'w') as samplefile:
|
|
|
|
for n in xrange(count):
|
|
|
|
prio = priority_distribution(priorities)
|
|
|
|
samplefile.write('%i\n' % prio)
|
|
|
|
return fn
|
|
|
|
|
|
|
|
def runtests(pushpops=50*1000, times=30, priorities=1, samplefile=None, priority_distribution=uniform_priority):
|
2009-03-19 12:04:19 +00:00
|
|
|
samplefile = samplefile or gen_samples(pushpops, priorities, priority_distribution)
|
2009-03-19 02:25:20 +00:00
|
|
|
|
|
|
|
print "\n== With %s priorities (%s) ==\n" % (priorities, samplefile)
|
2009-03-18 19:44:36 +00:00
|
|
|
print "pushpops = %s, times = %s" % (pushpops, times)
|
|
|
|
|
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
stmt = stmt_fmt
|
2009-03-18 19:44:36 +00:00
|
|
|
for name, cls in TESTCASES:
|
2009-03-19 02:25:20 +00:00
|
|
|
setup = setup_fmt % {
|
|
|
|
'PriorityClass': cls.__name__,
|
|
|
|
'priorities': priorities,
|
|
|
|
'samplefile': samplefile,
|
|
|
|
}
|
2009-03-18 19:44:36 +00:00
|
|
|
t = timeit.Timer(stmt, setup)
|
|
|
|
print "%s implementation: %s" % (name, t.timeit(number=times))
|
|
|
|
|
2009-03-19 02:25:20 +00:00
|
|
|
|
2009-03-18 19:44:36 +00:00
|
|
|
if __name__ == '__main__':
|
2009-03-19 02:25:20 +00:00
|
|
|
o = OptionParser()
|
|
|
|
o.add_option('-n', '--samples-count', type='int', default=50000, metavar='NUMBER',
|
|
|
|
help='The max number or samples to generate')
|
|
|
|
o.add_option('-r', '--retry-times', type='int', default=30, metavar='NUMBER',
|
|
|
|
help='the times to retry each test')
|
|
|
|
o.add_option('-s', '--samplefile', default=None, metavar='FILENAME',
|
|
|
|
help='load samples from file, default: use sample generator')
|
|
|
|
o.add_option('-p', '--priorities', default='1,3,5,10,100', metavar='CSV_PRIOLIST',
|
|
|
|
help='a comma separated list of priorities to test')
|
|
|
|
o.add_option('-d', '--priority-distribution', default='uniform', metavar='DISTRIBUTION',
|
|
|
|
help='distribution used for random priority generator, default: uniform. possibles: %s' \
|
|
|
|
% ','.join(PRIORITY_DISTRIBUTIONS.keys()))
|
|
|
|
|
|
|
|
opt, args = o.parse_args()
|
|
|
|
|
|
|
|
priolist = map(int, opt.priorities.split(','))
|
|
|
|
distribution = PRIORITY_DISTRIBUTIONS[opt.priority_distribution]
|
|
|
|
for prio in priolist:
|
|
|
|
runtests(pushpops=opt.samples_count, priorities=prio, times=opt.retry_times,
|
|
|
|
samplefile=opt.samplefile, priority_distribution=distribution)
|
2009-03-18 19:44:36 +00:00
|
|
|
|
|
|
|
# Results (in seconds, on an intel core2 2.16ghz):
|
|
|
|
# == Without priorities ==
|
|
|
|
|
|
|
|
# pushpops = 50000, times = 30
|
|
|
|
# heapq implementation: 7.7959010601
|
|
|
|
# dict+deque implementation: 5.6420109272
|
|
|
|
# deque+heapq implementation: 3.57563900948
|
|
|
|
|
|
|
|
# == With 5 priorities ==
|
|
|
|
|
|
|
|
# pushpops = 50000, times = 30
|
|
|
|
# heapq implementation: 9.83902192116
|
|
|
|
# dict+deque implementation: 9.21094298363
|
|
|
|
# deque+heapq implementation: 9.05321097374
|
|
|
|
|
|
|
|
# == With 10 priorities ==
|
|
|
|
|
|
|
|
# pushpops = 50000, times = 30
|
|
|
|
# heapq implementation: 9.97831392288
|
|
|
|
# dict+deque implementation: 11.9721341133
|
|
|
|
# deque+heapq implementation: 9.79048800468
|
|
|
|
|
|
|
|
# == With 100 priorities ==
|
|
|
|
|
|
|
|
# pushpops = 50000, times = 30
|
|
|
|
# heapq implementation: 10.4782910347
|
|
|
|
# dict+deque implementation: 64.6989660263
|
|
|
|
# deque+heapq implementation: 10.858932972
|