diff options
| author | eunhhu <[email protected]> | 2026-09-30 17:27:32 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-30 17:27:32 +0100 |
| commit | 07047c391f32c43827c0da145f6c89edb5007941 (patch) | |
| tree | f119fd54e7047c990d05a59d7ef49d7ddac5dafc /core | |
| parent | 481642fbdc94db37ae42ded7244674054b6377c3 (diff) | |
| download | pure-07047c391f32c43827c0da145f6c89edb5007941.tar.gz pure-07047c391f32c43827c0da145f6c89edb5007941.zip | |
Keep i64 off the number paths: lanes fold numbers, cells read as bytes
Counting user-mode instructions per query (bank, 100,000 accounts)
against ee21aec found what i64 had added to the number paths, and an
instruction sampler found where:
- fold_in took a union and asked whether the fold was of i64s for every
item, in the group and leaf-at-a-time passes too, where a fold of
i64s never runs (it is never planned). Those passes now call
fold_number, which takes a double; fold_in keeps the i64 branch for
folds run item by item. per_branch: 27.83M instructions an ask back
to 27.05M (26.72M before i64).
- cell_at's third kind made it too big to inline into pure_list_get,
so every item read became a call. A number's, bool's or integer's
cell is 8 bytes read as they are (memcpy, so no aliasing rule is
bent), one branch as before, and it inlines again. A table of 10,000
rows: 8.78M instructions an ask to 8.70M (8.58M before i64).
Behaviour is unchanged; every check passes.
Diffstat (limited to 'core')
| -rw-r--r-- | core/module-list.c | 13 | ||||
| -rw-r--r-- | core/module.c | 41 |
2 files changed, 35 insertions, 19 deletions
diff --git a/core/module-list.c b/core/module-list.c index 51148eb..ac622cc 100644 --- a/core/module-list.c +++ b/core/module-list.c @@ -130,11 +130,16 @@ static double *numbers(const Layout *l, const Node *leaf, unsigned f) { return ( static int64_t *integers(const Layout *l, const Node *leaf, unsigned f) { return (int64_t *)((char *)leaf + l->column[f]); } static PureSpan *texts(const Layout *l, const Node *leaf, unsigned f) { return (PureSpan *)((char *)leaf + l->column[f]); } +/* A number's, bool's or integer's cell is its 8 bytes, read as they are + * (whichever it holds; the reader's kind says which). */ static PureCell cell_at(const Layout *l, const Node *leaf, unsigned i, unsigned f) { - if (l->kinds[f] == PURE_CELL_INTEGER) return (PureCell){.i64 = integers(l, leaf, f)[i]}; - if (!pure_cell_text(l->kinds[f])) return (PureCell){.num = numbers(l, leaf, f)[i]}; - PureSpan text = texts(l, leaf, f)[i]; - return (PureCell){.text = (unsigned char *)text.data, .size = text.size}; + PureCell cell = {0}; + if (!pure_cell_text(l->kinds[f])) memcpy(&cell.i64, (const char *)leaf + l->column[f] + 8 * (size_t)i, 8); + else { + PureSpan text = texts(l, leaf, f)[i]; + cell.text = (unsigned char *)text.data, cell.size = text.size; + } + return cell; } static void put_cells(const Layout *l, Node *leaf, unsigned i, const PureCell *cells) { diff --git a/core/module.c b/core/module.c index 7c3a0ac..2688395 100644 --- a/core/module.c +++ b/core/module.c @@ -1956,8 +1956,9 @@ static bool seen_new(Seen *seen, double value, bool *full) { } /* One item: its value, and whether it counts (for count and first, the - * value is). false without memory (a distinct fold's set). */ -static bool fold_in(Fold *fold, size_t row, PureValue value, double counts) { + * value is). false without memory (a distinct fold's set). A fold of i64s + * is never planned, so a leaf's lanes (numbers) come here alone. */ +static bool fold_number(Fold *fold, size_t row, double value, double counts) { if (counts == 0) return true; unsigned how = fold->how; if (how == PURE_FOLD_FIRST) { @@ -1967,22 +1968,32 @@ static bool fold_in(Fold *fold, size_t row, PureValue value, double counts) { } if (how == PURE_FOLD_DISTINCT) { bool full = false; - fold->total += fold->integer ? seen_bits(&fold->seen, (uint64_t)value.i64, &full) : seen_new(&fold->seen, value.num, &full); + fold->total += seen_new(&fold->seen, value, &full); fold->any = true; return !full; } - if (fold->integer) { /* an i64's sum, most or least */ - int64_t v = value.i64; - if (how == PURE_FOLD_SUM) { - if (__builtin_add_overflow(fold->whole, v, &fold->whole)) fold->overflow = fold->done = true; - } else if (!fold->any || (how == PURE_FOLD_MAX ? v > fold->whole : v < fold->whole)) - fold->whole = v; + fold->total = how == PURE_FOLD_COUNT ? fold->total + 1 : how == PURE_FOLD_SUM ? fold->total + value : + !fold->any ? value : how == PURE_FOLD_MAX ? maximum(fold->total, value) : minimum(fold->total, value); + fold->any = true; + return true; +} + +/* One item run as written: a number's, or an i64's (a sum past the range + * overflows and ends the fold; count and first take no i64). */ +static bool fold_in(Fold *fold, size_t row, PureValue value, double counts) { + if (!fold->integer) return fold_number(fold, row, value.num, counts); + if (counts == 0) return true; + int64_t v = value.i64; + if (fold->how == PURE_FOLD_DISTINCT) { + bool full = false; + fold->total += seen_bits(&fold->seen, (uint64_t)v, &full); fold->any = true; - return true; + return !full; } - double number = value.num; - fold->total = how == PURE_FOLD_COUNT ? fold->total + 1 : how == PURE_FOLD_SUM ? fold->total + number : - !fold->any ? number : how == PURE_FOLD_MAX ? maximum(fold->total, number) : minimum(fold->total, number); + if (fold->how == PURE_FOLD_SUM) { + if (__builtin_add_overflow(fold->whole, v, &fold->whole)) fold->overflow = fold->done = true; + } else if (!fold->any || (fold->how == PURE_FOLD_MAX ? v > fold->whole : v < fold->whole)) + fold->whole = v; fold->any = true; return true; } @@ -2043,7 +2054,7 @@ static PureResult fold_runs(const PureModule *m, PureValue *values, PureBlock in fold->any = any; } else for (unsigned i = first; i < last && !fold->done; ++i) - if (!fold_in(fold, items.start + i, (PureValue){.num = v[i]}, c[i])) return PURE_ALLOCATION; + if (!fold_number(fold, items.start + i, v[i], c[i])) return PURE_ALLOCATION; } return PURE_OK; } @@ -2222,7 +2233,7 @@ static bool group_pass(const PureModule *m, PureValue *values, PureBlock inner, if (c[i] == 0) continue; Group *group = group_of(pass, keys[i], how, true); if (!group) return false; - if (!group->fold.done && !fold_in(&group->fold, items.start + i, (PureValue){.num = v[i]}, c[i])) return false; + if (!group->fold.done && !fold_number(&group->fold, items.start + i, v[i], c[i])) return false; } } return true; |
