Skip to content

Commit 201db55

Browse files
committed
ci: Implement multi-OS CI build and benchmark execution via GitHub Actions and a new Python script.
1 parent 99180fb commit 201db55

2 files changed

Lines changed: 60 additions & 31 deletions

File tree

.github/workflows/build.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ jobs:
9696
shell: bash
9797
run: cmake --build build --config Release --verbose
9898

99+
- name: Run Benchmarks
100+
shell: bash
101+
run: |
102+
if [ "${{ matrix.os }}" == "windows-latest" ]; then
103+
EXE_PATH="build/Release/proxpl.exe"
104+
else
105+
EXE_PATH="build/proxpl"
106+
fi
107+
108+
echo "Running benchmarks with $EXE_PATH"
109+
python benchmarks/run_benchmarks.py --executable "$EXE_PATH"
110+
99111
- name: Upload Artifact
100112
uses: actions/upload-artifact@v4
101113
with:

benchmarks/run_benchmarks.py

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,65 @@
1-
# --------------------------------------------------
2-
# Project: ProX Programming Language (ProXPL)
3-
# Author: ProgrammerKR
4-
# Created: 2025-12-16
5-
# Copyright © 2025. ProXentix India Pvt. Ltd. All rights reserved.
6-
1+
import argparse
72
import subprocess
83
import time
94
import os
105
import sys
6+
import glob
117

12-
def run_command(cmd):
8+
def run_benchmark(executable, benchmark_file):
9+
# Ensure absolute path for executable to avoid issues
10+
executable = os.path.abspath(executable)
11+
benchmark_file = os.path.abspath(benchmark_file)
12+
13+
cmd = [executable, benchmark_file]
1314
start = time.time()
1415
try:
15-
subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
16+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
17+
end = time.time()
18+
return end - start, result.stdout
1619
except subprocess.CalledProcessError as e:
17-
print(f"Error running {cmd}: {e}")
18-
return None
19-
end = time.time()
20-
return end - start
20+
print(f"Error running {benchmark_file}: {e}")
21+
print(f"Stdout: {e.stdout}")
22+
print(f"Stderr: {e.stderr}")
23+
return None, None
24+
except Exception as e:
25+
print(f"Execution failed: {e}")
26+
return None, None
2127

2228
def main():
23-
benchmarks = [
24-
"benchmarks/fibonacci.prox",
25-
"benchmarks/loop_math.prox",
26-
"benchmarks/string_concat.prox"
27-
]
28-
29-
# Assume we have compiled proxpl in bin/proxpl (or use python version for now if bin not ready)
30-
# For now, we compare against CPython as specific in prompt (target numbers)
29+
parser = argparse.ArgumentParser(description="Run ProXPL benchmarks.")
30+
parser.add_argument("--executable", required=True, help="Path to proXPL executable")
31+
args = parser.parse_args()
32+
33+
if not os.path.exists(args.executable):
34+
print(f"Error: Executable not found at {args.executable}")
35+
sys.exit(1)
36+
37+
# Find all .prox files in benchmarks directory
38+
bench_dir = os.path.dirname(os.path.abspath(__file__))
39+
benchmarks = glob.glob(os.path.join(bench_dir, "*.prox"))
3140

32-
print(f"{'Benchmark':<25} | {'ProXPL (s)':<10} | {'CPython (s)':<10} | {'Speedup':<10}")
33-
print("-" * 65)
41+
if not benchmarks:
42+
print("No .prox benchmark files found.")
43+
# Optional: don't fail if no benchmarks?
44+
# But user expects benchmarks.
45+
return
3446

47+
print(f"{'Benchmark':<30} | {'Time (s)':<10} | {'Status':<10}")
48+
print("-" * 55)
49+
50+
failure = False
3551
for bench in benchmarks:
36-
# Construct equivalent python command (assuming corresponding .py files exist or we generate them)
37-
# For simplicity, we just run the prox file with current proxpl interpreter if it works,
38-
# but since we are replacing it, we might not have a working one yet.
39-
# This script is a template.
40-
41-
prox_cmd = f"bin/proxpl run {bench}"
42-
# py_cmd = f"python3 {bench.replace('.prox', '.py')}"
52+
name = os.path.basename(bench)
53+
duration, output = run_benchmark(args.executable, bench)
4354

44-
# Placeholder Results
45-
print(f"{bench:<25} | {'N/A':<10} | {'1.20':<10} | {'Pending'}")
55+
if duration is not None:
56+
print(f"{name:<30} | {duration:<10.4f} | {'PASS':<10}")
57+
else:
58+
print(f"{name:<30} | {'N/A':<10} | {'FAIL':<10}")
59+
failure = True
60+
61+
if failure:
62+
sys.exit(1)
4663

4764
if __name__ == "__main__":
4865
main()

0 commit comments

Comments
 (0)