Skip to content

Commit 10627ef

Browse files
committed
Sync benchmark scripts with CPU branch for comparable results
- Copy benchmark-hardware.py from debug/benchmark-github-actions - Copy benchmark-jupyter.ipynb from debug/benchmark-github-actions - Copy benchmark-jupyterbook.md from debug/benchmark-github-actions - Update ci.yml to use matching file names The test scripts are now identical between both branches, only the CI workflow differs (runner type and JAX installation).
1 parent 922b24c commit 10627ef

File tree

4 files changed

+111
-108
lines changed

4 files changed

+111
-108
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
echo "=== Bare Metal Python Script Execution ==="
3333
python scripts/benchmark-hardware.py
3434
mkdir -p benchmark_results
35-
mv benchmark_results_baremetal.json benchmark_results/
35+
mv benchmark_results_bare_metal.json benchmark_results/
3636
- name: Run Jupyter Notebook Benchmark (via nbconvert)
3737
shell: bash -l {0}
3838
run: |
@@ -56,21 +56,14 @@ jobs:
5656
# Create minimal _toc.yml
5757
echo "format: jb-book" > benchmark_test/_toc.yml
5858
echo "root: benchmark-jupyterbook" >> benchmark_test/_toc.yml
59-
# Build
60-
jb build benchmark_test --path-output benchmark_build/
59+
# Build (run from benchmark_test so JSON is written there)
60+
cd benchmark_test
61+
jb build . --path-output ../benchmark_build/
62+
cd ..
6163
echo "Jupyter-Book build completed successfully"
6264
# Move JSON results if generated
63-
if [ -f benchmark_test/benchmark_results_jupyterbook.json ]; then
64-
mv benchmark_test/benchmark_results_jupyterbook.json benchmark_results/
65-
elif [ -f benchmark_results_jupyterbook.json ]; then
66-
mv benchmark_results_jupyterbook.json benchmark_results/
67-
fi
68-
- name: Collect and Upload Benchmark Results
69-
uses: actions/upload-artifact@v5
70-
with:
71-
name: benchmark-results
72-
path: benchmark_results/
73-
- name: Display Benchmark Results
65+
cp benchmark_test/benchmark_results_jupyterbook.json benchmark_results/ 2>/dev/null || echo "No jupyterbook results"
66+
- name: Collect and Display Benchmark Results
7467
shell: bash -l {0}
7568
run: |
7669
echo "=== Benchmark Results Summary ==="
@@ -79,6 +72,12 @@ jobs:
7972
cat "$f"
8073
echo ""
8174
done
75+
- name: Upload Benchmark Results
76+
uses: actions/upload-artifact@v5
77+
with:
78+
name: benchmark-results
79+
path: benchmark_results/
80+
if-no-files-found: warn
8281
- name: Install latex dependencies
8382
run: |
8483
sudo apt-get -qq update

scripts/benchmark-hardware.py

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Hardware benchmark script for CI runners.
1+
"""
2+
Hardware benchmark script for CI runners.
23
Compares CPU and GPU performance to diagnose slowdowns.
34
Works on both CPU-only (GitHub Actions) and GPU (RunsOn) runners.
45
"""
@@ -8,10 +9,10 @@
89
import json
910
from datetime import datetime
1011

11-
# Global results dictionary for JSON output
12+
# Global results dictionary
1213
RESULTS = {
14+
"pathway": "bare_metal",
1315
"timestamp": datetime.now().isoformat(),
14-
"execution_method": "bare_metal",
1516
"system": {},
1617
"benchmarks": {}
1718
}
@@ -27,14 +28,18 @@ def get_cpu_info():
2728

2829
RESULTS["system"]["platform"] = platform.platform()
2930
RESULTS["system"]["processor"] = platform.processor()
30-
RESULTS["system"]["python_version"] = platform.python_version()
31+
RESULTS["system"]["python"] = platform.python_version()
32+
RESULTS["system"]["cpu_count"] = os.cpu_count()
3133

32-
# Try to get CPU frequency
34+
# Try to get CPU model
35+
cpu_model = None
36+
cpu_mhz = None
3337
try:
3438
with open('/proc/cpuinfo', 'r') as f:
3539
for line in f:
3640
if 'model name' in line:
37-
print(f"CPU Model: {line.split(':')[1].strip()}")
41+
cpu_model = line.split(':')[1].strip()
42+
print(f"CPU Model: {cpu_model}")
3843
break
3944
except:
4045
pass
@@ -44,31 +49,33 @@ def get_cpu_info():
4449
with open('/proc/cpuinfo', 'r') as f:
4550
for line in f:
4651
if 'cpu MHz' in line:
47-
print(f"CPU MHz: {line.split(':')[1].strip()}")
52+
cpu_mhz = line.split(':')[1].strip()
53+
print(f"CPU MHz: {cpu_mhz}")
4854
break
4955
except:
5056
pass
5157

