aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-06 05:08:16 +0100
committereunhhu <[email protected]>2026-10-06 05:08:16 +0100
commitb94de93a5ae36bab5e00b5b479afeb59e9702a61 (patch)
tree48418e7d8477f3a055f0adfe2a6330dd623fd44c /tests
parent9cb6985c0d9459ccf4dbbab4b05109168c362f75 (diff)
downloadpure-b94de93a5ae36bab5e00b5b479afeb59e9702a61.tar.gz
pure-b94de93a5ae36bab5e00b5b479afeb59e9702a61.zip
Batch: a batch's appends made at once (pure_list_add_many, a call a chunk of 128) when every list takes its items so (an event's list, no index into it, one append to it: FLAT not keyed at its end, DENSE by keys it holds at its count, HASHED by number; never past its arrays' limit) and the memory budget takes them all (each item only grows what it counts): columns grown and widened once, the first key there already the executor's EXISTS at its round; else round by round as before, tried at once again after a round that changed a list's form. 50,000 DENSE adds 5.18 to 0.65 ms (the compiled code 0.28). APPEND_SOURCE: keys there already at rounds q and p, keys past a DENSE list's from round p, two appends to one list, widened columns, under memory budgets (seeds 1, 2, 3, 5, 23 alike: 31,402 batches at once in seed 23's, 292 by the budget round by round)
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 744b505..1fe7079 100644
--- a/tests/check.py
+++ b/tests/check.py
@@ -1338,6 +1338,53 @@ on go {
"""
+# Items a batch appends at once (APPEND_SOURCE): keys there already, met
+# at round q of a DENSE list and at round p of a HASHED one (the
+# executor's fault at that round); keys past what a DENSE list holds from
+# round p on (it changes its form there, round by round); a list appended
+# to twice a round (round by round); columns widened by the items; all
+# under memory budgets that run out in the middle of a batch.
+APPEND_SOURCE = """record Cell {
+ at = 0
+ v = 0
+}
+state items = 0
+state last = 0
+input go = message {
+ n: u32
+ q: u32
+ p: u32
+}
+on go {
+ let d: list of Cell by at
+ let e: list of Cell by at
+ let h: list of Cell by at
+ let u: list of Cell
+ let w: list of Cell
+ for i in 0 .. go.n {
+ w.append(Cell { at: i, v: i * 300 })
+ d.add(Cell { at: i - floor(i / go.q) * go.q, v: i * 0.5 })
+ }
+ for i in 0 .. go.n {
+ e.add(Cell { at: i + floor(i / go.p) * 1000000, v: i })
+ h.add(Cell { at: i * 7919 - floor(i * 7919 / go.p) * go.p + 5000000, v: 0 - i })
+ }
+ for i in 0 .. go.n {
+ u.append(Cell { at: i, v: i })
+ u.append(Cell { at: 0 - i, v: i * 70000 })
+ }
+ items = d.count + e.count * 10000 + h.count * 100000000 + u.count + w.count
+ let s = 0
+ for c in u {
+ s = s + c.v
+ }
+ for c in w {
+ s = s + c.v * 2
+ }
+ last = s
+}
+"""
+
def module_assumptions(aup, pure, work):
"""The compiled code's integers (Pure docs/design/022) where they stop
holding: a loop whose columns hold small whole numbers until, halfway,
@@ -1401,6 +1448,19 @@ def module_assumptions(aup, pure, work):
assert outputs[name] == outputs['batches'], ('recur', 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 'divide' in faults and 'none' in faults and 'non_finite' in faults and 'memory' in faults, faults
+ source, program = work / 'append.aup', work / 'append.pmod' # items appended at once, against the rounds one by one
+ source.write_text(APPEND_SOURCE)
+ compile_module(aup, source, program)
+ given = ''.join(f'message go {struct.pack("<III", n, q, p).hex()}\nwork\n' for n, q, p in
+ ((3000, 70000, 70000), (3000, 1500, 70000), (3000, 70000, 2000), (3000, 70000, 40), (90, 70000, 70000), (20, 3, 5)))
+ given += ''.join(f'memory {b}\n' + given for b in (30000, 90000, 200000)) + 'memory 0\nbudget 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'], ('append', 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 'exists' in faults and 'none' in faults and 'memory' in faults and 'work' in faults, faults
source, program = work / 'nested.aup', work / 'nested.pmod' # nested loops together and reductions, against the rounds one by one
source.write_text(NESTED_SOURCE)
compile_module(aup, source, program)