mirror of
https://github.com/hanzoai/overlord.git
synced 2026-10-30 18:25:54 +00:00
224 lines
7.7 KiB
Python
224 lines
7.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Setup script for Metal GPU acceleration
|
|
This script installs the necessary dependencies for Metal GPU acceleration
|
|
and verifies that they're working correctly.
|
|
"""
|
|
|
|
import os
|
|
import platform
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def run_command(cmd, verbose=True):
|
|
"""Execute a shell command and return the success status"""
|
|
if verbose:
|
|
print(f"Running: {cmd}")
|
|
try:
|
|
result = subprocess.run(cmd, shell=True, check=False,
|
|
capture_output=True, text=True)
|
|
if result.returncode != 0:
|
|
if verbose:
|
|
print(f"Error: {result.stderr}")
|
|
return False
|
|
else:
|
|
if verbose:
|
|
print(f"Success: {result.stdout}")
|
|
return True
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Exception: {str(e)}")
|
|
return False
|
|
|
|
|
|
def is_metal_available():
|
|
"""Check if Metal is available on the system"""
|
|
if platform.system() != "Darwin":
|
|
print("Metal GPU acceleration is only available on macOS")
|
|
return False
|
|
|
|
try:
|
|
# Try to import the Metal module
|
|
import Metal
|
|
return True
|
|
except ImportError:
|
|
return False
|
|
|
|
|
|
def install_metal_dependencies():
|
|
"""Install the necessary dependencies for Metal GPU acceleration"""
|
|
if platform.system() != "Darwin":
|
|
print("Metal GPU acceleration is only available on macOS")
|
|
return False
|
|
|
|
print("\n=== Installing Metal GPU acceleration dependencies ===\n")
|
|
|
|
dependencies = [
|
|
"pip install -U pip",
|
|
"pip install -U wheel setuptools",
|
|
"pip install -U numpy pillow",
|
|
"pip install -U pyobjc-core",
|
|
"pip install -U pyobjc-framework-Cocoa",
|
|
"pip install -U pyobjc-framework-Quartz",
|
|
"pip install -U pyobjc-framework-Metal",
|
|
"pip install -U pyobjc-framework-MetalKit",
|
|
"pip install -U pyobjc-framework-MetalPerformanceShaders",
|
|
]
|
|
|
|
success = True
|
|
for cmd in dependencies:
|
|
if not run_command(cmd):
|
|
print(f"Failed to install dependency with: {cmd}")
|
|
success = False
|
|
|
|
return success
|
|
|
|
|
|
def verify_metal_installation():
|
|
"""Verify that Metal dependencies are correctly installed"""
|
|
print("\n=== Verifying Metal GPU acceleration setup ===\n")
|
|
|
|
try:
|
|
import Metal
|
|
print("✅ Metal framework is installed")
|
|
except ImportError:
|
|
print("❌ Metal framework is not installed")
|
|
return False
|
|
|
|
try:
|
|
import MetalKit
|
|
print("✅ MetalKit framework is installed")
|
|
except ImportError:
|
|
print("❌ MetalKit framework is not installed")
|
|
return False
|
|
|
|
try:
|
|
import MetalPerformanceShaders
|
|
print("✅ MetalPerformanceShaders framework is installed")
|
|
except ImportError:
|
|
print("❌ MetalPerformanceShaders framework is not installed")
|
|
return False
|
|
|
|
# Check if we can actually get a Metal device
|
|
try:
|
|
devices = Metal.MTLCopyAllDevices()
|
|
if devices and len(devices) > 0:
|
|
print(f"✅ Found {len(devices)} Metal device(s):")
|
|
for i, device in enumerate(devices):
|
|
print(f" {i+1}. {device.name()} ({device.registryID()})")
|
|
else:
|
|
print("❌ No Metal devices found")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ Failed to enumerate Metal devices: {e}")
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def test_metal_performance():
|
|
"""Run a simple benchmark to test Metal performance"""
|
|
print("\n=== Testing Metal GPU performance ===\n")
|
|
|
|
try:
|
|
# Add the parent directory to the sys.path so we can import the metal_utils module
|
|
current_dir = Path(__file__).resolve().parent
|
|
project_dir = current_dir.parent
|
|
overlord_dir = project_dir / "overlord"
|
|
|
|
sys.path.insert(0, str(project_dir))
|
|
|
|
# Test image path - create a simple test image if it doesn't exist
|
|
test_image_dir = project_dir / "tests" / "data"
|
|
test_image_dir.mkdir(parents=True, exist_ok=True)
|
|
test_image_path = test_image_dir / "test_image.png"
|
|
|
|
# Create a test image if it doesn't exist
|
|
if not test_image_path.exists():
|
|
try:
|
|
from PIL import Image, ImageDraw
|
|
img = Image.new('RGB', (1280, 800), color=(73, 109, 137))
|
|
d = ImageDraw.Draw(img)
|
|
d.rectangle([(100, 100), (1180, 700)], fill=(255, 128, 0))
|
|
d.ellipse([(400, 200), (880, 600)], fill=(0, 0, 0))
|
|
img.save(test_image_path)
|
|
print(f"Created test image at {test_image_path}")
|
|
except Exception as e:
|
|
print(f"Failed to create test image: {e}")
|
|
test_image_path = None
|
|
|
|
if test_image_path and test_image_path.exists():
|
|
try:
|
|
from overlord.tools.metal_utils import benchmark_metal_vs_traditional
|
|
|
|
# Run the benchmark
|
|
print("Running benchmark (this may take a few seconds)...")
|
|
results = benchmark_metal_vs_traditional(str(test_image_path))
|
|
|
|
# Print results
|
|
if results["metal"]["available"]:
|
|
metal_time = results["metal"]["avg_time"]
|
|
trad_time = results["traditional"]["avg_time"]
|
|
speedup = results["speedup"]
|
|
|
|
print(f"\nMetal GPU acceleration benchmark results:")
|
|
print(f"- Metal processing time: {metal_time:.4f}s")
|
|
print(f"- Traditional processing time: {trad_time:.4f}s")
|
|
print(f"- Speedup: {speedup:.2f}x")
|
|
|
|
if speedup > 1.0:
|
|
print("\n✅ Metal GPU acceleration is working and provides a speedup!")
|
|
else:
|
|
print("\n⚠️ Metal GPU acceleration is working but provides no speedup.")
|
|
else:
|
|
print("\n❌ Metal GPU acceleration is not available for benchmarking.")
|
|
except Exception as e:
|
|
print(f"Error during benchmark: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
except Exception as e:
|
|
print(f"Failed to run performance test: {e}")
|
|
|
|
|
|
def main():
|
|
"""Main entry point for the script"""
|
|
print(f"=== Metal GPU Acceleration Setup ===")
|
|
print(f"System: {platform.system()} {platform.version()}")
|
|
print(f"Architecture: {platform.machine()}")
|
|
print(f"Python: {platform.python_version()}")
|
|
|
|
# Check if we're on macOS
|
|
if platform.system() != "Darwin":
|
|
print("Metal GPU acceleration is only available on macOS")
|
|
return 1
|
|
|
|
# Check if Metal is already available
|
|
if is_metal_available():
|
|
print("Metal GPU acceleration is already available!")
|
|
else:
|
|
print("Metal GPU acceleration is not available, installing dependencies...")
|
|
if not install_metal_dependencies():
|
|
print("Failed to install some Metal dependencies.")
|
|
# Continue anyway to see what worked
|
|
|
|
# Verify the installation
|
|
if verify_metal_installation():
|
|
print("\n✅ Metal GPU acceleration setup completed successfully!")
|
|
|
|
# Run the performance test
|
|
test_metal_performance()
|
|
|
|
print("\nYou can now use Metal GPU acceleration in Overlord!")
|
|
else:
|
|
print("\n❌ Metal GPU acceleration setup failed.")
|
|
print("Please check the errors above and try again.")
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|