| """PDC benchmarks via compiled C backend (Sequential, OpenMP, POSIX Threads).""" |
|
|
| import subprocess |
| import sys |
| from pathlib import Path |
|
|
| CHART_CATEGORIES = [ |
| "Sequential", |
| "OpenMP (2)", |
| "OpenMP (4)", |
| "POSIX Threads (4)", |
| ] |
|
|
| APP_DIR = Path(__file__).resolve().parent |
| BACKEND_DIR = APP_DIR / "c_backend" |
| PROJECT_ROOT = APP_DIR.parent |
|
|
|
|
| def _bench_binary() -> Path: |
| name = "search_bench.exe" if sys.platform == "win32" else "search_bench" |
| for base in (BACKEND_DIR, PROJECT_ROOT): |
| candidate = base / name |
| if candidate.exists(): |
| return candidate |
| return BACKEND_DIR / name |
|
|
|
|
| def _bench_cwd(bench: Path) -> Path: |
| return bench.parent |
|
|
|
|
| def _label_for(method: str, workers: int) -> str: |
| if method == "Sequential": |
| return "Sequential" |
| if method == "OpenMP": |
| return f"OpenMP ({workers})" |
| if method == "POSIX Threads": |
| return f"POSIX Threads ({workers})" |
| return method |
|
|
|
|
| def run_backend_benchmark(method_type: str, worker_count: int, keyword: str) -> float: |
| bench = _bench_binary() |
| if not bench.exists(): |
| raise FileNotFoundError(_build_help()) |
| proc = subprocess.run( |
| [str(bench), method_type, str(worker_count), keyword], |
| capture_output=True, |
| text=True, |
| cwd=str(_bench_cwd(bench)), |
| ) |
| if proc.returncode != 0: |
| raise RuntimeError(proc.stderr.strip() or "C benchmark failed") |
| return float(proc.stdout.strip()) |
|
|
|
|
| def _build_help() -> str: |
| return ( |
| "Compiled benchmark not found.\n" |
| "Build locally:\n" |
| " cd c_backend && gcc -O2 -fopenmp -pthread search_bench.c hostel_mock_data.c " |
| "-o search_bench -lm" |
| ) |
|
|
|
|
| def _parse_row(line: str) -> dict: |
| parts = line.split() |
| if parts[0] == "POSIX" and len(parts) > 1 and parts[1] == "Threads": |
| method = "POSIX Threads" |
| workers = int(parts[2]) |
| fee_t, search_t, total_t = float(parts[3]), float(parts[4]), float(parts[5]) |
| found, speedup = int(parts[6]), float(parts[7]) |
| else: |
| method = parts[0] |
| workers = int(parts[1]) |
| fee_t, search_t, total_t = float(parts[2]), float(parts[3]), float(parts[4]) |
| found, speedup = int(parts[5]), float(parts[6]) |
|
|
| return { |
| "Method": method, |
| "Workers": workers, |
| "Fee (s)": fee_t, |
| "Search (s)": search_t, |
| "Time (s)": total_t, |
| "Found": found, |
| "Speedup": speedup, |
| "Label": _label_for(method, workers), |
| } |
|
|
|
|
| def run_all_benchmarks(students, keyword="Ali"): |
| del students |
| bench = _bench_binary() |
| if not bench.exists(): |
| raise FileNotFoundError(_build_help()) |
|
|
| proc = subprocess.run( |
| [str(bench), "all", keyword], |
| capture_output=True, |
| text=True, |
| cwd=str(_bench_cwd(bench)), |
| ) |
| if proc.returncode != 0: |
| raise RuntimeError(proc.stderr.strip() or "C benchmark failed") |
|
|
| rows = [_parse_row(line) for line in proc.stdout.strip().splitlines() if line.strip()] |
| if not rows: |
| raise RuntimeError("No benchmark results from C backend") |
| return rows, keyword |
|
|