Changeset: 84422ee91c69 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=84422ee91c69 Modified Files: Branch: default Log Message:
merge from Jun2010: " changeset: 35959:20153e10ec8a branch: Jun2010 tag: tip parent: 35946:a5ef8be5bf23 parent: 35958:15ebf7087032 user: Stefan Manegold <[email protected]> date: Sun May 16 10:07:11 2010 +0200 files: MonetDB5/src/modules/kernel/group.mx description: merge from Feb2010: " changeset: 35958:15ebf7087032 branch: Feb2010 tag: tip parent: 35945:4e039e33fe3c user: Stefan Manegold <[email protected]> date: Sun May 16 10:05:18 2010 +0200 files: MonetDB5/src/modules/kernel/group.mx description: performance bug fix: revived refined clustered derive over ordered groups Due to its inherent random access, hash-based grouping and sub-grouping (derive) of BATs that exceed main-memory size is very "painful" (slow). However, it appears that in many practical cases, at least on of the group-by columns is sorted. SQL translation already ensures that this column is used first for grouping, enabling a simple sequential access scan-based grouping, and resulting in ordered disjoint outer groups. Subsequent derives can then exploit this property to limit random access during derive as follows: (1) instead of and actual derive step, perform a simple grouping step on each outer group, i.e., for each outer value, possibly even exploiting per outer group (sub-) sortedness; (2) perform individual and independent in-memory derives over disjoint slices that collect multiple complete outer groups. Experimentation suggests that (1) is too sensitive to data distribution, in particular with many small outer groups the overhead appears to be too large. With chuck sizes tuned to be large but fit in memory, (2) appears to perform quite well, e.g., reducing a two-cloumn grouped count (with one column sorted) over a 2.2 billion records table (32 GB CSV) on a 8 GB machine from 25 h to just over 1 h. Caveat: Due to a different translation path (for insiders: group by on mkey-like combined hashes over all relevant columns), this has no effect (improvement) on creating (multi-column) primary keys. " " diffs (176 lines): diff -r 82fea21df3be -r 84422ee91c69 MonetDB5/src/modules/kernel/group.mx --- a/MonetDB5/src/modules/kernel/group.mx Sun May 16 00:29:17 2010 +0200 +++ b/MonetDB5/src/modules/kernel/group.mx Sun May 16 10:08:15 2010 +0200 @@ -809,6 +809,7 @@ *hdst++ = *(oid*) BUNhead(bi,p); *dst++ = e->use.gid; } + bn->tsorted = 0; BATsetcount(bn, (BUN) (dst - (oid *) bn->T->heap.base)); if (hash) GDKfree(hash); @@ -927,10 +928,10 @@ Of course, with inputs that exceed main memory size, ordered data allows for rather straight forward partitioning into (few) large chunks that fit into -main memory to perform the derive step of each chunk independintly in +main memory to perform the derive step of each chunk independently in memory. These chunks can consist of multiple "outer" groups, provided each chunk contains only complete outer groups. -I will prepare the respective code. +This is what "CTderive_clustered()" (see below) does. */ /* partion based sub-order derive */ @@ -1027,8 +1028,123 @@ @c static int +derive(BAT **H, BAT **M, BAT *ct_histo, BAT *ct_map, BAT *b, int tt); + +/* break large (out-of-memory) derive over ordered outer groups into + * disjoint slices that fit into memory and perform in-memory derive step + * independently on each slice + */ +static int +CTderive_clustered(BAT **H, BAT **M, BAT *_histo, BAT *_map, BAT *_b, int tt, wrd limit) +{ + wrd s0 = 0, s1 = 0, *t = 0; + BUN i0 = 0, i1 = 0, j = 0; + BAT *mn = 0, *hn = 0; + + if (!_histo || !_map || !_b) + return GDK_FAIL; + + /* complete result map */ + mn = BATnew(TYPE_void, TYPE_oid, BATcount(_b)); + if (!mn) + return GDK_FAIL; + /* complete result histo */ + hn = BATnew(TYPE_oid, TYPE_wrd, BATcount(_b)); + if (!mn) { + BBPreclaim(mn); + return GDK_FAIL; + } + /* outer group sizes */ + t = (wrd*)Tloc(_histo, BUNfirst(_histo)); + /* number of outer groups */ + j = BATcount(_histo); + + /* iterate over outer groups */ + while (i1 < j) { + BAT *ct_histo, *ct_map, *b, *histo = 0, *bn = 0; + + /* collect outer groups for large in-memory slice */ + s1 = t[i1++]; + while (i1 < j && s1 + t[i1] < limit) + s1 += t[i1++]; + s1 += s0; + + /* get disjoint slices of input */ + b = BATslice(_b, (BUN)s0, (BUN)s1); + ct_map = BATslice(_map, (BUN)s0, (BUN)s1); + ct_histo = BATslice(_histo, (BUN)i0, (BUN)i1); + if (!b || !ct_map || !ct_histo) { + if (b) + BBPreleaseref(b->batCacheid); + if (ct_map) + BBPreleaseref(ct_map->batCacheid); + if (ct_histo) + BBPreleaseref(ct_histo->batCacheid); + BBPreclaim(mn); + BBPreclaim(hn); + return GDK_FAIL; + } + /* invest in scan to check tail-sortedness */ + /* (net effect: make required data hot) */ + (void)BATordered(BATmirror(b)); + + bn = BATnew(TYPE_void, TYPE_oid, BATcount(b)); + if (bn == NULL) { + BBPreleaseref(b->batCacheid); + BBPreleaseref(ct_map->batCacheid); + BBPreleaseref(ct_histo->batCacheid); + BBPreclaim(mn); + BBPreclaim(hn); + return GDK_FAIL; + } + + /* perform derive on independent slice */ + @:choosederive(sync,clustered)@ + if (histo == NULL) { + BBPreleaseref(b->batCacheid); + BBPreleaseref(ct_map->batCacheid); + BBPreleaseref(ct_histo->batCacheid); + BBPreclaim(mn); + BBPreclaim(hn); + BBPreclaim(bn); + return GDK_FAIL; + } + + BBPreleaseref(b->batCacheid); + BBPreleaseref(ct_map->batCacheid); + BBPreleaseref(ct_histo->batCacheid); + + /* invest in scan to check tail-sortedness */ + /* (data is still hot) */ + (void)BATordered(BATmirror(bn)); + /* append partial map to total map */ + BATappend(mn, bn, FALSE); + BBPreclaim(bn); + + /* invest in scan to check head- & tail-sortedness */ + /* (data is still hot) */ + (void)BATordered(histo); + (void)BATordered(BATmirror(histo)); + /* append partial histo to total histo */ + BATins(hn, histo, FALSE); + BBPreclaim(histo); + + s0 = s1; + i0 = i1; + } + + /* initialize map head */ + ALIGNsetH(mn, _b); + + *H = hn; + *M = mn; + return grp_new(mn, hn);; +} + +static int derive(BAT **H, BAT **M, BAT *ct_histo, BAT *ct_map, BAT *b, int tt) { + wrd limit = (wrd)((MT_npages() * MT_pagesize()) / (100 * GDKnr_threads)); BAT *histo = NULL, *bn = NULL; int synced = ALIGNsynced(ct_map, b); @@ -1036,6 +1152,19 @@ int ht = (synced && BAThdense(b)) ? TYPE_void : TYPE_oid; if (!ct_map->tkey) { /* cannot derive more groups */ + if (synced && + !BATtkey(b) && + BAThdense(b) && + BATtordered(ct_map)&1 && + BAThordered(ct_histo) && + (wrd)BATcount(b) > 2 * limit) { + /* break large (out-of-memory) derive over ordered + * outer groups into disjoint slices that fit into + * memory and perform in-memory derive step + * independently on each slice + */ + return CTderive_clustered(H, M, ct_histo, ct_map, b, tt, limit); + } #if 0 /* see comment above */ if (!b->tkey && BATcount(b) > 1 && BATtordered(ct_map)&1 && @@ -1077,7 +1206,6 @@ } /* postprocess the result bat 'bn' */ - bn->tsorted = 0; if (BATcount(bn) == BATcount(b)) { ALIGNsetH(bn, b); } else { _______________________________________________ Checkin-list mailing list [email protected] http://mail.monetdb.org/mailman/listinfo/checkin-list
