#!/usr/local/cpython-3.4/bin/python3 '''Test a bunch of implicitly-sorted dictionary-like datastructures''' import dbm import sys import common import python2x3 def to_key(interpreter_name, number_pattern, datastructure, size): '''Create a database key from a few variables''' bytes_size = python2x3.string_to_binary(str(size)) key = interpreter_name + b'/' + number_pattern + b'/' + datastructure + b'/' + bytes_size return key class Test_parameters(object): # pylint: disable=too-few-public-methods,too-many-instance-attributes '''A container class that holds some tests, to make passing things around easier''' def __init__(self, too_long, max_reps, interpreter_path, number_pattern, size, exponent, max_exponent): # pylint: disable=too-many-arguments self.max_reps = max_reps self.interpreter_path = interpreter_path self.number_pattern = number_pattern self.size = size self.too_long = too_long self.exponent = exponent self.max_exponent = max_exponent def inner_loops(database, test_parameters): '''Perform the benchmark inner loops''' interpreter_name = common.get_interpreter(test_parameters.interpreter_path) datastructures = list(common.DATASTRUCTURES) datastructures.sort() for datastructure in datastructures: key = to_key( interpreter_name=interpreter_name, number_pattern=test_parameters.number_pattern, datastructure=datastructure, size=test_parameters.size, ) if key in database: # This could be because we've already computed # this, or it could be because a previous # test of this datastructure took too long. if database[key] == 'too_long': sys.stderr.write('Skipping {} because things were taking too long\n'.format(key)) else: sys.stderr.write('Skipping {} because it has already been done\n'.format(key)) continue durations = [] for repno in range(test_parameters.max_reps): dummy = repno sys.stderr.write('Testing {}\n'.format(key)) duration = common.invoke_test_one( test_parameters.interpreter_path, datastructure, test_parameters.number_pattern, test_parameters.size, test_parameters.too_long, ) if duration == -1: sys.stderr.write(' Timed out\n') break else: sys.stderr.write(' Got duration {}\n'.format(duration)) durations.append(duration) if duration == -1: # This indicates that the time was too high (signified with a number that's WAAAY too high) mean = 1e100 standard_deviation = 0 else: mean = common.compute_mean(durations) standard_deviation = common.compute_standard_deviation(durations, mean) if mean > test_parameters.too_long: value = 'too_long' # Write "too_long" to all sizes from exponent to max_exponent for too_long_exponent in range(test_parameters.exponent, test_parameters.max_exponent + 1): size = 2 ** too_long_exponent key = to_key( interpreter_name=interpreter_name, number_pattern=test_parameters.number_pattern, datastructure=datastructure, size=size, ) database[key] = value else: value = '%s %s' % (mean, standard_deviation) database[key] = value def outer_loops(database, min_exponent, max_exponent, max_reps, too_long): '''Perform the benchmark outer loops''' for exponent in range(min_exponent, max_exponent + 1): size = 2 ** exponent for interpreter_path in common.INTERPRETERS: for number_pattern in common.NUMBER_PATTERN: test_parameters = Test_parameters( max_reps=max_reps, interpreter_path=interpreter_path, number_pattern=number_pattern, size=size, too_long=too_long, exponent=exponent, max_exponent=max_exponent, ) inner_loops( database, test_parameters, ) def main(): '''Main function''' production = True if production: min_exponent = 11 max_exponent = 30 max_reps = 5 too_long = 30.0 * 60.0 else: min_exponent = 10 max_exponent = 11 max_reps = 2 too_long = 20.0 database = dbm.open('results', 'c') outer_loops(database, min_exponent, max_exponent, max_reps, too_long) main()