File size: 8,293 Bytes
80a1334
 
 
aae35f1
80a1334
 
aae35f1
 
 
80a1334
 
 
aae35f1
 
 
 
 
 
 
 
80a1334
 
 
aae35f1
 
 
 
 
 
 
 
 
 
 
 
80a1334
aae35f1
 
 
 
 
80a1334
 
 
 
 
aae35f1
80a1334
 
aae35f1
 
 
80a1334
aae35f1
 
 
 
 
 
 
 
 
 
 
 
 
80a1334
aae35f1
 
 
 
 
 
80a1334
 
 
 
 
 
aae35f1
80a1334
 
 
 
 
 
 
aae35f1
 
80a1334
 
aae35f1
80a1334
 
aae35f1
 
 
 
 
 
 
 
 
80a1334
 
aae35f1
 
 
 
 
 
 
 
80a1334
 
 
 
aae35f1
80a1334
 
 
aae35f1
 
80a1334
 
 
 
aae35f1
 
 
80a1334
 
 
aae35f1
80a1334
 
 
aae35f1
 
 
80a1334
 
 
 
 
 
 
aae35f1
80a1334
 
 
 
aae35f1
 
80a1334
aae35f1
 
 
 
 
 
 
80a1334
aae35f1
 
80a1334
aae35f1
 
80a1334
aae35f1
 
 
 
 
80a1334
 
 
aae35f1
 
80a1334
 
 
 
 
 
 
aae35f1
 
80a1334
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import platform
import subprocess
import os
import logging
from typing import Dict, Optional

# Configure logging
logger = logging.getLogger(__name__)


