1- """Hardware benchmark script for CI runners.
1+ """
2+ Hardware benchmark script for CI runners.
23Compares CPU and GPU performance to diagnose slowdowns.
34Works on both CPU-only (GitHub Actions) and GPU (RunsOn) runners.
45"""
89import json
910from datetime import datetime
1011
11- # Global results dictionary for JSON output
12+ # Global results dictionary
1213RESULTS = {
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
7481def 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
101108def 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
134141def 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"\n Results saved to: { output_path } " )
318+
319+
305320if __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"\n Results saved to { output_file } " )
0 commit comments