aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/013-parallel-syncs/journal.py
diff options
context:
space:
mode:
Diffstat (limited to 'research/experiments/013-parallel-syncs/journal.py')
-rw-r--r--research/experiments/013-parallel-syncs/journal.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/research/experiments/013-parallel-syncs/journal.py b/research/experiments/013-parallel-syncs/journal.py
new file mode 100644
index 0000000..5f49095
--- /dev/null
+++ b/research/experiments/013-parallel-syncs/journal.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+"""The tree store's commits under each store variant of variants.py, without
+HTTP: latency percentiles of research/experiments/010-one-sync-commit
+/commits.c, and how many ext4 journal commits (jbd2 transactions, read from
+/proc/fs/jbd2) each run caused. Rounds rotate the variants' order."""
+import argparse
+import json
+import re
+import shutil
+import statistics
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+
+import variants
+
+HERE = Path(__file__).resolve().parent
+ROOT = HERE.parents[2]
+COMMITS = HERE.parent / '010-one-sync-commit' / 'commits.c'
+
+
+def transactions(device):
+ return int(re.match(r'(\d+) transactions', (Path('/proc/fs/jbd2') / device / 'info').read_text()).group(1))
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--directory', type=Path, default=Path('/var/tmp'), help='on the device to measure')
+ parser.add_argument('--journal', default='mmcblk0p2-8', help='its /proc/fs/jbd2 entry')
+ parser.add_argument('--rounds', type=int, default=4)
+ parser.add_argument('--commits', type=int, default=4000)
+ args = parser.parse_args()
+ with tempfile.TemporaryDirectory() as work:
+ work = Path(work)
+ binaries = {}
+ for number, (name, patches) in enumerate(variants.PATCHES.items()):
+ source = (ROOT / 'store' / 'store-tree.c').read_text()
+ for old, new in patches:
+ assert old in source, old
+ source = source.replace(old, new)
+ (work / f'store-{number}.c').write_text(source)
+ binaries[name] = work / f'commits-{number}'
+ subprocess.run(['cc', '-O2', '-std=c17', f'-I{ROOT / "core"}', '-o', str(binaries[name]), str(COMMITS),
+ str(work / f'store-{number}.c'), '-lpthread'], check=True)
+ names, runs = list(binaries), {name: [] for name in binaries}
+ for round_ in range(args.rounds):
+ for name in names[round_ % len(names):] + names[:round_ % len(names)]:
+ store = Path(tempfile.mkdtemp(dir=args.directory, prefix='pure-journal-'))
+ shutil.rmtree(store)
+ try:
+ before = transactions(args.journal)
+ out = subprocess.run([str(binaries[name]), str(store), str(args.commits)], capture_output=True,
+ text=True, check=True)
+ measured = {**json.loads(out.stdout), 'journal_commits': transactions(args.journal) - before}
+ finally:
+ shutil.rmtree(store, ignore_errors=True)
+ runs[name].append(measured)
+ print(json.dumps({'round': round_, 'store': name, **measured}), flush=True)
+ for name in names:
+ print(json.dumps({'store': name, 'commits': args.commits, **{key: statistics.median(r[key] for r in runs[name])
+ for key in ('commits_per_second', 'p50_ms', 'p90_ms', 'p99_ms', 'journal_commits')}}))
+
+
+if __name__ == '__main__':
+ sys.exit(main())