-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_cool.py
More file actions
145 lines (124 loc) · 4.41 KB
/
Copy pathrun_cool.py
File metadata and controls
145 lines (124 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python
"""Orchestrate the Cooler (.cool/.mcool) benchmarks.
Runs each (library, workload, threads) configuration in a fresh process,
interleaving iterations across libraries so background drift affects both
sides equally, and writes results to results/cool_results.json.
.venv/bin/python run_cool.py [--iterations 3] [--resolution 10000]
"""
import argparse
import hashlib
import json
import os
import platform
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
REPO_ROOT = Path(__file__).parent
RESULTS_PATH = REPO_ROOT / "results" / "cool_results.json"
WORKLOADS = ("stream_count", "collect_all", "region")
POLARS_BIO_THREADS = (1, 2, 4, 8)
def file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(8 * 1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def run_child(module: str, workload: str, threads: int, resolution: int):
env = os.environ.copy()
env.update(
{
"COOL_WORKLOAD": workload,
"COOL_RESOLUTION": str(resolution),
"THREAD_NUM": str(threads),
"POLARS_MAX_THREADS": str(threads),
"TQDM_DISABLE": "1",
}
)
process = subprocess.run(
[sys.executable, "-m", module],
cwd=REPO_ROOT,
env=env,
capture_output=True,
text=True,
)
if process.returncode != 0:
raise RuntimeError(
f"{module} {workload} t{threads} failed:\n{process.stdout}\n{process.stderr}"
)
for line in process.stdout.splitlines():
if line.startswith("BENCHMARK_RESULT:"):
return json.loads(line[len("BENCHMARK_RESULT:") :])
raise RuntimeError(f"{module} produced no BENCHMARK_RESULT line")
def library_versions() -> dict:
import importlib.metadata
versions = {}
for package in ("polars-bio", "polars", "cooler", "pandas", "numpy"):
try:
versions[package] = importlib.metadata.version(package)
except importlib.metadata.PackageNotFoundError:
versions[package] = "missing"
return versions
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--iterations", type=int, default=3)
parser.add_argument("--resolution", type=int, default=10000)
parser.add_argument(
"--skip-verify", action="store_true", help="skip the equivalence check"
)
args = parser.parse_args()
mcool = Path(
os.environ.get(
"MCOOL_PATH", "/Users/mwiewior/research/data/COOL/test.mcool"
)
)
if not mcool.exists():
print(f"missing dataset: {mcool} — run setup.sh first", file=sys.stderr)
return 1
if not args.skip_verify:
print("verifying polars-bio vs cooler equivalence ...")
env = os.environ.copy()
env.update(
{"COOL_RESOLUTION": str(args.resolution), "TQDM_DISABLE": "1"}
)
subprocess.run(
[sys.executable, "-m", "benchmarks.verify_cool_equivalence"],
cwd=REPO_ROOT,
env=env,
check=True,
)
configurations = [
("benchmarks.bench_cool_cooler", workload, 1) for workload in WORKLOADS
] + [
("benchmarks.bench_cool_polars_bio", workload, threads)
for workload in WORKLOADS
for threads in POLARS_BIO_THREADS
]
runs = []
for iteration in range(args.iterations):
for module, workload, threads in configurations:
print(f"[iter {iteration + 1}/{args.iterations}] {module} {workload} t{threads}")
result = run_child(module, workload, threads, args.resolution)
result["iteration"] = iteration
runs.append(result)
payload = {
"generated_at": datetime.now(timezone.utc).isoformat(),
"dataset": {
"path": str(mcool),
"sha256": file_sha256(mcool),
"resolution": args.resolution,
},
"platform": {
"machine": platform.machine(),
"system": platform.system(),
"python": platform.python_version(),
},
"versions": library_versions(),
"iterations": args.iterations,
"runs": runs,
}
RESULTS_PATH.write_text(json.dumps(payload, indent=2) + "\n")
print(f"wrote {RESULTS_PATH} ({len(runs)} runs)")
return 0
if __name__ == "__main__":
sys.exit(main())