diff options
| author | eunhhu <[email protected]> | 2026-10-09 14:24:51 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-09 14:24:51 +0100 |
| commit | 82b99bfaa673265778df511b36ab22f0563049c0 (patch) | |
| tree | 4c274fc352f6225b5bc174a557fb336439467db5 /core | |
| parent | 2427fbe9227de6fcea13addaf7ca6d82d9829957 (diff) | |
| download | pure-82b99bfaa673265778df511b36ab22f0563049c0.tar.gz pure-82b99bfaa673265778df511b36ab22f0563049c0.zip | |
Batch executor, stage 5 of design 025: the sums into cells at once from round 0 (sums_in_words): the rows and e's in four bytes first (vector code) up to the first round whose e is not a whole number below 2^32, then each round's sums in turn in integers for a one- or four-byte cell while it stays in its bytes, as a number for an eight-byte cell while finite; where one is not so the executor's way goes on from that round and sum (nothing faulted or widened before it); join 4.9% fewer cycles; SUMS_SOURCE in check.py (sixteen rows met again and again, a one-byte column widened mid-batch, a four-byte one past 2^32, a masked fraction), 7,912 rounds at once and 3,228 the other way, the same three ways; seeds 1 2 3 5 23 (default and PURE_SELECT=all), the fixed sources (also sanitized) and the unit tests pass
Diffstat (limited to 'core')
| -rw-r--r-- | core/module-batch.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/core/module-batch.c b/core/module-batch.c index 0d02e45..ba19850 100644 --- a/core/module-batch.c +++ b/core/module-batch.c @@ -3143,6 +3143,77 @@ static int append_items(Batch *b, Frame *frame, unsigned n, uint64_t per) { static int batch_run(Frame *frame, Loop *loop, unsigned *done); +/* The sums into cells from round 0 at once (docs/design/025, stage 5): the + * round's sums in turn, a one- or four-byte cell's in integers while its e + * is a whole number below 2^32 and its sum stays in its bytes, an + * eight-byte cell's as a number while it is finite (the numbers the + * executor's adds would make, with no fault and no widening). The rows and + * the e's in four bytes first (vector code), up to the first round whose e + * is not one. Where one is not so, *round and *sum: the executor's way goes + * on from there. */ +static void sums_in_words(Batch *b, const double *const *rows, const double *const *es, const uint32_t *const *masks, + const PureCells *cells, unsigned *round, unsigned *sum) { + unsigned n = b->n, count = b->scatter_count, stop = n, spares = b->spare_count, buffers = b->buffers; + bool reverse = b->reverse, failed = b->failed; + uint32_t *row32[SUMS], *e32[SUMS]; + *round = 0, *sum = 0; + for (unsigned i = 0; i < count; ++i) { + uint8_t width = cells[i].width[b->scatters[i].field]; + if ((width != 8 && width != 4 && width != 1) || !(row32[i] = fresh(b)) || (width != 8 && !(e32[i] = fresh(b)))) { + b->spare_count = spares, b->buffers = buffers, b->failed = failed; /* (the rounds one by one) */ + return; + } + const double *at = rows[i], *e = es[i]; + for (unsigned l = 0; l < n; ++l) row32[i][l] = at[l] >= 0 && at[l] < 4294967296.0 ? (uint32_t)at[l] : 0; + if (width == 8) continue; + uint32_t bad = 0, *out = e32[i]; + for (unsigned l = 0; l < n; ++l) { + uint32_t u = e[l] >= 0 && e[l] < 4294967296.0 ? (uint32_t)e[l] : 0; + out[l] = u, bad |= (double)u != e[l]; + } + for (unsigned l = 0; bad && l < n; ++l) /* the first round (of those it runs in) whose e is not a whole number below 2^32 */ + if ((!masks[i] || masks[i][l]) && (double)out[l] != e[l]) { + unsigned r = reverse ? n - 1 - l : l; + stop = r < stop ? r : stop; + } + } + for (unsigned r = 0; r < stop; ++r) { + unsigned l = reverse ? n - 1 - r : r; + for (unsigned i = 0; i < count; ++i) { + if (masks[i] && !masks[i][l]) continue; + uint8_t width = cells[i].width[b->scatters[i].field]; + void *column = cells[i].columns[b->scatters[i].field]; + uint32_t row = row32[i][l]; + if (width == 8) { + double v; + memcpy(&v, (const double *)column + row, sizeof(v)); + v += es[i][l]; + if (!isfinite(v)) { + stop = r, *sum = i; + break; + } + memcpy((double *)column + row, &v, sizeof(v)); + } else if (width == 4) { + uint64_t v = (uint64_t)((uint32_t *)column)[row] + e32[i][l]; + if (v >> 32) { + stop = r, *sum = i; + break; + } + ((uint32_t *)column)[row] = (uint32_t)v; + } else { + uint32_t v = ((uint8_t *)column)[row] + e32[i][l]; + if (v > 255) { + stop = r, *sum = i; + break; + } + ((uint8_t *)column)[row] = (uint8_t)v; + } + } + } + *round = stop; + b->spare_count = spares, b->buffers = buffers; /* its four bytes let go */ +} + /* A batch (batch_run), the filters' rounds and keys let go after it (held only while one runs: a thread keeps none). */ int pure_batch_run(Frame *frame, Loop *loop, unsigned *done) { int how = batch_run(frame, loop, done); @@ -3234,9 +3305,11 @@ static int batch_run(Frame *frame, Loop *loop, unsigned *done) { return STEP_NEXT; } } - for (unsigned r = 0; r < n; ++r) { + unsigned from_round, from_sum; + sums_in_words(b, rows, es, masks, cells, &from_round, &from_sum); + for (unsigned r = from_round; r < n; ++r) { /* the rest round by round, as the executor adds and sets */ unsigned l = round_of(b, r); - for (unsigned i = 0; i < b->scatter_count; ++i) { + for (unsigned i = r == from_round ? from_sum : 0; i < b->scatter_count; ++i) { const Scatter *sc = &b->scatters[i]; if (masks[i] && !masks[i][l]) continue; size_t row = (size_t)rows[i][l]; |
