Merge pull request #138 from mlochbaum/groupstat
Faster initial index scanning for Group
This commit is contained in:
commit
9023f6fe3b
@ -1 +1 @@
|
|||||||
Subproject commit 105c9b598a4e6eb90347a072042b3064a190bafb
|
Subproject commit 53f42ce4331176d281fa577408ec5a652bdd9127
|
||||||
@ -742,7 +742,7 @@ cachedBin‿linkerCache ← {
|
|||||||
"xag"‿"src/builtins/scan.c"‿"scan", "xag"‿"src/builtins/fold.c"‿"fold",
|
"xag"‿"src/builtins/scan.c"‿"scan", "xag"‿"src/builtins/fold.c"‿"fold",
|
||||||
"xag"‿"src/builtins/slash.c"‿"slash", "xag"‿"src/builtins/slash.c"‿"replicate",
|
"xag"‿"src/builtins/slash.c"‿"slash", "xag"‿"src/builtins/slash.c"‿"replicate",
|
||||||
"xag"‿"src/builtins/sort.c"‿"bins", "xa."‿"src/builtins/slash.c"‿"count"
|
"xag"‿"src/builtins/sort.c"‿"bins", "xa."‿"src/builtins/slash.c"‿"count"
|
||||||
"xag"‿"src/builtins/select.c"‿"select"
|
"xag"‿"src/builtins/select.c"‿"select", "xag"‿"src/builtins/group.c"‿"group"
|
||||||
⟩
|
⟩
|
||||||
objs ← ⟨⟩
|
objs ← ⟨⟩
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,11 @@
|
|||||||
#include "../utils/calls.h"
|
#include "../utils/calls.h"
|
||||||
#include "../utils/mut.h"
|
#include "../utils/mut.h"
|
||||||
|
|
||||||
|
#if SINGELI
|
||||||
|
#define SINGELI_FILE group
|
||||||
|
#include "../utils/includeSingeli.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern B ud_c1(B, B);
|
extern B ud_c1(B, B);
|
||||||
extern B ne_c2(B, B, B);
|
extern B ne_c2(B, B, B);
|
||||||
extern B slash_c1(B, B);
|
extern B slash_c1(B, B);
|
||||||
@ -57,17 +62,26 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xn, usz* xsh, u8 we) {
|
|||||||
bool bad = false, sort = true;
|
bool bad = false, sort = true;
|
||||||
usz neg = 0, change = 0;
|
usz neg = 0, change = 0;
|
||||||
void *wp0 = tyany_ptr(w);
|
void *wp0 = tyany_ptr(w);
|
||||||
|
#if SINGELI
|
||||||
|
#define ACCUM(T) \
|
||||||
|
u8 bad_t, sort_t; \
|
||||||
|
si_group_statistics_##T(wp0, xn, &bad_t, &neg, &sort_t, &change, &max); \
|
||||||
|
bad = bad_t; sort = sort_t;
|
||||||
|
#else
|
||||||
|
#define ACCUM(T) \
|
||||||
|
T prev = -1; \
|
||||||
|
for (usz i = 0; i < xn; i++) { \
|
||||||
|
T n = ((T*)wp0)[i]; \
|
||||||
|
if (n>max) max = n; \
|
||||||
|
bad |= n < -1; \
|
||||||
|
neg += n == -1; \
|
||||||
|
sort &= prev <= n; \
|
||||||
|
change += prev != n; \
|
||||||
|
prev = n; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#define CASE(T) case el_##T: { \
|
#define CASE(T) case el_##T: { \
|
||||||
T max = -1, prev = -1; \
|
T max = -1; ACCUM(T) \
|
||||||
for (usz i = 0; i < xn; i++) { \
|
|
||||||
T n = ((T*)wp0)[i]; \
|
|
||||||
if (n>max) max = n; \
|
|
||||||
bad |= n < -1; \
|
|
||||||
neg += n == -1; \
|
|
||||||
sort &= prev <= n; \
|
|
||||||
change += prev != n; \
|
|
||||||
prev = n; \
|
|
||||||
} \
|
|
||||||
if (wia>xn) { ria=((T*)wp0)[xn]; bad|=ria<-1; } \
|
if (wia>xn) { ria=((T*)wp0)[xn]; bad|=ria<-1; } \
|
||||||
i64 m=(i64)max+1; if (m>ria) ria=m; \
|
i64 m=(i64)max+1; if (m>ria) ria=m; \
|
||||||
break; }
|
break; }
|
||||||
@ -77,6 +91,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xn, usz* xsh, u8 we) {
|
|||||||
case el_bit: ria = xn? 1+bit_has(wp0,xn,1) : wia? bitp_get(wp0,0) : 0; break;
|
case el_bit: ria = xn? 1+bit_has(wp0,xn,1) : wia? bitp_get(wp0,0) : 0; break;
|
||||||
}
|
}
|
||||||
#undef CASE
|
#undef CASE
|
||||||
|
#undef ACCUM
|
||||||
if (bad) thrM("𝕨⊔𝕩: 𝕨 can't contain elements less than ¯1");
|
if (bad) thrM("𝕨⊔𝕩: 𝕨 can't contain elements less than ¯1");
|
||||||
if (ria > (i64)(USZ_MAX)) thrOOM();
|
if (ria > (i64)(USZ_MAX)) thrOOM();
|
||||||
|
|
||||||
|
|||||||
@ -283,7 +283,25 @@ B eequal_c2(B t, B w, B x) {
|
|||||||
#if TEST_RANGE
|
#if TEST_RANGE
|
||||||
#include "../utils/calls.h"
|
#include "../utils/calls.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if TEST_GROUP_STAT
|
||||||
|
extern void (*const si_group_statistics_i8)(void*,usz,uint8_t*,usz*,uint8_t*,usz*,int8_t*);
|
||||||
|
extern void (*const si_group_statistics_i16)(void*,usz,uint8_t*,usz*,uint8_t*,usz*,int16_t*);
|
||||||
|
extern void (*const si_group_statistics_i32)(void*,usz,uint8_t*,usz*,uint8_t*,usz*,int32_t*);
|
||||||
|
#endif
|
||||||
B internalTemp_c1(B t, B x) {
|
B internalTemp_c1(B t, B x) {
|
||||||
|
#if TEST_GROUP_STAT
|
||||||
|
u8 bad; usz neg; u8 sort; usz change; i32 max;
|
||||||
|
#define CASE(T) \
|
||||||
|
if (TI(x,elType)==el_##T) { T max_t; si_group_statistics_##T(tyany_ptr(x), IA(x), &bad, &neg, &sort, &change, &max_t); max = max_t; } \
|
||||||
|
else
|
||||||
|
CASE(i8) CASE(i16) CASE(i32)
|
||||||
|
thrM("bad eltype");
|
||||||
|
#undef CASE
|
||||||
|
decG(x);
|
||||||
|
f64* rp; B r = m_f64arrv(&rp, 5);
|
||||||
|
rp[0] = bad; rp[1] = neg; rp[2] = sort; rp[3] = change; rp[4] = max;
|
||||||
|
return r;
|
||||||
|
#endif
|
||||||
#if TEST_RANGE
|
#if TEST_RANGE
|
||||||
i64 buf[2];
|
i64 buf[2];
|
||||||
bool b = getRange_fns[TI(x,elType)](tyany_ptr(x), buf, IA(x));
|
bool b = getRange_fns[TI(x,elType)](tyany_ptr(x), buf, IA(x));
|
||||||
|
|||||||
@ -264,7 +264,10 @@ if_inline (hasarch{'X86_64'}) {
|
|||||||
} else {
|
} else {
|
||||||
def {
|
def {
|
||||||
__adds,__subs,__sqrt,vec_broadcast,vec_make,
|
__adds,__subs,__sqrt,vec_broadcast,vec_make,
|
||||||
vec_shift_left_128,vec_shift_right_128,vec_merge_shift_right,
|
vec_shift_left,vec_shift_left_128,
|
||||||
|
vec_shift_right,vec_shift_right_128,
|
||||||
|
vec_merge_shift_left,vec_merge_shift_left_128,
|
||||||
|
vec_merge_shift_right,vec_merge_shift_right_128,
|
||||||
vec_shuffle16_lo
|
vec_shuffle16_lo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
103
src/singeli/src/group.singeli
Normal file
103
src/singeli/src/group.singeli
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
include './base'
|
||||||
|
include './vecfold'
|
||||||
|
|
||||||
|
if_inline (hasarch{'SSE2'}) {
|
||||||
|
def fold_addw{v:V} = vfold{+, fold{+, mzip128{v, V**0}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
def vec_merge_shift_right{a:V=[n]_, b:V, s if hasarch{'SSE2'} and not hasarch{'SSSE3'}} = {
|
||||||
|
vec_shift_left{a, n-s} | vec_shift_right{b, s}
|
||||||
|
}
|
||||||
|
def vec_merge_shift_right{a:V, b:V, 1 if width{V}>128} = {
|
||||||
|
def nl = width{V}/128 # number of lanes
|
||||||
|
p:= vec_select{128, tup{a,b}, nl-1+iota{nl}}
|
||||||
|
vec_merge_shift_right_128{p, b, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __add{a:(usz), b:(u1)} = a + promote{usz,b}
|
||||||
|
def __lt{a:V=[_]_, b if knum{b}} = a < V**b
|
||||||
|
def __eq{a:V=[_]_, b if knum{b}} = a == V**b
|
||||||
|
|
||||||
|
def group_statistics{T} = {
|
||||||
|
def store{p:(*u8), 0, b:(u1)} = store{p, 0, promote{u8, b}}
|
||||||
|
|
||||||
|
def widen_sum = width{T} <= 8
|
||||||
|
def sum_vec = if (widen_sum) fold_addw else vfold{+, .}
|
||||||
|
|
||||||
|
def var{op, get} = {
|
||||||
|
# Identity, type
|
||||||
|
def id = match (op) { {(max)} => -1; {(&)} => 1; {_} => 0 }
|
||||||
|
def S = match (op) { {(max)} => T; {(+)} => usz; {_} => u1 }
|
||||||
|
|
||||||
|
# Scalar accumulator
|
||||||
|
def updater{v,op}{...a} = { v = op{v, get{...a}} }
|
||||||
|
def scal{val} = {
|
||||||
|
v:S = val
|
||||||
|
tup{v, updater{v, op}}
|
||||||
|
}
|
||||||
|
def scal{} = scal{id}
|
||||||
|
|
||||||
|
# Vector accumulator
|
||||||
|
def vec{l} = {
|
||||||
|
def V = match (S) { {(T)} => [l]T; {_} => [l]ty_u{T} }
|
||||||
|
v := V**(if (id==1) maxvalue{ty_u{T}} else id)
|
||||||
|
def u = updater{v, if (same{op,+}) (-) else op}
|
||||||
|
def {flush, get} = if (S!=usz) {
|
||||||
|
def get = match (op) {
|
||||||
|
{(&)} => all_hom
|
||||||
|
{(|)} => any_hom
|
||||||
|
{(max)} => vfold{max, .}
|
||||||
|
}
|
||||||
|
tup{{}=>{}, {} => get{v}}
|
||||||
|
} else {
|
||||||
|
f:usz = 0
|
||||||
|
def flush{} = { f += cast_i{usz, sum_vec{v}}; v = V**0 }
|
||||||
|
tup{flush, {} => f}
|
||||||
|
}
|
||||||
|
tup{u, flush, get}
|
||||||
|
}
|
||||||
|
tup{if (S==u1) u8 else S, scal, vec}
|
||||||
|
}
|
||||||
|
def {types, init_scal, init_vec} = each{tup,
|
||||||
|
var{|, {_,w} => w < -1}, # bad
|
||||||
|
var{+, {_,w} => w == -1}, # neg
|
||||||
|
var{&, {p,w} => p <= w }, # sort
|
||||||
|
var{+, {p,w} => p != w }, # change
|
||||||
|
var{max, {_,w} => w } # max
|
||||||
|
}
|
||||||
|
def run{g, ...par} = g{...par}
|
||||||
|
def runvars{gens, ...par} = each{run{., ...par}, gens}
|
||||||
|
|
||||||
|
fn group_statistics(w0:*void, xn:usz, outs:each{__pnt,types}) : void = {
|
||||||
|
def {start, init} = if (not has_simd) tup{0, tup{}} else {
|
||||||
|
def vl = arch_defvw/width{T}; def V = [vl]T
|
||||||
|
def {accum, flush, get} = flip{runvars{init_vec, vl}}
|
||||||
|
e:= xn / vl
|
||||||
|
i:usz = 0
|
||||||
|
prev:V = V**(-1)
|
||||||
|
while (i < e) {
|
||||||
|
def lmax = 1 << (width{T}-1 - (not widen_sum)*lb{vl})
|
||||||
|
l:= min{usz~~lmax, e-i}
|
||||||
|
@for (w in *V~~w0 + i over l) {
|
||||||
|
runvars{accum, vec_merge_shift_right{prev, w, 1}, w}
|
||||||
|
prev = w
|
||||||
|
}
|
||||||
|
i+= l
|
||||||
|
runvars{flush}
|
||||||
|
}
|
||||||
|
tup{e*vl, tup{runvars{get}}}
|
||||||
|
}
|
||||||
|
def {vals, accum} = flip{each{run, init_scal, ...init}}
|
||||||
|
prev:T = -1
|
||||||
|
if (start > 0) prev = load{*T~~w0, start-1}
|
||||||
|
@for (w in *T~~w0 over _ from start to xn) {
|
||||||
|
runvars{accum, prev,w}
|
||||||
|
prev = w
|
||||||
|
}
|
||||||
|
each{store{.,0,.}, outs, vals}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export{'si_group_statistics_i8', group_statistics{i8}}
|
||||||
|
export{'si_group_statistics_i16', group_statistics{i16}}
|
||||||
|
export{'si_group_statistics_i32', group_statistics{i32}}
|
||||||
19
test/cases/build-specific/test_group_stat.bqn
Normal file
19
test/cases/build-specific/test_group_stat.bqn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# needs: Singeli & -DTEST_GROUP_STAT
|
||||||
|
"basic test doesn't work; are you on a -DTEST_GROUP_STAT build?" ! 0‿0‿1‿10‿9 ≡ •internal.Temp ↕10
|
||||||
|
|
||||||
|
%DEF tvar AllEq←{v←⊑𝕩 ⋄ {𝕩≡v?1;!𝕩‿v}¨ ⥊𝕩 ⋄ v} ⋄ _tvar ← {Sel _𝕣 a: AllEq {Sel •internal.Temp 𝕩•internal.Variation a}¨ ∊⟜"Ai8"‿"Ai16"‿"Ai32"⊸/ •internal.ListVariations •internal.Squeeze a}
|
||||||
|
%USE tvar ⋄ ⊢_tvar ↕10 %% 0‿0‿1‿10‿9
|
||||||
|
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq {⊑_tvar ¯2⌾(𝕩⊸⊑) a}¨ ↕𝕩}¨ 1+↕40 %% 1
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq {⊑_tvar ¯128⌾(𝕩⊸⊑) a}¨ ↕𝕩}¨ 1+↕40 %% 1
|
||||||
|
|
||||||
|
%USE tvar ⋄ AllEq {⊢_tvar 𝕩⥊0}¨ 1+↕1000 %% 0‿0‿1‿1‿0
|
||||||
|
%USE tvar ⋄ AllEq {⊢_tvar 𝕩⥊10}¨ 1+↕1000 %% 0‿0‿1‿1‿10
|
||||||
|
%USE tvar ⋄ {! ⟨0,0,0,𝕩,3⟩ ≡ ⊢_tvar 𝕩⥊3‿2}¨ 2+↕1000
|
||||||
|
%USE tvar ⋄ {! ⟨0,0,1,𝕩,𝕩-1⟩ ≡ ⊢_tvar ↕𝕩}¨ 1+↕1000
|
||||||
|
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq {0‿1‿2‿4⊸⊏_tvar 3⌾(𝕩⊸⊑) a}¨ ↕𝕩-1}¨ 2+↕40 %% 0‿0‿0‿3
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq { ⊢_tvar 9⌾(𝕩⊸⊑) a}¨ 1+↕𝕩-2}¨ 3+↕40 %% 0‿0‿0‿3‿9
|
||||||
|
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq {0‿1‿4⊸⊏_tvar ¯1⌾(𝕩⊸⊑) a}¨ ↕𝕩}¨ 2+↕40 %% 0‿1‿0
|
||||||
|
%USE tvar ⋄ AllEq {a←𝕩⥊0 ⋄ AllEq {0‿1‿4⊸⊏_tvar 12⌾(𝕩⊸⊑) a}¨ ↕𝕩}¨ 1+↕40 %% 0‿0‿12
|
||||||
Loading…
Reference in New Issue
Block a user