blob: cd6bbcb70065921166f74d72fda302ae8083359f [file] [log] [blame]
Guido van Rossum03e35c51998-05-10 18:27:29 +00001"""Sort performance test.
2
3See main() for command line syntax.
4See tabulate() for output format.
5
6"""
Guido van Rossumea176b61998-05-10 18:20:05 +00007
8import sys
9import time
Andrew M. Kuchlinga9745612002-04-10 14:54:39 +000010import random
Guido van Rossumea176b61998-05-10 18:20:05 +000011import marshal
12import tempfile
Guido van Rossumea176b61998-05-10 18:20:05 +000013import os
14
15td = tempfile.gettempdir()
16
Tim Peters8b6ec792002-07-18 15:53:32 +000017def randfloats(n):
18 """Return a list of n random floats in [0, 1)."""
19 # Generating floats is expensive, so this writes them out to a file in
20 # a temp directory. If the file already exists, it just reads them
21 # back in and shuffles them a bit.
Guido van Rossumea176b61998-05-10 18:20:05 +000022 fn = os.path.join(td, "rr%06d" % n)
23 try:
24 fp = open(fn, "rb")
25 except IOError:
Tim Peters8b6ec792002-07-18 15:53:32 +000026 r = random.random
27 result = [r() for i in xrange(n)]
Guido van Rossumea176b61998-05-10 18:20:05 +000028 try:
29 try:
30 fp = open(fn, "wb")
31 marshal.dump(result, fp)
32 fp.close()
33 fp = None
34 finally:
35 if fp:
36 try:
37 os.unlink(fn)
38 except os.error:
39 pass
40 except IOError, msg:
41 print "can't write", fn, ":", msg
42 else:
43 result = marshal.load(fp)
44 fp.close()
Guido van Rossumea176b61998-05-10 18:20:05 +000045 # Shuffle it a bit...
46 for i in range(10):
Tim Peters8b6ec792002-07-18 15:53:32 +000047 i = random.randrange(n)
Guido van Rossumea176b61998-05-10 18:20:05 +000048 temp = result[:i]
49 del result[:i]
50 temp.reverse()
Tim Peters8b6ec792002-07-18 15:53:32 +000051 result.extend(temp)
Guido van Rossumea176b61998-05-10 18:20:05 +000052 del temp
Tim Peters8b6ec792002-07-18 15:53:32 +000053 assert len(result) == n
Guido van Rossumea176b61998-05-10 18:20:05 +000054 return result
55
Tim Peters8b6ec792002-07-18 15:53:32 +000056def flush():
Guido van Rossumea176b61998-05-10 18:20:05 +000057 sys.stdout.flush()
58
59def doit(L):
60 t0 = time.clock()
61 L.sort()
62 t1 = time.clock()
63 print "%6.2f" % (t1-t0),
Tim Peters8b6ec792002-07-18 15:53:32 +000064 flush()
Guido van Rossumea176b61998-05-10 18:20:05 +000065
66def tabulate(r):
Guido van Rossum03e35c51998-05-10 18:27:29 +000067 """Tabulate sort speed for lists of various sizes.
68
69 The sizes are 2**i for i in r (the argument, a list).
70
71 The output displays i, 2**i, and the time to sort arrays of 2**i
72 floating point numbers with the following properties:
73
74 *sort: random data
75 \sort: descending data
76 /sort: ascending data
Tim Peters0a30e642002-07-20 04:21:51 +000077 3sort: ascending data but with 3 random exchanges
Guido van Rossum03e35c51998-05-10 18:27:29 +000078 ~sort: many duplicates
Tim Peters8b6ec792002-07-18 15:53:32 +000079 =sort: all equal
Guido van Rossum16653cb1998-05-26 15:05:12 +000080 !sort: worst case scenario
Guido van Rossum03e35c51998-05-10 18:27:29 +000081
82 """
Tim Peters0a30e642002-07-20 04:21:51 +000083 cases = ("*sort", "\\sort", "/sort", "3sort", "~sort", "=sort", "!sort")
Tim Peters8b6ec792002-07-18 15:53:32 +000084 fmt = ("%2s %7s" + " %6s"*len(cases))
Guido van Rossum16653cb1998-05-26 15:05:12 +000085 print fmt % (("i", "2**i") + cases)
Guido van Rossumea176b61998-05-10 18:20:05 +000086 for i in r:
Tim Peters8b6ec792002-07-18 15:53:32 +000087 n = 1 << i
88 L = randfloats(n)
89 print "%2d %7d" % (i, n),
90 flush()
Guido van Rossumea176b61998-05-10 18:20:05 +000091 doit(L) # *sort
92 L.reverse()
93 doit(L) # \sort
94 doit(L) # /sort
Tim Peters8b6ec792002-07-18 15:53:32 +000095
Tim Peters0a30e642002-07-20 04:21:51 +000096 # Do 3 random exchanges.
97 for dummy in range(3):
98 i1 = random.randrange(n)
99 i2 = random.randrange(n)
100 L[i1], L[i2] = L[i2], L[i1]
101 doit(L) # 3sort
102
Tim Peters8b6ec792002-07-18 15:53:32 +0000103 # Arrange for lots of duplicates.
Guido van Rossumea176b61998-05-10 18:20:05 +0000104 if n > 4:
Guido van Rossumb298a301998-05-12 13:21:31 +0000105 del L[4:]
Tim Peters8b6ec792002-07-18 15:53:32 +0000106 L = L * (n // 4)
107 # Force the elements to be distinct objects, else timings can be
108 # artificially low.
Guido van Rossumb298a301998-05-12 13:21:31 +0000109 L = map(lambda x: --x, L)
Guido van Rossumea176b61998-05-10 18:20:05 +0000110 doit(L) # ~sort
Guido van Rossumb298a301998-05-12 13:21:31 +0000111 del L
Tim Peters8b6ec792002-07-18 15:53:32 +0000112
113 # All equal. Again, force the elements to be distinct objects.
114 L = map(abs, [-0.5] * n)
115 doit(L) # =sort
116 del L
117
118 # This one looks like [3, 2, 1, 0, 0, 1, 2, 3]. It was a bad case
119 # for an older implementation of quicksort, which used the median
120 # of the first, last and middle elements as the pivot. It's still
121 # a worse-than-average case for samplesort, but on the order of a
122 # measly 5% worse, not a quadratic-time disaster as it was with
123 # quicksort.
124 half = n // 2
125 L = range(half - 1, -1, -1)
126 L.extend(range(half))
127 # Force to float, so that the timings are comparable. This is
128 # significantly faster if we leave tham as ints.
129 L = map(float, L)
Guido van Rossum16653cb1998-05-26 15:05:12 +0000130 doit(L) # !sort
Guido van Rossumea176b61998-05-10 18:20:05 +0000131 print
132
133def main():
Guido van Rossum03e35c51998-05-10 18:27:29 +0000134 """Main program when invoked as a script.
135
136 One argument: tabulate a single row.
137 Two arguments: tabulate a range (inclusive).
138 Extra arguments are used to seed the random generator.
139
140 """
Guido van Rossumea176b61998-05-10 18:20:05 +0000141 # default range (inclusive)
142 k1 = 15
Tim Peters8b6ec792002-07-18 15:53:32 +0000143 k2 = 20
Guido van Rossumea176b61998-05-10 18:20:05 +0000144 if sys.argv[1:]:
Guido van Rossum03e35c51998-05-10 18:27:29 +0000145 # one argument: single point
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000146 k1 = k2 = int(sys.argv[1])
Guido van Rossumea176b61998-05-10 18:20:05 +0000147 if sys.argv[2:]:
Guido van Rossum03e35c51998-05-10 18:27:29 +0000148 # two arguments: specify range
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000149 k2 = int(sys.argv[2])
Guido van Rossumea176b61998-05-10 18:20:05 +0000150 if sys.argv[3:]:
151 # derive random seed from remaining arguments
Tim Peters8b6ec792002-07-18 15:53:32 +0000152 x = 1
Guido van Rossumea176b61998-05-10 18:20:05 +0000153 for a in sys.argv[3:]:
Tim Peters8b6ec792002-07-18 15:53:32 +0000154 x = 69069 * x + hash(a)
155 random.seed(x)
Guido van Rossum03e35c51998-05-10 18:27:29 +0000156 r = range(k1, k2+1) # include the end point
Guido van Rossumea176b61998-05-10 18:20:05 +0000157 tabulate(r)
158
159if __name__ == '__main__':
160 main()