mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
3.3 KiB
125 lines
3.3 KiB
#!/usr/bin/env python2
|
|
#
|
|
# Find a sequence of duk_hobject hash sizes which have a desired 'ratio'
|
|
# and are primes. Prime hash sizes ensure that all probe sequence values
|
|
# (less than hash size) are relatively prime to hash size, i.e. cover the
|
|
# entire hash. Prime data is packed into about 1 byte/prime using a
|
|
# prediction-correction model.
|
|
#
|
|
# Also generates a set of probe steps which are relatively prime to every
|
|
# hash size.
|
|
#
|
|
|
|
import sys
|
|
import math
|
|
|
|
def is_prime(n):
|
|
if n == 0:
|
|
return False
|
|
if n == 1 or n == 2:
|
|
return True
|
|
|
|
n_limit = int(math.ceil(float(n) ** 0.5)) + 1
|
|
n_limit += 100 # paranoia
|
|
if n_limit >= n:
|
|
n_limit = n - 1
|
|
for i in xrange(2,n_limit + 1):
|
|
if (n % i) == 0:
|
|
return False
|
|
return True
|
|
|
|
def next_prime(n):
|
|
while True:
|
|
n += 1
|
|
if is_prime(n):
|
|
return n
|
|
|
|
def generate_sizes(min_size, max_size, step_ratio):
|
|
"Generate a set of hash sizes following a nice ratio."
|
|
|
|
sizes = []
|
|
ratios = []
|
|
curr = next_prime(min_size)
|
|
next = curr
|
|
sizes.append(curr)
|
|
|
|
step_ratio = float(step_ratio) / 1024
|
|
|
|
while True:
|
|
if next > max_size:
|
|
break
|
|
ratio = float(next) / float(curr)
|
|
if ratio < step_ratio:
|
|
next = next_prime(next)
|
|
continue
|
|
sys.stdout.write('.'); sys.stdout.flush()
|
|
sizes.append(next)
|
|
ratios.append(ratio)
|
|
curr = next
|
|
next = next_prime(int(next * step_ratio))
|
|
|
|
sys.stdout.write('\n'); sys.stdout.flush()
|
|
return sizes, ratios
|
|
|
|
def generate_corrections(sizes, step_ratio):
|
|
"Generate a set of correction from a ratio-based predictor."
|
|
|
|
# Generate a correction list for size list, assuming steps follow a certain
|
|
# ratio; this allows us to pack size list into one byte per size
|
|
|
|
res = []
|
|
|
|
res.append(sizes[0]) # first entry is first size
|
|
|
|
for i in xrange(1, len(sizes)):
|
|
prev = sizes[i - 1]
|
|
pred = int(prev * step_ratio) >> 10
|
|
diff = int(sizes[i] - pred)
|
|
res.append(diff)
|
|
|
|
if diff < 0 or diff > 127:
|
|
raise Exception('correction does not fit into 8 bits')
|
|
|
|
res.append(-1) # negative denotes last end of list
|
|
return res
|
|
|
|
def generate_probes(count, sizes):
|
|
res = []
|
|
|
|
# Generate probe values which are guaranteed to be relatively prime to
|
|
# all generated hash size primes. These don't have to be primes, but
|
|
# we currently use smallest non-conflicting primes here.
|
|
|
|
i = 2
|
|
while len(res) < count:
|
|
if is_prime(i) and (i not in sizes):
|
|
if i > 255:
|
|
raise Exception('probe step does not fit into 8 bits')
|
|
res.append(i)
|
|
i += 1
|
|
continue
|
|
i += 1
|
|
|
|
return res
|
|
|
|
# NB: these must match duk_hobject defines and code
|
|
step_ratio = 1177 # approximately (1.15 * (1 << 10))
|
|
min_size = 16
|
|
max_size = 2**32 - 1
|
|
|
|
sizes, ratios = generate_sizes(min_size, max_size, step_ratio)
|
|
corrections = generate_corrections(sizes, step_ratio)
|
|
probes = generate_probes(32, sizes)
|
|
print len(sizes)
|
|
print 'SIZES: ' + repr(sizes)
|
|
print 'RATIOS: ' + repr(ratios)
|
|
print 'CORRECTIONS: ' + repr(corrections)
|
|
print 'PROBES: ' + repr(probes)
|
|
|
|
# highest 32-bit prime
|
|
i = 2**32
|
|
while True:
|
|
i -= 1
|
|
if is_prime(i):
|
|
print 'highest 32-bit prime is: %d (0x%08x)' % (i, i)
|
|
break
|
|
|