diff options
Diffstat (limited to 'lib/python2.7/test/sortperf.py')
-rw-r--r-- | lib/python2.7/test/sortperf.py | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/lib/python2.7/test/sortperf.py b/lib/python2.7/test/sortperf.py new file mode 100644 index 0000000..cc83ee4 --- /dev/null +++ b/lib/python2.7/test/sortperf.py @@ -0,0 +1,169 @@ +"""Sort performance test. + +See main() for command line syntax. +See tabulate() for output format. + +""" + +import sys +import time +import random +import marshal +import tempfile +import os + +td = tempfile.gettempdir() + +def randfloats(n): + """Return a list of n random floats in [0, 1).""" + # Generating floats is expensive, so this writes them out to a file in + # a temp directory. If the file already exists, it just reads them + # back in and shuffles them a bit. + fn = os.path.join(td, "rr%06d" % n) + try: + fp = open(fn, "rb") + except IOError: + r = random.random + result = [r() for i in xrange(n)] + try: + try: + fp = open(fn, "wb") + marshal.dump(result, fp) + fp.close() + fp = None + finally: + if fp: + try: + os.unlink(fn) + except os.error: + pass + except IOError, msg: + print "can't write", fn, ":", msg + else: + result = marshal.load(fp) + fp.close() + # Shuffle it a bit... + for i in range(10): + i = random.randrange(n) + temp = result[:i] + del result[:i] + temp.reverse() + result.extend(temp) + del temp + assert len(result) == n + return result + +def flush(): + sys.stdout.flush() + +def doit(L): + t0 = time.clock() + L.sort() + t1 = time.clock() + print "%6.2f" % (t1-t0), + flush() + +def tabulate(r): + """Tabulate sort speed for lists of various sizes. + + The sizes are 2**i for i in r (the argument, a list). + + The output displays i, 2**i, and the time to sort arrays of 2**i + floating point numbers with the following properties: + + *sort: random data + \sort: descending data + /sort: ascending data + 3sort: ascending, then 3 random exchanges + +sort: ascending, then 10 random at the end + %sort: ascending, then randomly replace 1% of the elements w/ random values + ~sort: many duplicates + =sort: all equal + !sort: worst case scenario + + """ + cases = tuple([ch + "sort" for ch in r"*\/3+%~=!"]) + fmt = ("%2s %7s" + " %6s"*len(cases)) + print fmt % (("i", "2**i") + cases) + for i in r: + n = 1 << i + L = randfloats(n) + print "%2d %7d" % (i, n), + flush() + doit(L) # *sort + L.reverse() + doit(L) # \sort + doit(L) # /sort + + # Do 3 random exchanges. + for dummy in range(3): + i1 = random.randrange(n) + i2 = random.randrange(n) + L[i1], L[i2] = L[i2], L[i1] + doit(L) # 3sort + + # Replace the last 10 with random floats. + if n >= 10: + L[-10:] = [random.random() for dummy in range(10)] + doit(L) # +sort + + # Replace 1% of the elements at random. + for dummy in xrange(n // 100): + L[random.randrange(n)] = random.random() + doit(L) # %sort + + # Arrange for lots of duplicates. + if n > 4: + del L[4:] + L = L * (n // 4) + # Force the elements to be distinct objects, else timings can be + # artificially low. + L = map(lambda x: --x, L) + doit(L) # ~sort + del L + + # All equal. Again, force the elements to be distinct objects. + L = map(abs, [-0.5] * n) + doit(L) # =sort + del L + + # This one looks like [3, 2, 1, 0, 0, 1, 2, 3]. It was a bad case + # for an older implementation of quicksort, which used the median + # of the first, last and middle elements as the pivot. + half = n // 2 + L = range(half - 1, -1, -1) + L.extend(range(half)) + # Force to float, so that the timings are comparable. This is + # significantly faster if we leave tham as ints. + L = map(float, L) + doit(L) # !sort + print + +def main(): + """Main program when invoked as a script. + + One argument: tabulate a single row. + Two arguments: tabulate a range (inclusive). + Extra arguments are used to seed the random generator. + + """ + # default range (inclusive) + k1 = 15 + k2 = 20 + if sys.argv[1:]: + # one argument: single point + k1 = k2 = int(sys.argv[1]) + if sys.argv[2:]: + # two arguments: specify range + k2 = int(sys.argv[2]) + if sys.argv[3:]: + # derive random seed from remaining arguments + x = 1 + for a in sys.argv[3:]: + x = 69069 * x + hash(a) + random.seed(x) + r = range(k1, k2+1) # include the end point + tabulate(r) + +if __name__ == '__main__': + main() |