58+
RESULTS["system"]["cpu_model"] = cpu_model
59+
RESULTS["system"]["cpu_mhz"] = cpu_mhz
60+
5261
# CPU count
5362
print(f"CPU Count: {os.cpu_count()}")
54-
RESULTS["system"]["cpu_count"] = os.cpu_count()
5563

5664
# Check for GPU
65+
gpu_info = None
5766
try:
5867
import subprocess
5968
result = subprocess.run(['nvidia-smi', '--query-gpu=name,memory.total', '--format=csv,noheader'],
6069
capture_output=True, text=True, timeout=5)
6170
if result.returncode == 0:
6271
gpu_info = result.stdout.strip()
6372
print(f"GPU: {gpu_info}")
64-
RESULTS["system"]["gpu"] = gpu_info
6573
else:
6674
print("GPU: None detected")
67-
RESULTS["system"]["gpu"] = None
6875
except:
6976
print("GPU: None detected (nvidia-smi not available)")
70-
RESULTS["system"]["gpu"] = None
7177

78+
RESULTS["system"]["gpu"] = gpu_info
7279
print()
7380

7481
def benchmark_cpu_pure_python():
@@ -84,7 +91,7 @@ def benchmark_cpu_pure_python():
8491
total = sum(i * i for i in range(10_000_000))
8592
elapsed = time.perf_counter() - start
8693
print(f"Integer sum (10M iterations): {elapsed:.3f} seconds")
87-
results["integer_sum_10M"] = elapsed
94+
results["integer_sum_10m"] = elapsed
8895

8996
# Float computation
9097
start = time.perf_counter()
@@ -93,10 +100,10 @@ def benchmark_cpu_pure_python():
93100
total += (i * 0.1) ** 0.5
94101
elapsed = time.perf_counter() - start
95102
print(f"Float sqrt (1M iterations): {elapsed:.3f} seconds")
96-
results["float_sqrt_1M"] = elapsed
103+
results["float_sqrt_1m"] = elapsed
104+
print()
97105

98106
RESULTS["benchmarks"]["pure_python"] = results
99-
print()
100107

101108
def benchmark_cpu_numpy():
102109
"""NumPy CPU benchmark."""
@@ -126,29 +133,23 @@ def benchmark_cpu_numpy():
126133
y = np.cos(x**2) + np.sin(x)
127134
elapsed = time.perf_counter() - start
128135
print(f"Element-wise ops (50M elements): {elapsed:.3f} seconds")
129-
results["elementwise_50M"] = elapsed
136+
results["elementwise_50m"] = elapsed
137+
print()
130138

131139
RESULTS["benchmarks"]["numpy"] = results
132-
print()
133140

134141
def benchmark_gpu_jax():
135142
"""JAX benchmark (GPU if available, otherwise CPU)."""
136143
try:
137144
import jax
138145
import jax.numpy as jnp
139146

140-
results = {}
141-
142147
devices = jax.devices()
143148
default_backend = jax.default_backend()
144149

145150
# Check if GPU is available
146151
has_gpu = any('cuda' in str(d).lower() or 'gpu' in str(d).lower() for d in devices)
147152

148-
results["has_gpu"] = has_gpu
149-
results["default_backend"] = default_backend
150-
results["devices"] = [str(d) for d in devices]
151-
152153
print("=" * 60)
153154
if has_gpu:
154155
print("JAX BENCHMARK: GPU")
@@ -161,6 +162,12 @@ def benchmark_gpu_jax():
161162
print(f"GPU Available: {has_gpu}")
162163
print()
163164

165+
results = {
166+
"backend": default_backend,
167+
"has_gpu": has_gpu,
168+
"devices": str(devices)
169+
}
170+
164171
# Warm-up JIT compilation
165172
print("Warming up JIT compilation...")
166173
n = 1000
@@ -217,17 +224,17 @@ def elementwise_ops(x):
217224
y = elementwise_ops(x).block_until_ready()
218225
warmup_time = time.perf_counter() - start
219226
print(f"Element-wise warm-up (50M): {warmup_time:.3f} seconds")
220-
results["elementwise_50M_warmup"] = warmup_time
227+
results["elementwise_50m_warmup"] = warmup_time
221228

