gabriel / musehub public

bench_push.py file-level

at sha256:c · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 💥 blast risk
sha256:e fix(9A-4 F7): env alias + staging secrets for overseer provenance gate.… · aaronrene · Jul 13, 2026
1 #!/usr/bin/env python3
2 """Push benchmarking tool — create a fresh unique repo, build commits, push, report timing.
3
4 Creates real repos on the hub (staging or local), builds N commits of random content,
5 times the first push and the re-push (all objects already present), then cleans up.
6 This is a manual performance/regression tool, not a release gate.
7
8 Usage:
9 python tools/bench_push.py xs # 1 commit, 5 files, 512 B/file
10 python tools/bench_push.py s # 10 commits, 10 files, 1 KB/file
11 python tools/bench_push.py m # 100 commits,20 files, 2 KB/file
12 python tools/bench_push.py l # 500 commits,50 files, 4 KB/file
13 python tools/bench_push.py xl # 1000 commits,100 files,8 KB/file
14 python tools/bench_push.py xs s m # run multiple sizes in sequence
15 python tools/bench_push.py --hub https://staging.musehub.ai xs
16 """
17 from __future__ import annotations
18
19 import json
20 import random
21 import shutil
22 import string
23 import subprocess
24 import sys
25 import time
26 from pathlib import Path
27
28 HUB_REPO_CTX = str(Path(__file__).parent.parent) # musehub repo root
29
30 SIZES = {
31 "xs": (1, 5, 512),
32 "s": (10, 10, 1_024),
33 "m": (100, 20, 2_048),
34 "l": (500, 50, 4_096),
35 "xl": (1000, 100, 8_192),
36 }
37
38
39 def run(cmd: list[str], cwd: str | None = None, check: bool = True) -> subprocess.CompletedProcess:
40 return subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, check=check)
41
42
43 def rnd_content(size: int, seed: int) -> str:
44 rng = random.Random(seed)
45 return "".join(random.Random(seed).choice(string.ascii_letters + string.digits + "\n")
46 for _ in range(size))
47
48
49 def smoke(label: str, hub: str) -> dict:
50 n_commits, n_files, file_size = SIZES[label]
51 ts = int(time.time())
52 slug = f"smoke-{label}-{ts}"
53 repo_path = Path(f"/tmp/{slug}")
54
55 total_kb = n_commits * n_files * file_size // 1024
56 print(f"\n{'='*64}")
57 print(f" {label.upper()} — {n_commits} commits × {n_files} files × {file_size}B ≈ {total_kb} KB")
58 print(f" repo: gabriel/{slug} hub: {hub}")
59 print(f"{'='*64}")
60
61 # Fresh local repo
62 repo_path.mkdir(parents=True, exist_ok=True)
63 run(["muse", "init"], cwd=str(repo_path))
64 run(["muse", "remote", "set-url", "local", f"{hub}/gabriel/{slug}"], cwd=str(repo_path))
65
66 # Create hub repo
67 print(f" creating hub repo…", flush=True)
68 r = run(["muse", "-C", HUB_REPO_CTX, "hub", "repo", "create",
69 "--name", slug, "--visibility", "public", "--hub", hub], check=False)
70 if r.returncode != 0:
71 print(f" ❌ hub create failed: {r.stderr[:200]}")
72 shutil.rmtree(repo_path, ignore_errors=True)
73 return {"label": label, "error": "hub create failed"}
74
75 # Build commits
76 print(f" building {n_commits} commit(s)…", flush=True)
77 t_build = time.monotonic()
78 src_dir = repo_path / "src"
79 src_dir.mkdir()
80 for ci in range(n_commits):
81 for fi in range(n_files):
82 (src_dir / f"file_{fi:04d}.txt").write_text(rnd_content(file_size, ci * 10000 + fi))
83 run(["muse", "code", "add", "."], cwd=str(repo_path))
84 run(["muse", "commit", "-m", f"c{ci+1}",
85 "--agent-id", "smoke", "--model-id", "none", "--sign"], cwd=str(repo_path))
86 if n_commits >= 100 and (ci + 1) % 100 == 0:
87 print(f" {ci+1}/{n_commits}", flush=True)
88 print(f" built in {time.monotonic()-t_build:.1f}s", flush=True)
89
90 # Object count from HEAD manifest
91 try:
92 m = json.loads(run(["muse", "read", "--json", "--manifest"], cwd=str(repo_path)).stdout)
93 n_objects = len(m.get("manifest", {}))
94 except Exception:
95 n_objects = -1
96 print(f" HEAD snapshot: {n_objects} unique objects")
97
98 # First push
99 print(f" pushing…", flush=True)
100 t0 = time.monotonic()
101 p = run(["muse", "push", "local", "main"], cwd=str(repo_path), check=False)
102 elapsed = time.monotonic() - t0
103
104 if p.returncode != 0:
105 print(f" ❌ FAILED in {elapsed:.3f}s")
106 print(p.stderr[-400:])
107 shutil.rmtree(repo_path, ignore_errors=True)
108 return {"label": label, "n_commits": n_commits, "n_objects": n_objects,
109 "error": p.stderr[-120:].strip(), "first_push_s": round(elapsed, 3)}
110
111 print(f" ✅ first push: {elapsed:.3f}s")
112 # Show key server timing lines
113 for line in p.stdout.splitlines():
114 if any(k in line for k in ["TOTAL server", "stored", "✅ Pushed"]):
115 print(f" {line.strip()}")
116
117 # Re-push (all objects already in DB — tests O(1) presign path)
118 print(f" re-pushing (already-stored)…", flush=True)
119 t1 = time.monotonic()
120 p2 = run(["muse", "push", "local", "main"], cwd=str(repo_path), check=False)
121 elapsed2 = time.monotonic() - t1
122 print(f" {'✅' if p2.returncode == 0 else '❌'} re-push: {elapsed2:.3f}s")
123
124 shutil.rmtree(repo_path, ignore_errors=True)
125 return {
126 "label": label, "n_commits": n_commits, "n_objects": n_objects,
127 "first_push_s": round(elapsed, 3), "repush_s": round(elapsed2, 3), "ok": True,
128 }
129
130
131 def main() -> None:
132 args = sys.argv[1:]
133 hub = "https://localhost:1337"
134
135 # --hub flag
136 if "--hub" in args:
137 i = args.index("--hub")
138 hub = args[i + 1]
139 args = args[:i] + args[i + 2:]
140
141 if not args:
142 print(__doc__)
143 sys.exit(1)
144
145 labels = [a.lower() for a in args]
146 for lbl in labels:
147 if lbl not in SIZES:
148 print(f"unknown size '{lbl}' — choose from: {', '.join(SIZES)}")
149 sys.exit(1)
150
151 results = [smoke(lbl, hub) for lbl in labels]
152
153 if len(results) > 1:
154 print(f"\n{'='*64}")
155 print(f" SUMMARY")
156 print(f"{'='*64}")
157 print(f"{'Size':<6} {'Commits':>8} {'Objects':>8} {'First':>10} {'Re-push':>9} Status")
158 print("-" * 50)
159 for r in results:
160 if "error" in r and "first_push_s" not in r:
161 print(f"{r['label'].upper():<6} {r.get('n_commits','?'):>8} {r.get('n_objects','?'):>8} "
162 f"{'FAILED':>10} {'—':>9} ❌")
163 else:
164 print(f"{r['label'].upper():<6} {r['n_commits']:>8} {r['n_objects']:>8} "
165 f"{r['first_push_s']:>9.3f}s {r.get('repush_s',0):>8.3f}s ✅")
166
167
168 if __name__ == "__main__":
169 main()