1#!/usr/bin/env python3 2 3try: 4 frozendict 5 print("builtin") 6except NameError: 7 from frozendict import coold 8 9class F(coold): 10 def __new__(cls, *args, **kwargs): 11 return super().__new__(cls, *args, **kwargs) 12 13frozendict = F 14 15def main(number): 16 import timeit 17 import uuid 18 from time import time 19 from math import sqrt 20 21 def mindev(data, xbar = None): 22 if not data: 23 raise ValueError("No data") 24 25 if xbar == None: 26 xbar = min(data) 27 28 sigma2 = 0 29 30 for x in data: 31 sigma2 += (x - xbar) ** 2 32 33 N = len(data) - 1 34 35 if N < 1: 36 N = 1 37 38 return sqrt(sigma2 / N) 39 40 def autorange(stmt, setup="pass", globals=None, ratio=1000, bench_time=10, number=None): 41 if setup == None: 42 setup = "pass" 43 44 t = timeit.Timer(stmt=stmt, setup=setup, globals=globals) 45 break_immediately = False 46 47 if number == None: 48 a = t.autorange() 49 50 num = a[0] 51 number = int(num / ratio) 52 53 if number < 1: 54 number = 1 55 56 repeat = int(num / number) 57 58 if repeat < 1: 59 repeat = 1 60 61 else: 62 repeat = 1 63 break_immediately = True 64 65 results = [] 66 67 data_tmp = t.repeat(number=number, repeat=repeat) 68 min_value = min(data_tmp) 69 data_min = [min_value] 70 71 bench_start = time() 72 73 while 1: 74 data_min.extend(t.repeat(number=number, repeat=repeat)) 75 76 if break_immediately or time() - bench_start > bench_time: 77 break 78 79 data_min.sort() 80 xbar = data_min[0] 81 i = 0 82 83 while i < len(data_min): 84 i = len(data_min) 85 sigma = mindev(data_min, xbar=xbar) 86 87 for i in range(2, len(data_min)): 88 if data_min[i] - xbar > 3 * sigma: 89 break 90 91 k = i 92 93 if i < 5: 94 k = 5 95 96 del data_min[k:] 97 98 return (min(data_min) / number, mindev(data_min, xbar=xbar) / number) 99 100 101 def getUuid(): 102 return str(uuid.uuid4()) 103 104 105 dictionary_sizes = (5, 1000) 106 107 print_tpl = "Name: {name: <25} Size: {size: >4}; Keys: {keys: >3}; Type: {type: >10}; Time: {time:.2e}; Sigma: {sigma:.0e}" 108 str_key = '12323f29-c31f-478c-9b15-e7acc5354df9' 109 int_key = dictionary_sizes[0] - 2 110 111 if int_key < 0: 112 int_key = 0 113 114 benchmarks = ( 115 {"name": "constructor(d)", "code": "klass(d)", "setup": "klass = type(o)", }, 116 {"name": "constructor(kwargs)", "code": "klass(**d)", "setup": "klass = type(o)", }, 117 {"name": "constructor(seq2)", "code": "klass(v)", "setup": "klass = type(o); v = tuple(d.items())", }, 118 {"name": "constructor(o)", "code": "klass(o)", "setup": "klass = type(o)", }, 119 {"name": "o.copy()", "code": "o.copy()", "setup": "pass", }, 120 {"name": "o == o", "code": "o == o", "setup": "pass", }, 121 {"name": "for x in o", "code": "for _ in o: pass", "setup": "pass", }, 122 {"name": "for x in o.values()", "code": "for _ in values: pass", "setup": "values = o.values()", }, 123 {"name": "for x in o.items()", "code": "for _ in items: pass", "setup": "items = o.items()", }, 124 {"name": "pickle.dumps(o)", "code": "dumps(o, protocol=-1)", "setup": "from pickle import dumps", }, 125 {"name": "pickle.loads(dump)", "code": "loads(dump)", "setup": "from pickle import loads, dumps; dump = dumps(o, protocol=-1)", }, 126 {"name": "class.fromkeys()", "code": "fromkeys(keys)", "setup": "fromkeys = type(o).fromkeys; keys = o.keys()", }, 127 {"name": "for x in o.keys()", "code": "for _ in keys: pass", "setup": "keys = o.keys()", }, 128 {"name": "for x in iter(o)", "code": "for _ in iter(o): pass", "setup": "pass", }, 129 {"name": "o == d", "code": "o == d", "setup": "pass", }, 130 {"name": "o.get(key)", "code": "get(key)", "setup": "key = getUuid(); get = o.get", }, 131 {"name": "o[key]", "code": "o[one_key]","setup": "pass", }, 132 {"name": "key in o", "code": "key in o", "setup": "key = getUuid()", }, 133 {"name": "key not in o", "code": "key not in o", "setup": "key = getUuid()", }, 134 {"name": "hash(o)", "code": "hash(o)", "setup": "pass", }, 135 {"name": "len(o)", "code": "len(o)", "setup": "pass", }, 136 {"name": "o.keys()", "code": "keys()", "setup": "keys = o.keys", }, 137 {"name": "o.values()", "code": "values()", "setup": "values = o.values", }, 138 {"name": "o.items()", "code": "items()", "setup": "items = o.items", }, 139 {"name": "iter(o)", "code": "iter(o)", "setup": "pass", }, 140 {"name": "repr(o)", "code": "repr(o)", "setup": "pass", }, 141 {"name": "str(o)", "code": "str(o)", "setup": "pass", }, 142 {"name": "set", "code": None, "setup": "val = getUuid()", }, 143 ) 144 145 dict_collection = [] 146 147 for n in dictionary_sizes: 148 d1 = {} 149 d2 = {} 150 151 for i in range(n-1): 152 d1[getUuid()] = getUuid() 153 d2[i] = i 154 155 d1[str_key] = getUuid() 156 d2[999] = 999 157 158 fd1 = frozendict(d1) 159 fd2 = frozendict(d2) 160 161 dict_collection.append({"str": ((d1, fd1), str_key), "int": ((d2, fd2), int_key)}) 162 163 for benchmark in benchmarks: 164 print("################################################################################") 165 166 for dict_collection_entry in dict_collection: 167 for (dict_keys, (dicts, one_key)) in dict_collection_entry.items(): 168 169 if benchmark["name"] == "constructor(kwargs)" and dict_keys == "int": 170 continue 171 172 print("////////////////////////////////////////////////////////////////////////////////") 173 174 for o in dicts: 175 if benchmark["name"] == "hash(o)" and type(o) == dict: 176 continue 177 178 if benchmark["name"] == "set": 179 if type(o) == dict: 180 benchmark["code"] = "o[one_key] = val" 181 else: 182 benchmark["code"] = "o.set(one_key, val)" 183 184 d = dicts[0] 185 186 bench_res = autorange( 187 stmt = benchmark["code"], 188 setup = benchmark["setup"], 189 globals = {"o": o.copy(), "getUuid": getUuid, "d": d.copy(), "one_key": one_key}, 190 number = number, 191 ) 192 193 print(print_tpl.format( 194 name = "`{}`;".format(benchmark["name"]), 195 keys = dict_keys, 196 size = len(o), 197 type = type(o).__name__, 198 time = bench_res[0], 199 sigma = bench_res[1], 200 )) 201 202 print("################################################################################") 203 204if __name__ == "__main__": 205 import sys 206 207 number = None 208 argv = sys.argv 209 len_argv = len(argv) 210 max_positional_args = 1 211 max_len_argv = max_positional_args + 1 212 213 if len_argv > max_len_argv: 214 raise ValueError( 215 ("{name} must not accept more than {nargs} positional " + 216 "command-line parameters").format(name=__name__, nargs=max_positional_args) 217 ) 218 219 number_arg_pos = 1 220 221 if len_argv == number_arg_pos + 1: 222 number = int(argv[number_arg_pos]) 223 224 main(number) 225