blob: 86b38baa1b3dffbb33d8e9a025608090083f59c1 [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 Peters7ea39b12002-07-21 17:37:03 +000077 3sort: ascending, then 3 random exchanges
78 +sort: ascending, then 10 random at the end
Guido van Rossum03e35c51998-05-10 18:27:29 +000079 ~sort: many duplicates
Tim Peters8b6ec792002-07-18 15:53:32 +000080 =sort: all equal
Guido van Rossum16653cb1998-05-26 15:05:12 +000081 !sort: worst case scenario
Guido van Rossum03e35c51998-05-10 18:27:29 +000082
83 """
Tim Peters7ea39b12002-07-21 17:37:03 +000084 cases = tuple([ch + "sort" for ch in r"*\/3+~=!"])
Tim Peters8b6ec792002-07-18 15:53:32 +000085 fmt = ("%2s %7s" + " %6s"*len(cases))
Guido van Rossum16653cb1998-05-26 15:05:12 +000086 print fmt % (("i", "2**i") + cases)
Guido van Rossumea176b61998-05-10 18:20:05 +000087 for i in r:
Tim Peters8b6ec792002-07-18 15:53:32 +000088 n = 1 << i
89 L = randfloats(n)
90 print "%2d %7d" % (i, n),
91 flush()
Guido van Rossumea176b61998-05-10 18:20:05 +000092 doit(L) # *sort
93 L.reverse()
94 doit(L) # \sort
95 doit(L) # /sort
Tim Peters8b6ec792002-07-18 15:53:32 +000096
Tim Peters0a30e642002-07-20 04:21:51 +000097 # Do 3 random exchanges.
98 for dummy in range(3):
99 i1 = random.randrange(n)
100 i2 = random.randrange(n)
101 L[i1], L[i2] = L[i2], L[i1]
102 doit(L) # 3sort
103
Tim Peters7ea39b12002-07-21 17:37:03 +0000104 # Replace the last 10 with random floats.
105 if n >= 10:
106 L[-10:] = [random.random() for dummy in range(10)]
107 doit(L) # +sort
108
Tim Peters8b6ec792002-07-18 15:53:32 +0000109 # Arrange for lots of duplicates.
Guido van Rossumea176b61998-05-10 18:20:05 +0000110 if n > 4:
Guido van Rossumb298a301998-05-12 13:21:31 +0000111 del L[4:]
Tim Peters8b6ec792002-07-18 15:53:32 +0000112 L = L * (n // 4)
113 # Force the elements to be distinct objects, else timings can be
114 # artificially low.
Guido van Rossumb298a301998-05-12 13:21:31 +0000115 L = map(lambda x: --x, L)
Guido van Rossumea176b61998-05-10 18:20:05 +0000116 doit(L) # ~sort
Guido van Rossumb298a301998-05-12 13:21:31 +0000117 del L
Tim Peters8b6ec792002-07-18 15:53:32 +0000118
119 # All equal. Again, force the elements to be distinct objects.
120 L = map(abs, [-0.5] * n)
121 doit(L) # =sort
122 del L
123
124 # This one looks like [3, 2, 1, 0, 0, 1, 2, 3]. It was a bad case
125 # for an older implementation of quicksort, which used the median
Tim Peters7ea39b12002-07-21 17:37:03 +0000126 # of the first, last and middle elements as the pivot.
Tim Peters8b6ec792002-07-18 15:53:32 +0000127 half = n // 2
128 L = range(half - 1, -1, -1)
129 L.extend(range(half))
130 # Force to float, so that the timings are comparable. This is
131 # significantly faster if we leave tham as ints.
132 L = map(float, L)
Guido van Rossum16653cb1998-05-26 15:05:12 +0000133 doit(L) # !sort
Guido van Rossumea176b61998-05-10 18:20:05 +0000134 print
135
136def main():
Guido van Rossum03e35c51998-05-10 18:27:29 +0000137 """Main program when invoked as a script.
138
139 One argument: tabulate a single row.
140 Two arguments: tabulate a range (inclusive).
141 Extra arguments are used to seed the random generator.
142
143 """
Guido van Rossumea176b61998-05-10 18:20:05 +0000144 # default range (inclusive)
145 k1 = 15
Tim Peters8b6ec792002-07-18 15:53:32 +0000146 k2 = 20
Guido van Rossumea176b61998-05-10 18:20:05 +0000147 if sys.argv[1:]:
Guido van Rossum03e35c51998-05-10 18:27:29 +0000148 # one argument: single point
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000149 k1 = k2 = int(sys.argv[1])
Guido van Rossumea176b61998-05-10 18:20:05 +0000150 if sys.argv[2:]:
Guido van Rossum03e35c51998-05-10 18:27:29 +0000151 # two arguments: specify range
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000152 k2 = int(sys.argv[2])
Guido van Rossumea176b61998-05-10 18:20:05 +0000153 if sys.argv[3:]:
154 # derive random seed from remaining arguments
Tim Peters8b6ec792002-07-18 15:53:32 +0000155 x = 1
Guido van Rossumea176b61998-05-10 18:20:05 +0000156 for a in sys.argv[3:]:
Tim Peters8b6ec792002-07-18 15:53:32 +0000157 x = 69069 * x + hash(a)
158 random.seed(x)
Guido van Rossum03e35c51998-05-10 18:27:29 +0000159 r = range(k1, k2+1) # include the end point
Guido van Rossumea176b61998-05-10 18:20:05 +0000160 tabulate(r)
161
162if __name__ == '__main__':
163 main()