Credible resizing policy for dyadic search hashes
This commit is contained in:
parent
ee7a11a279
commit
09572de49a
@ -35,12 +35,13 @@ def hash_val{x:u32 & hasarch{'SSE4.2'}} = {
|
||||
# Allocate and initialize resizing hash table
|
||||
# Initial size sz+ext and maximum size msz+ext
|
||||
# One region for each type in Ts initialized with value from v0s
|
||||
def hash_alloc{logsz, msz, ext, Ts, v0s, ordered} = {
|
||||
def hash_alloc{logsz, msz, ext, Ts, v0s, has_radix, ordered} = {
|
||||
def ws = each{width,Ts}
|
||||
def wt = tupsel{0,ws}
|
||||
each{assert, slice{ws,0,-1} >= slice{ws,1}} # Doesn't do alignment
|
||||
# Variables updated on resize
|
||||
sz := usz~~1 << logsz
|
||||
sh := tupsel{0,ws} - logsz
|
||||
sh := wt - logsz
|
||||
|
||||
def add{}=0; def add{a,...r} = a+add{...r}
|
||||
halloc := talloc{u8, (msz+ext)*add{...ws/8}}
|
||||
@ -56,6 +57,7 @@ def hash_alloc{logsz, msz, ext, Ts, v0s, ordered} = {
|
||||
def hash_resize{cc, m} = {
|
||||
dif := sz*((1<<m)-1)
|
||||
sh -= m; sz <<= m
|
||||
set_thresh{}
|
||||
cc = 0
|
||||
k:tupsel{0,Ts} = 0; --k
|
||||
each{{p,v} => { p -= dif; memset{p, v, dif} }, ptrs, v0s}
|
||||
@ -84,5 +86,18 @@ def hash_alloc{logsz, msz, ext, Ts, v0s, ordered} = {
|
||||
}
|
||||
}
|
||||
|
||||
tup{ptrs, sz, sh, hash_resize, {}=>tfree{halloc}}
|
||||
# Test for resize if more than 1/2^t collisions/element
|
||||
t:usz = 0 # Shift amount
|
||||
def div_thresh{i} = i>>t
|
||||
# Threshold setter, re-applied on resize
|
||||
def set_thresh{} = {
|
||||
if (sz==msz) t = 0
|
||||
else if ((not has_radix) and sz>=(1<<24)/wt) t = 0
|
||||
else if ( sz>=(1<<20)/wt) t = 3
|
||||
else t = 5
|
||||
}
|
||||
tup{set_thresh, div_thresh}
|
||||
set_thresh{}
|
||||
|
||||
tup{ptrs, sz, sh, div_thresh, hash_resize, {}=>tfree{halloc}}
|
||||
}
|
||||
|
||||
@ -344,7 +344,6 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
||||
def swap_sides{} = each{{a,b}=>{t:=a; a=b; b=t}, tup{ip,m}, tup{fp,n}}
|
||||
swap:u1 = n+(1024*(prim!='⊒')) < (if (prim!='∊') m else m-m/4)
|
||||
if (swap) swap_sides{}
|
||||
def stop = m
|
||||
|
||||
log := clzc{m}
|
||||
# Max size
|
||||
@ -356,11 +355,12 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
||||
|
||||
# Filling e slots past the end requires e*(e+1)/2 collisions, so
|
||||
# m entries with <2 each can fill <sqrt(4*m)
|
||||
ext := tern{m<=b, m, b + (usz~~1 << (log/2 + 1))}
|
||||
def cc_stop = 2*m
|
||||
ext := tern{m<=b, max{m,usz~~4}, b + (usz~~1 << (log/2 + 1))}
|
||||
maxh := T~~maxvalue{T}
|
||||
def aux = prim!='∊'
|
||||
def {tabs, sz, sh, hash_resize, hash_free} = hash_alloc{
|
||||
sl, msz, ext, tup{T, ...aux**u32}, tup{maxh, ...aux**'any'}, 1
|
||||
def {tabs, sz, sh, div_thresh, hash_resize, hash_free} = hash_alloc{
|
||||
sl, msz, ext, tup{T, ...aux**u32}, tup{maxh, ...aux**'any'}, 0, 1
|
||||
}
|
||||
def {hash,...vals} = tabs
|
||||
|
||||
@ -368,8 +368,7 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
||||
i:usz = 0 # Saved to determine if hashing finished
|
||||
def insert_all{set_tab, set_maxh, dup, ...uniq} = {
|
||||
cc:usz = 0 # Collision counter
|
||||
def insert_finish = makelabel{}
|
||||
while (1) {
|
||||
while (i < m) {
|
||||
e := tern{m-i>b, i+b, m}
|
||||
while (i < e) {
|
||||
def ii = if (prim!='⊒') i else m-i-1
|
||||
@ -395,15 +394,21 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
||||
set_tab{j, h}
|
||||
++i
|
||||
}
|
||||
if (i == m) goto{insert_finish}
|
||||
# Check collision counter and possibly resize (needs tuning)
|
||||
if (cc >= stop and sz == msz) goto{abort}
|
||||
if (16*cc >= stop and sz < msz) {
|
||||
hash_resize{cc, 2} # Factor of 4
|
||||
if (cc >= stop) goto{abort}
|
||||
# Check collision counter and possibly resize
|
||||
def p64 = promote{u64,.}
|
||||
dc := p64{cc} - p64{div_thresh{i}}
|
||||
if (tern{i<m, i64~~dc>=0, sz<msz}) {
|
||||
if (sz == msz) goto{abort}
|
||||
rdc := p64{m-i}*dc # 0 if i==m, no need to recompute
|
||||
mm := p64{i}*p64{m+i}
|
||||
def recheck = setlabel{}
|
||||
if (cc>=cc_stop or p64{n/4}*p64{cc} + rdc >= mm>>(5+log-(wt-sh))) {
|
||||
hash_resize{cc, 2} # Factor of 4
|
||||
if (i==m and sz<msz) goto{recheck}
|
||||
if (cc >= cc_stop) { i=0; goto{abort} }
|
||||
}
|
||||
}
|
||||
}
|
||||
setlabel{insert_finish}
|
||||
}
|
||||
def get_end{} = {
|
||||
end := maxh>>sh
|
||||
|
||||
@ -8,7 +8,7 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = {
|
||||
def wt = width{T}
|
||||
def prim = to_prim{name}
|
||||
def has_radix = if (prim=='⊐') 0 else wt==32
|
||||
def {res0,stop} = if (prim=='∊') tup{1,n>>has_radix} else tup{0,2*n}
|
||||
def {res0,cc_stop} = if (prim=='∊') tup{1,n>>has_radix} else tup{0,2*n}
|
||||
|
||||
log := clzc{n}
|
||||
# Max size
|
||||
@ -24,25 +24,10 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = {
|
||||
x0 := hash_val{xp->0}
|
||||
rp <-{0} res0
|
||||
def aux = prim!='∊'
|
||||
def {{hash,...vals}, sz, sh, hash_resize, hash_free} = hash_alloc{
|
||||
sl, msz, ext, tup{T, ...aux**u32}, tup{x0, ...aux**0}, 0
|
||||
def {{hash,...vals}, sz, sh, div_thresh, hash_resize, hash_free} = hash_alloc{
|
||||
sl, msz, ext, tup{T, ...aux**u32}, tup{x0, ...aux**0}, has_radix, 0
|
||||
}
|
||||
|
||||
# Resize or abort if more than 1/2^thresh collisions/element
|
||||
def {set_thresh, div_thresh} = {
|
||||
t:usz = 0 # Shift amount
|
||||
def div_thresh{i} = i>>t
|
||||
# Threshold setter, re-applied on resize
|
||||
def set_thresh{} = {
|
||||
if (sz==msz) t = 0
|
||||
else if ((not has_radix) and sz>=(1<<24)/wt) t = 0
|
||||
else if ( sz>=(1<<20)/wt) t = 3
|
||||
else t = 5
|
||||
}
|
||||
tup{set_thresh, div_thresh}
|
||||
}
|
||||
set_thresh{}
|
||||
|
||||
def {output, write_res} = match (prim) {
|
||||
{('∊')} => tup{{b}=>b, {j,h,k,x0} => { hash<-{j}h; k!=h }}
|
||||
{('⊒')} => {
|
||||
@ -83,10 +68,9 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = {
|
||||
if (sz == msz) goto{break} # Abort
|
||||
if (has_radix and i < n/2 and sz >= 1<<18) goto{break}
|
||||
# Avoid resizing if close to the end
|
||||
if (cc>=stop or p64{n-i}*dc >= (p64{i}*p64{n+i})>>(5+log-(wt-sh))) {
|
||||
if (cc>=cc_stop or p64{n-i}*dc >= (p64{i}*p64{n+i})>>(5+log-(wt-sh))) {
|
||||
hash_resize{cc, 2} # Factor of 4
|
||||
if (cc >= stop) goto{break}
|
||||
set_thresh{}
|
||||
if (cc >= cc_stop) goto{break}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user