222229
# Compiled
223230
start = time.perf_counter()
224231
y = elementwise_ops(x).block_until_ready()
225232
elapsed = time.perf_counter() - start
226233
print(f"Element-wise compiled (50M): {elapsed:.3f} seconds")
227-
results["elementwise_50M_compiled"] = elapsed
234+
results["elementwise_50m_compiled"] = elapsed
228235

229-
RESULTS["benchmarks"]["jax"] = results
230236
print()
237+
RESULTS["benchmarks"]["jax"] = results
231238

232239
except ImportError as e:
233240
print(f"JAX not available: {e}")
@@ -242,12 +249,12 @@ def benchmark_numba():
242249
import numba
243250
import numpy as np
244251

245-
results = {}
246-
247252
print("=" * 60)
248253
print("CPU BENCHMARK: Numba")
249254
print("=" * 60)
250255

256+
results = {}
257+
251258
@numba.jit(nopython=True)
252259
def numba_sum(n):
253260
total = 0
@@ -260,14 +267,14 @@ def numba_sum(n):
260267
result = numba_sum(10_000_000)
261268
warmup_time = time.perf_counter() - start
262269
print(f"Integer sum warm-up (includes compile): {warmup_time:.3f} seconds")
263-
results["integer_sum_10M_warmup"] = warmup_time
270+
results["integer_sum_10m_warmup"] = warmup_time
264271

265272
# Compiled run
266273
start = time.perf_counter()
267274
result = numba_sum(10_000_000)
268275
elapsed = time.perf_counter() - start
269276
print(f"Integer sum compiled (10M): {elapsed:.3f} seconds")
270-
results["integer_sum_10M_compiled"] = elapsed
277+
results["integer_sum_10m_compiled"] = elapsed
271278

272279
@numba.jit(nopython=True, parallel=True)
273280
def numba_parallel_sum(arr):
@@ -283,17 +290,17 @@ def numba_parallel_sum(arr):
283290
result = numba_parallel_sum(arr)
284291
warmup_time = time.perf_counter() - start
285292
print(f"Parallel sum warm-up (50M): {warmup_time:.3f} seconds")
286-
results["parallel_sum_50M_warmup"] = warmup_time
293+
results["parallel_sum_50m_warmup"] = warmup_time
287294

288295
# Compiled
289296
start = time.perf_counter()
290297
result = numba_parallel_sum(arr)
291298
elapsed = time.perf_counter() - start
292299
print(f"Parallel sum compiled (50M): {elapsed:.3f} seconds")
293-
results["parallel_sum_50M_compiled"] = elapsed
300+
results["parallel_sum_50m_compiled"] = elapsed
294301

295-
RESULTS["benchmarks"]["numba"] = results
296302
print()
303+
RESULTS["benchmarks"]["numba"] = results
297304

298305
except ImportError as e:
299306
print(f"Numba not available: {e}")
@@ -302,6 +309,14 @@ def numba_parallel_sum(arr):
302309
print(f"Numba benchmark failed: {e}")
303310
RESULTS["benchmarks"]["numba"] = {"error": str(e)}
304311

312+
313+
def save_results(output_path="benchmark_results_bare_metal.json"):
314+
"""Save benchmark results to JSON file."""
315+
with open(output_path, 'w') as f:
316+
json.dump(RESULTS, f, indent=2)
317+
print(f"\nResults saved to: {output_path}")
318+
319+
305320
if __name__ == "__main__":
306321
print("\n" + "=" * 60)
307322
print("HARDWARE BENCHMARK FOR CI RUNNER")
@@ -313,12 +328,9 @@ def numba_parallel_sum(arr):
313328
benchmark_numba()
314329
benchmark_gpu_jax()
315330

331+
# Save results to JSON
332+
save_results("benchmark_results_bare_metal.json")
333+
316334
print("=" * 60)
317335
print("BENCHMARK COMPLETE")
318336
print("=" * 60)
319-
320-
# Save results to JSON
321-
output_file = "benchmark_results_baremetal.json"
322-
with open(output_file, 'w') as f:
323-
json.dump(RESULTS, f, indent=2)
324-
print(f"\nResults saved to {output_file}")

0 commit comments

Comments
 (0)