aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/046-commit-replica/run.py
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 14:16:33 +0100
committereunhhu <[email protected]>2026-10-19 14:16:33 +0100
commitd5107e9e61d1083f945edb64ec619c333024a43f (patch)
tree5f8444aced1da3c0151b151f89e13ef89a8769d4 /research/experiments/046-commit-replica/run.py
parent109c3afd29b6cad3e529d83fde8aeb1d0da700ff (diff)
downloadpure-d5107e9e61d1083f945edb64ec619c333024a43f.tar.gz
pure-d5107e9e61d1083f945edb64ec619c333024a43f.zip
046, 029: the taken-over store sent a message too (opened() works on a copy: show, add, show; 20 more kill -9s: all open and take it as owners; 667 prefixes again with it: all pass); the price measured again without the fold that inflated it (entries.aup's summed view folded every entry each message): 48.5 to 232 us a message on tmpfs, 146 us of the 183 waiting for acks; the shim never stopped across the runs
Diffstat (limited to 'research/experiments/046-commit-replica/run.py')
-rw-r--r--research/experiments/046-commit-replica/run.py31
1 files changed, 19 insertions, 12 deletions
diff --git a/research/experiments/046-commit-replica/run.py b/research/experiments/046-commit-replica/run.py
index 1e4f4b8..e31ff50 100644
--- a/research/experiments/046-commit-replica/run.py
+++ b/research/experiments/046-commit-replica/run.py
@@ -46,7 +46,8 @@ def build():
for name in ('shipper', 'follower'):
subprocess.run(cc + [f'-I{PURE / "link"}', str(HERE / f'{name}.c'), str(PURE / 'build' / 'libpure-link.a'),
'-lm', '-pthread', '-ldl', '-o', str(WORK / name)], check=True)
- subprocess.run([str(AUP), 'build', str(HERE / 'entries.aup'), '-o', str(WORK / 'entries.pmod')], check=True)
+ for name in ('entries', 'entries-price'): # the price's: no view that folds the list (each message shows the views)
+ subprocess.run([str(AUP), 'build', str(HERE / f'{name}.aup'), '-o', str(WORK / f'{name}.pmod')], check=True)
keys = json.loads(subprocess.run([str(WORK / 'follower'), 'keys', str(WORK)], capture_output=True, text=True,
check=True, env=ENV).stdout)
return keys
@@ -85,7 +86,7 @@ def stores_differ(a, b):
class Run:
"""A follower, a shipper and an owner, started in that order on fresh stores."""
- def __init__(self, keys, every=0, shim=True):
+ def __init__(self, keys, every=0, shim=True, module='entries'):
self.owner_dir, self.follower_dir = WORK / 'owner-store', WORK / 'follower-store'
for d in (self.owner_dir, self.follower_dir):
shutil.rmtree(d, ignore_errors=True)
@@ -111,7 +112,7 @@ class Run:
self.paused = os.open(WORK / 'paused', os.O_RDWR) # held open both ways: no open waits for the other end
self.resume = os.open(WORK / 'resume', os.O_RDWR)
env.update(SHIM_PAUSE_EVERY=str(every), SHIM_PAUSE_DIR=str(WORK))
- self.owner = subprocess.Popen([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(self.owner_dir)],
+ self.owner = subprocess.Popen([str(RUN), str(WORK / f'{module}.pmod'), '--views', '--store', str(self.owner_dir)],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,
env=env, bufsize=1)
self.done = 0 # messages the owner said done (each line comes after its save, so after the follower's ack)
@@ -144,14 +145,19 @@ class Run:
def opened(store):
- """The store opened by pure-run as its owner: the views (total, summed) it shows, or why it did not open."""
- r = subprocess.run([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(store)], input='show\n',
- capture_output=True, text=True, env=ENV, timeout=120)
- lines = [l for l in r.stdout.splitlines() if l.startswith('{')]
- if r.returncode or not lines:
+ """The store opened by pure-run as its owner: the views (total, summed) it shows, and whether it then takes a message
+ as an owner does (total one more, the entry its own; on a copy: the store looked at is left as it was)."""
+ shutil.rmtree(WORK / 'opened', ignore_errors=True)
+ shutil.copytree(store, WORK / 'opened')
+ r = subprocess.run([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(WORK / 'opened')],
+ input='show\n' + message(7) + 'show\n', capture_output=True, text=True, env=ENV, timeout=120)
+ lines = [json.loads(l) for l in r.stdout.splitlines() if l.startswith('{')]
+ if r.returncode or len(lines) < 3:
return {'opened': False, 'exit': r.returncode, 'stderr': r.stderr[-300:]}
- shown = json.loads(lines[-1])
- return {'opened': True, 'fault': shown.get('fault'), **shown['views']}
+ shown, after = lines[0], lines[-1]
+ took = (after['views']['total'] == shown['views']['total'] + 1 and after['fault'] == 'none' and
+ after['views']['summed'] == shown['views']['summed'] + 7.25)
+ return {'opened': True, 'fault': shown.get('fault'), **shown['views'], 'takes_a_message': took}
def summed(n): # every partial sum a multiple of 0.25 below 2^50: exact as a binary64
@@ -212,7 +218,8 @@ def takeover(keys, runs, events, torn=False):
time.sleep(1.0) # what was on the way reaches the follower
follower = run.stop_follower()
took = opened(run.follower_dir)
- good = (took.get('opened') and took.get('fault') == 'none' and done <= took.get('total', -1) <= sent and
+ good = (took.get('opened') and took.get('fault') == 'none' and took.get('takes_a_message') and
+ done <= took.get('total', -1) <= sent and
took.get('summed') == summed(int(took.get('total', 0))))
print(json.dumps({'run': 'takeover', 'k': k, 'whole_node': whole_node, 'record': os.environ.get('SHIPPER_RECORD'), 'sent': sent, 'owner_said_done': done,
'follower_took': took, 'follower': follower, 'passed': bool(good),
@@ -222,7 +229,7 @@ def takeover(keys, runs, events, torn=False):
def price(keys, events):
out = {}
for shim in (False, True):
- run = Run(keys, shim=shim)
+ run = Run(keys, shim=shim, module='entries-price')
start = time.perf_counter()
run.feed(events)
run.owner.wait()