aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-08 17:04:12 +0100
committereunhhu <[email protected]>2026-10-08 17:04:12 +0100
commitba35fb24dd8105f2b6492c103c4cb2471b15b715 (patch)
treef375947761568b97fb5e481066a5734a89120159 /tests
parentbe51c8a15d4f220ea8322f3c562f1f0c51b1e8e7 (diff)
downloadpure-ba35fb24dd8105f2b6492c103c4cb2471b15b715.tar.gz
pure-ba35fb24dd8105f2b6492c103c4cb2471b15b715.zip
Batch executor, stage 4 of design 025: a column read at affine rows in memory's order in four or eight bytes is a view of the column itself (cells_at), no copy, read only while the pass runs; what outlives the pass (a local, a set's rows and value, an append's cells, a sum's rows and e, a filter's key, a read's rows) copies it (own); knapsack 4.0% fewer instructions, 6.6% fewer cycles; VIEW_SOURCE in check.py (a local holding a field the batch sets, a set from the same column in the order that overwrites what it reads, a set widening the column under a view), which differs and trips ASan's memcpy overlap when the copies are left out; seeds 1 2 3 5 23 (default and PURE_SELECT=all), the fixed sources (also sanitized) and the unit tests pass
Diffstat (limited to 'tests')
-rw-r--r--tests/check.py60
1 files changed, 60 insertions, 0 deletions
diff --git a/tests/check.py b/tests/check.py
index 2314c36..1d98f05 100644
--- a/tests/check.py
+++ b/tests/check.py
@@ -1227,6 +1227,53 @@ on go {
"""
+# Columns read in place (VIEW_SOURCE, docs/design/025's stage 4): a local
+# holding a row's field while the batch sets that field (its last value
+# written back after the sets), a set whose value is the same column three
+# rows over in the order that overwrites what it reads, and a set that widens
+# the column to eight bytes while a local holds a view of it.
+VIEW_SOURCE = """record Cell {
+ at = 0
+ v = 0
+}
+state last = 0
+state back = 0
+state wide = 0
+state sum = 0
+input go = message {
+ n: u32
+ q: u32
+}
+on go {
+ let t: list of Cell by at
+ for i in 0 .. go.n {
+ t.add(Cell { at: i, v: i * 3 })
+ }
+ let a = 0
+ for i in 0 .. go.n - 3 {
+ a = t[i].v
+ t[i].v = t[i + 3].v + 1
+ }
+ last = a
+ for k in 0 .. go.n - 3 {
+ let i = go.n - 1 - k
+ t[i].v = t[i - 3].v
+ }
+ back = t[go.n - 1].v + t[go.n - 2].v * 1000
+ let w = 0
+ for i in 0 .. go.n - 3 {
+ w = t[i].v
+ t[i].v = t[i + 3].v + go.q + 0.5
+ }
+ wide = w
+ let s = 0
+ for c in t {
+ s = s + c.v
+ }
+ sum = s
+}
+"""
+
# Reductions that start with no lanes (REDUCE_SOURCE, docs/design/025): the
# same e in every lane (a count, a uniform max and min, a fraction, a sum
# past 2^53 one a lane), a count in a nested loop of the same rounds in
@@ -1711,6 +1758,19 @@ def module_assumptions(aup, pure, work):
assert outputs[name] == outputs['batches'], ('reduce', name, next((a, b) for a, b in zip(outputs[name].splitlines(), outputs['batches'].splitlines()) if a != b))
faults = [json.loads(line)['fault'] for line in outputs['batches'].splitlines() if line.startswith('{"states"')]
assert 'none' in faults and 'work' in faults, faults
+ source, program = work / 'view.aup', work / 'view.pmod' # columns read in place, against the rounds one by one
+ source.write_text(VIEW_SOURCE)
+ compile_module(aup, source, program)
+ given = ''.join(f'message go {struct.pack("<II", n, q).hex()}\nwork\n' for n, q in
+ ((3000, 7), (3000, 70000), (2049, 1), (40, 3), (5, 2), (1500, 100000)))
+ given += 'budget 30011\n' + given + 'budget 0\n'
+ outputs = {name: subprocess.run([str(pure / 'build/pure-run'), str(program)], input=given, capture_output=True, text=True,
+ timeout=120, env=dict(os.environ, **env)).stdout
+ for name, env in (('batches', {'PURE_JIT': '0'}), ('rounds', {'PURE_JIT': '0', 'PURE_BATCH': '0'}), ('all', {'PURE_JIT': 'all'}))}
+ for name in ('rounds', 'all'):
+ assert outputs[name] == outputs['batches'], ('view', name, next((a, b) for a, b in zip(outputs[name].splitlines(), outputs['batches'].splitlines()) if a != b))
+ faults = [json.loads(line)['fault'] for line in outputs['batches'].splitlines() if line.startswith('{"states"')]
+ assert 'none' in faults and 'work' in faults, faults
return len(runs)