#!/usr/bin/env python3 """ Benchmark Comparison Script for Bioheat PINN Compares RustyTorch++ (Rust) vs PyTorch (Python) performance for solving the Pennes Bioheat Equation using PINNs. Usage: python run_comparison.py [--steps 1000] [--output comparison_report.html] """ import argparse import json import os import subprocess import sys from datetime import datetime from pathlib import Path from typing import Dict, Any, Optional # Import the PyTorch benchmark from pytorch_bioheat_reference import benchmark_pytorch def run_rustytorch_benchmark( num_steps: int = 1000, binary_path: Optional[str] = None, ) -> Optional[Dict[str, Any]]: """ Run RustyTorch++ benchmark via CLI. Note: This requires a compiled benchmark binary. If not available, returns None. """ # Look for benchmark binary if binary_path is None: possible_paths = [ "../../target/release/bioheat_benchmark", "../../target/debug/bioheat_benchmark", "../target/release/bioheat_benchmark", ] for path in possible_paths: if os.path.exists(path): binary_path = path break if binary_path is None or not os.path.exists(binary_path): print("RustyTorch++ benchmark binary not found.") print("To compile: cargo build --release -p rtx-bioheat --bin bioheat_benchmark") return None try: result = subprocess.run( [binary_path, "--steps", str(num_steps), "--json"], capture_output=True, text=True, timeout=600, ) if result.returncode != 0: print(f"RustyTorch++ benchmark failed: {result.stderr}") return None return json.loads(result.stdout) except Exception as e: print(f"Error running RustyTorch++ benchmark: {e}") return None def generate_html_report( pytorch_results: Dict[str, Any], rustytorch_results: Optional[Dict[str, Any]], output_path: str, ): """Generate HTML comparison report.""" # Calculate speedups if RustyTorch results available if rustytorch_results: training_speedup = pytorch_results['training_time_sec'] / rustytorch_results['training_time_sec'] inference_speedup = pytorch_results['inference_mean_ms'] / rustytorch_results['inference_mean_ms'] else: training_speedup = None inference_speedup = None html = f"""
RustyTorch++ vs PyTorch - Pennes Bioheat Equation
The Pennes bioheat equation models heat transfer in biological tissue for thermal ablation planning.
| Metric | PyTorch | {"RustyTorch++ | " if rustytorch_results else ""} {"Speedup | " if rustytorch_results else ""}
|---|---|---|---|
| Device | {pytorch_results['device']} | {f"{rustytorch_results['device']} | " if rustytorch_results else ""} {f"- | " if rustytorch_results else ""}
| Model Parameters | {pytorch_results['num_parameters']:,} | {f"{rustytorch_results['num_parameters']:,} | " if rustytorch_results else ""} {f"- | " if rustytorch_results else ""}
| Training Steps | {pytorch_results['num_steps']} | {f"{rustytorch_results['num_steps']} | " if rustytorch_results else ""} {f"- | " if rustytorch_results else ""}
| Training Time (sec) | {pytorch_results['training_time_sec']:.2f} | {f"{rustytorch_results['training_time_sec']:.2f} | " if rustytorch_results else ""} {f"{training_speedup:.2f}x | " if training_speedup else ""}
| Steps/Second | {pytorch_results['steps_per_second']:.1f} | {f"{rustytorch_results['steps_per_second']:.1f} | " if rustytorch_results else ""} {f"{training_speedup:.2f}x | " if training_speedup else ""}
| Inference Time (32^3 grid) | {pytorch_results['inference_mean_ms']:.2f} ms | {f"{rustytorch_results['inference_mean_ms']:.2f} ms | " if rustytorch_results else ""} {f"{inference_speedup:.2f}x | " if inference_speedup else ""}
| Peak GPU Memory | {pytorch_results['peak_memory_mb']:.1f} MB | {f"{rustytorch_results['peak_memory_mb']:.1f} MB | " if rustytorch_results else ""} {f"- | " if rustytorch_results else ""}
| Final Loss | {pytorch_results['final_loss']:.4e} | {f"{rustytorch_results['final_loss']:.4e} | " if rustytorch_results else ""} {f"- | " if rustytorch_results else ""}