class HardwareDetector:
    def __init__(self):
        logger.info("Initializing HardwareDetector")
        try:
            self.specs = self._detect_system_specs()
            logger.info("Hardware detection completed successfully")
            logger.debug(f"Detected specs: {self.specs}")
        except Exception as e:
            logger.error(f"Failed to detect hardware specs: {e}")
            raise
    
    def _detect_system_specs(self) -> Dict:
        """Detect system hardware specifications automatically."""
        logger.debug("Starting system hardware detection")
        
        platform_info = platform.system()
        architecture = platform.machine()
        cpu_count = os.cpu_count()
        python_version = platform.python_version()
        
        logger.debug(f"Platform: {platform_info}, Architecture: {architecture}")
        logger.debug(f"CPU cores: {cpu_count}, Python: {python_version}")
        
        gpu_info = self._detect_gpu()
        
        specs = {
            'platform': platform_info,
            'architecture': architecture,
            'cpu_count': cpu_count,
            'python_version': python_version,
            'gpu_info': gpu_info,
            'cuda_available': False,
            'mps_available': False
        }
        
        # Check for PyTorch and device availability
        logger.debug("Checking PyTorch availability")
        try:
            import torch
            torch_version = torch.__version__
            cuda_available = torch.cuda.is_available()
            mps_available = torch.backends.mps.is_available()
            
            logger.info(f"PyTorch {torch_version} detected")
            logger.debug(f"CUDA available: {cuda_available}, MPS available: {mps_available}")
            
            specs['torch_version'] = torch_version
            specs['cuda_available'] = cuda_available
            specs['mps_available'] = mps_available
            
            if cuda_available:
                device_count = torch.cuda.device_count()
                device_name = torch.cuda.get_device_name(0)
                device_memory = torch.cuda.get_device_properties(0).total_memory // (1024**3)
                
                logger.info(f"CUDA devices: {device_count}, Primary: {device_name} ({device_memory}GB)")
                
                specs['cuda_device_count'] = device_count
                specs['cuda_device_name'] = device_name
                specs['cuda_memory'] = device_memory
                
        except ImportError as e:
            logger.warning(f"PyTorch not installed: {e}")
            specs['torch_version'] = 'Not installed'
            
        return specs
    
    def _detect_gpu(self) -> Optional[Dict]:
        """Attempt to detect GPU information using nvidia-smi."""
        logger.debug("Attempting GPU detection via nvidia-smi")
        try:
            result = subprocess.run([
                'nvidia-smi', 
                '--query-gpu=name,memory.total', 
                '--format=csv,noheader,nounits'
            ], capture_output=True, text=True, check=True)
            
            logger.debug(f"nvidia-smi output: {result.stdout}")
            
            lines = result.stdout.strip().split('\n')
            gpus = []
            logger.debug(f"Found {len(lines)} GPU entries")
            for line in lines:
                if line.strip():
                    try:
                        name, memory = line.split(', ')
                        gpu_entry = {'name': name.strip(), 'memory_mb': int(memory)}
                        gpus.append(gpu_entry)
                        logger.debug(f"Parsed GPU: {gpu_entry}")
                    except ValueError as e:
                        logger.warning(f"Failed to parse GPU line '{line}': {e}")
            
            logger.info(f"Successfully detected {len(gpus)} GPUs")
            return gpus
            
        except subprocess.CalledProcessError as e:
            logger.warning(f"nvidia-smi command failed: {e}")
            return None
        except FileNotFoundError:
            logger.debug("nvidia-smi not found, no NVIDIA GPU detected")
            return None
        except Exception as e:
            logger.error(f"Unexpected error during GPU detection: {e}")
            return None
    
    def get_manual_input(self) -> Dict:
        """Get hardware specifications via manual user input."""
        logger.info("Starting manual hardware input")
        print("Enter your hardware specifications manually:")
        
        gpu_name = input("GPU Name (e.g., RTX 4090, A100, leave empty if none): ").strip()
        logger.debug(f"User input GPU name: '{gpu_name}'")
        
        if gpu_name:
            try:
                vram_gb = int(input("VRAM in GB (e.g., 24): "))
                gpu_info = [{'name': gpu_name, 'memory_mb': vram_gb * 1024}]
                logger.info(f"Manual GPU configured: {gpu_name} with {vram_gb}GB VRAM")
            except ValueError as e:
                logger.warning(f"Invalid VRAM input: {e}")
                gpu_info = None
        else:
            gpu_info = None
            logger.info("No GPU specified in manual input")
            
        try:
            ram_gb = int(input("System RAM in GB (e.g., 32): "))
            logger.debug(f"User input RAM: {ram_gb}GB")
        except ValueError as e:
            logger.warning(f"Invalid RAM input: {e}, using default 16GB")
            ram_gb = 16  # Default
            
        specs = self.specs.copy()
        specs['gpu_info'] = gpu_info
        specs['ram_gb'] = ram_gb
        specs['manual_input'] = True
        
        logger.info(f"Manual hardware specs configured: {specs}")
        return specs
    
    def get_optimization_profile(self) -> str:
        """Determine the best optimization profile based on hardware."""
        logger.debug("Determining optimization profile")
        
        if self.specs['cuda_available']:
            cuda_memory = self.specs.get('cuda_memory', 0)
            logger.debug(f"CUDA available with {cuda_memory}GB memory")
            
            if cuda_memory >= 20:
                profile = 'high_end_gpu'
            elif cuda_memory >= 8:
                profile = 'mid_range_gpu'
            else:
                profile = 'low_vram_gpu'
                
        elif self.specs['mps_available']:
            logger.debug("MPS available, using Apple Silicon profile")
            profile = 'apple_silicon'
        else:
            logger.debug("No GPU acceleration available, using CPU-only profile")
            profile = 'cpu_only'
            
        logger.info(f"Selected optimization profile: {profile}")
        return profile
    
    def print_specs(self):
        """Print detected hardware specifications."""
        logger.info("Printing hardware specifications")
        
        print(f"Platform: {self.specs['platform']} ({self.specs['architecture']})")
        print(f"CPU Cores: {self.specs['cpu_count']}")
        print(f"Python: {self.specs['python_version']}")
        print(f"PyTorch: {self.specs.get('torch_version', 'Not detected')}")
        print(f"CUDA Available: {self.specs['cuda_available']}")
        print(f"MPS Available: {self.specs['mps_available']}")
        
        logger.debug("Hardware specs display completed")
        
        if self.specs['gpu_info']:
            print("GPU Information:")
            for i, gpu in enumerate(self.specs['gpu_info']):
                vram_gb = gpu['memory_mb'] / 1024
                print(f"  GPU {i}: {gpu['name']} ({vram_gb:.1f} GB VRAM)")
        else:
            print("No GPU detected")


if __name__ == "__main__":
    detector = HardwareDetector()
    
    print("=== Auto-detected Hardware ===")
    detector.print_specs()
    
    choice = input("\nUse auto-detected specs? (y/n): ").lower()
    if choice != 'y':
        specs = detector.get_manual_input()
        detector.specs = specs
        print("\n=== Final Hardware Specs ===")
        detector.print_specs()
    
    print(f"\nRecommended optimization profile: {detector.get_optimization_profile()}")