diff --git a/src/singeli/src/hashtab.singeli b/src/singeli/src/hashtab.singeli index a67cff5f..a3335894 100644 --- a/src/singeli/src/hashtab.singeli +++ b/src/singeli/src/hashtab.singeli @@ -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< { 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}} } diff --git a/src/singeli/src/search.singeli b/src/singeli/src/search.singeli index a46e37fd..c5c032b0 100644 --- a/src/singeli/src/search.singeli +++ b/src/singeli/src/search.singeli @@ -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 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=0, sz=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= cc_stop) { i=0; goto{abort} } + } } } - setlabel{insert_finish} } def get_end{} = { end := maxh>>sh diff --git a/src/singeli/src/selfsearch.singeli b/src/singeli/src/selfsearch.singeli index 9aacc666..fcf3b0b5 100644 --- a/src/singeli/src/selfsearch.singeli +++ b/src/singeli/src/selfsearch.singeli @@ -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} } } }