Coverage for src / monte_neo / cli / menu / hardware.py: 0%
95 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
1"""Hardware configuration workflow."""
3from __future__ import annotations
5from typing import TYPE_CHECKING
7import questionary
8from rich.console import Console
9from rich.panel import Panel
10from rich.table import Table
12from monte_neo.cli.styles import CUSTOM_STYLE
14if TYPE_CHECKING:
15 from monte_neo.cli.menu.main import InteractiveMenu
17console = Console()
20def hardware_workflow(menu: InteractiveMenu) -> None:
21 """Hardware configuration menu."""
22 console.print("\n[bold cyan]🔧 Hardware Configuration[/]\n")
24 # Display current hardware info
25 _show_hardware_info(menu)
27 choices = [
28 {"name": f"🚀 Use GPU ({'✅' if menu._use_gpu else '❌'})", "value": "toggle_gpu"},
29 {"name": f"💎 GPU Precision ({menu._gpu_precision})", "value": "gpu_precision"},
30 {"name": f"⚡ Metal Driver ({menu._metal_driver.upper()})", "value": "metal_driver"},
31 {"name": f"🎯 MC Pass Threshold ({menu._mc_pass_threshold:.0%})", "value": "mc_threshold"},
32 {"name": "📊 Benchmark Hardware", "value": "benchmark"},
33 {"name": "🔙 Back", "value": "back"},
34 ]
36 choice = questionary.select("Select hardware option:", choices=choices, style=CUSTOM_STYLE).ask()
38 if choice == "toggle_gpu":
39 menu._use_gpu = not menu._use_gpu
40 status = "enabled" if menu._use_gpu else "disabled"
41 console.print(f"[green]GPU acceleration {status}[/]")
43 elif choice == "gpu_precision":
44 prec_choices = [
45 {"name": "float32 (Standard - Best compatibility)", "value": "float32"},
46 {"name": "float16 (Faster - Good performance)", "value": "float16"},
47 {"name": "float8_e4m3 (Extreme - 4x memory bandwidth)", "value": "float8_e4m3"},
48 {"name": "float8_e5m2 (Extreme - 4x memory bandwidth)", "value": "float8_e5m2"},
49 ]
50 val = questionary.select("Select GPU precision:", choices=prec_choices, style=CUSTOM_STYLE).ask()
51 if val:
52 menu._gpu_precision = val
53 console.print(f"[green]GPU precision set to {val}[/]")
55 elif choice == "metal_driver":
56 if not menu._use_gpu:
57 console.print("[yellow]⚠️ Enable GPU first to use Metal drivers[/]")
58 else:
59 driver_choices = [
60 {"name": "Auto-Select (Recommended)", "value": "auto"},
61 {"name": "Clang C++ (Optimized)", "value": "cpp"},
62 {"name": "Objective-C++ (Native)", "value": "objc"},
63 {"name": "Apple Swift (Modern)", "value": "swift"},
64 ]
65 val = questionary.select("Select Metal driver:", choices=driver_choices, style=CUSTOM_STYLE).ask()
66 if val:
67 menu._metal_driver = val
68 # Update config object and save
69 menu.config.metal_driver = val
70 from monte_neo.utils.config import save_config
71 save_config(menu.config, "config.yaml")
72 console.print(f"[green]Metal driver set to {val.upper()} and saved to config.yaml[/]")
74 elif choice == "mc_threshold":
75 val = questionary.text("MC Pass Threshold (0.0-1.0):", default=str(menu._mc_pass_threshold)).ask()
76 if val:
77 menu._mc_pass_threshold = float(val)
78 console.print(f"[green]MC pass threshold set to {menu._mc_pass_threshold:.0%}[/]")
80 elif choice == "benchmark":
81 _run_hardware_benchmark(menu)
84def _show_hardware_info(menu: InteractiveMenu) -> None:
85 """Display current hardware configuration."""
87 # Check system capabilities
88 try:
89 import mlx.core as mx
90 mlx_available = True
91 device_info = mx.get_default_device() if hasattr(mx, 'get_default_device') else "Unknown"
92 except ImportError:
93 mlx_available = False
94 device_info = "Not available"
96 try:
97 import Metal
98 metal_available = Metal.MTLCreateSystemDefaultDevice() is not None
99 if metal_available:
100 device = Metal.MTLCreateSystemDefaultDevice()
101 metal_info = f"{device.name()} - {device.maxThreadgroupMemoryLength()//1024}KB shared memory"
102 else:
103 metal_info = "No Metal device"
104 except ImportError:
105 metal_available = False
106 metal_info = "Metal framework not available"
108 # Create hardware info table
109 table = Table(title="Hardware Configuration")
110 table.add_column("Component", style="cyan")
111 table.add_column("Status", style="green")
112 table.add_column("Details", style="dim")
114 table.add_row("GPU Acceleration", "✅ Enabled" if menu._use_gpu else "❌ Disabled",
115 f"MLX: {'Available' if mlx_available else 'Not available'}")
116 table.add_row("GPU Precision", menu._gpu_precision,
117 "Memory bandwidth: 4x with float8" if menu._gpu_precision.startswith("float8") else "Standard")
118 table.add_row("Metal Driver", menu._metal_driver.upper(),
119 metal_info if metal_available else "Metal not available")
120 table.add_row("MC Pass Threshold", f"{menu._mc_pass_threshold:.0%}",
121 "Production readiness threshold")
123 console.print(Panel(table, title="Current Configuration", border_style="blue"))
126def _run_hardware_benchmark(menu: InteractiveMenu) -> None:
127 """Run hardware performance benchmark."""
128 console.print("\n[bold yellow]🏃 Running hardware benchmark...[/]\n")
130 try:
131 from monte_neo.core.acceleration.float8 import Float8Encoder
133 # Test float8 performance
134 test_sizes = [1000, 10000, 100000]
136 table = Table(title="Float8 Performance Benchmark")
137 table.add_column("Array Size", style="cyan")
138 table.add_column("float32 Time (ms)", justify="right")
139 table.add_column("float8 Time (ms)", justify="right")
140 table.add_column("Speedup", justify="right")
141 table.add_column("Memory Saved", justify="right")
143 import time
145 import numpy as np
147 for size in test_sizes:
148 # Create test data
149 test_data = np.random.randn(size).astype(np.float32)
151 # Test float32 operations
152 start_time = time.time()
153 result_f32 = test_data * 2.0 + 1.0
154 f32_time = (time.time() - start_time) * 1000
156 # Test float8 operations
157 encoder = Float8Encoder("e4m3")
158 start_time = time.time()
159 packed = encoder.encode_array(test_data)
160 unpacked = encoder.decode_array(packed)
161 result_f8 = unpacked * 2.0 + 1.0
162 f8_time = (time.time() - start_time) * 1000
164 # Calculate metrics
165 speedup = f32_time / f8_time if f8_time > 0 else 0
166 memory_saved = "75%" # 8/32 = 0.25, so 75% saved
168 table.add_row(
169 f"{size:,}",
170 f"{f32_time:.2f}",
171 f"{f8_time:.2f}",
172 f"{speedup:.2f}x",
173 memory_saved
174 )
176 console.print(table)
177 console.print("\n[green]✅ Benchmark completed![/]")
179 except Exception as e:
180 console.print(f"[red]❌ Benchmark failed: {e}[/]")
181 console.print("[yellow]💡 Make sure all dependencies are installed for float8 support[/]")