#!/usr/bin/env python3 """ System configuration optimizations for improving concurrent performance. """ import os import asyncio import multiprocessing import threading import time import resource import logging from typing import Dict, Any, Optional from concurrent.futures import ThreadPoolExecutor # Configure logging logger = logging.getLogger('app') class SystemOptimizer: """System optimizer. Adjusts system parameters to improve concurrent performance. """ def __init__(self): self.original_settings = {} self.optimized = False def optimize_system_settings(self): """Apply optimized system settings.""" if self.optimized: return # Back up original settings self._backup_original_settings() # 1. Optimize file descriptor limits. try: soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) new_limit = min(65536, hard) # Increase to 65536 or the hard limit resource.setrlimit(resource.RLIMIT_NOFILE, (new_limit, hard)) self.original_settings['RLIMIT_NOFILE'] = (soft, hard) logger.info(f"File descriptor limit increased from {soft} to {new_limit}") except (ValueError, OSError) as e: logger.error(f"Failed to set file descriptor limit: {e}") # 2. Optimize thread stack size. try: soft, hard = resource.getrlimit(resource.RLIMIT_STACK) new_stack = min(8 * 1024 * 1024, hard) # 8 MB stack size resource.setrlimit(resource.RLIMIT_STACK, (new_stack, hard)) self.original_settings['RLIMIT_STACK'] = (soft, hard) logger.info(f"Thread stack size set to {new_stack // (1024*1024)}MB") except (ValueError, OSError) as e: logger.error(f"Failed to set thread stack size: {e}") # 3. Optimize environment variables. env_vars = { # Python optimizations 'PYTHONUNBUFFERED': '1', # Disable output buffering 'PYTHONDONTWRITEBYTECODE': '1', # Do not write .pyc files # Tokenizer optimizations - allow moderate parallelism 'TOKENIZERS_PARALLELISM': 'true', # Set to true to improve concurrency 'TOKENIZERS_FAST': '1', # Enable fast tokenizer # OpenMP optimizations 'OMP_NUM_THREADS': str(min(8, multiprocessing.cpu_count())), # Limit OpenMP threads 'OMP_WAIT_POLICY': 'PASSIVE', # Passive wait policy # Memory optimizations 'MALLOC_TRIM_THRESHOLD_': '100000', # Memory trimming threshold # Network optimizations 'TCP_NODELAY': '1', # Disable Nagle's algorithm # CUDA optimizations if GPU is used 'CUDA_LAUNCH_BLOCKING': '0', # Asynchronous CUDA launch # asyncio optimizations 'UVLOOP_ENABLED': '1', # Enable uvloop when available } for key, value in env_vars.items(): if key not in os.environ: os.environ[key] = value logger.info(f"Set environment variable: {key}={value}") self.optimized = True logger.info("System optimization completed") def _backup_original_settings(self): """Back up original settings.""" try: self.original_settings['RLIMIT_NOFILE'] = resource.getrlimit(resource.RLIMIT_NOFILE) self.original_settings['RLIMIT_STACK'] = resource.getrlimit(resource.RLIMIT_STACK) except: pass # Back up important environment variables. env_keys = [ 'TOKENIZERS_PARALLELISM', 'PYTHONUNBUFFERED', 'PYTHONDONTWRITEBYTECODE', 'OMP_NUM_THREADS' ] for key in env_keys: if key in os.environ: self.original_settings[key] = os.environ[key] def restore_original_settings(self): """Restore original settings.""" if not self.original_settings: return logger.info("Restoring original system settings...") # Restore resource limits. if 'RLIMIT_NOFILE' in self.original_settings: try: resource.setrlimit(resource.RLIMIT_NOFILE, self.original_settings['RLIMIT_NOFILE']) logger.info(f"Restored file descriptor limit") except: pass if 'RLIMIT_STACK' in self.original_settings: try: resource.setrlimit(resource.RLIMIT_STACK, self.original_settings['RLIMIT_STACK']) logger.info(f"Restored thread stack size") except: pass # Restore environment variables. for key, value in self.original_settings.items(): if key.startswith('TOKENIZERS_') or key in ['PYTHONUNBUFFERED', 'PYTHONDONTWRITEBYTECODE']: if key in os.environ: del os.environ[key] logger.info(f"Removed environment variable: {key}") elif key in ['OMP_NUM_THREADS'] and value is not None: os.environ[key] = value logger.info(f"Restored environment variable: {key}={value}") self.optimized = False logger.info("System settings restored") class AsyncioOptimizer: """asyncio optimizer.""" @staticmethod def setup_event_loop_policy(): """Set an optimized event loop policy.""" try: # Try to use uvloop if available. import uvloop asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) logger.info("Using uvloop event loop policy") except ImportError: logger.info("Using default event loop policy") # Set the thread pool size recommendation. cpu_count = multiprocessing.cpu_count() thread_pool_size = min(32, cpu_count * 4) # 4 threads per CPU core, up to 32 # Note: the default thread pool executor cannot be set here because # no event loop is running yet. This should be configured during app startup. logger.info(f"Recommended thread pool size: {thread_pool_size}") @staticmethod def optimize_gunicorn_settings() -> Dict[str, Any]: """Get optimized Gunicorn settings.""" cpu_count = multiprocessing.cpu_count() return { # Worker configuration 'workers': min(8, cpu_count + 1), # Number of worker processes 'worker_class': 'uvicorn.workers.UvicornWorker', # Use Uvicorn worker 'worker_connections': 2000, # Connections per worker 'max_requests': 5000, # Restart worker after max requests 'max_requests_jitter': 500, # Random jitter 'preload_app': True, # Preload application # Timeout settings 'timeout': 120, # Worker timeout 'keepalive': 5, # Keep-Alive timeout 'graceful_timeout': 30, # Graceful shutdown timeout # Performance optimizations 'worker_tmp_dir': '/dev/shm', # Use memory-backed filesystem # Logging settings 'accesslog': '-', # Standard output 'errorlog': '-', # Standard error output 'loglevel': 'info', } def setup_system_optimizations(): """Set up system optimizations.""" # 1. System-level optimizations system_optimizer = SystemOptimizer() system_optimizer.optimize_system_settings() # 2. asyncio optimizations asyncio_optimizer = AsyncioOptimizer() asyncio_optimizer.setup_event_loop_policy() return system_optimizer def create_performance_monitor() -> Dict[str, Any]: """Create performance monitoring configuration.""" return { 'monitor_interval': 60, # Monitoring interval in seconds 'metrics': { 'memory_usage': True, 'cpu_usage': True, 'disk_io': True, 'network_io': True, 'active_connections': True, 'request_latency': True, 'cache_hit_rate': True, 'error_rate': True, }, 'alerts': { 'memory_threshold': 0.9, # Alert at 90% memory usage 'cpu_threshold': 0.8, # Alert at 80% CPU usage 'disk_threshold': 0.9, # Alert at 90% disk usage 'error_threshold': 0.05, # Alert at 5% error rate 'latency_threshold': 5.0, # Alert at 5 seconds latency } } def get_optimized_worker_config() -> Dict[str, Any]: """Get optimized worker configuration.""" cpu_count = multiprocessing.cpu_count() memory_gb = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.0 ** 3) # Configuration constrained by available system resources. max_workers = min( 16, # Maximum worker count max(2, cpu_count), # At least 2 workers, at most the CPU core count int(memory_gb / 2) # Memory-based worker limit, 2 GB per worker ) return { 'max_workers': max_workers, 'worker_connections': 1000, # Connections per worker 'connection_pool_size': 100, # Connection pool size 'buffer_size': 8192, # Buffer size 'timeout': 120, # Timeout in seconds 'keepalive_timeout': 30, # Keep-Alive timeout } # Predefined optimization profiles OPTIMIZATION_CONFIGS = { 'low_memory': { 'max_workers': 2, 'worker_connections': 500, 'buffer_size': 4096, 'cache_size': 500, }, 'balanced': { 'max_workers': 4, 'worker_connections': 1000, 'buffer_size': 8192, 'cache_size': 1000, }, 'high_performance': { 'max_workers': 8, 'worker_connections': 2000, 'buffer_size': 16384, 'cache_size': 2000, } } def apply_optimization_profile(profile_name: str) -> Dict[str, Any]: """Apply an optimization profile.""" if profile_name not in OPTIMIZATION_CONFIGS: raise ValueError(f"Unknown optimization profile: {profile_name}") config = OPTIMIZATION_CONFIGS[profile_name].copy() # Add system-specific configuration. config.update({ 'profile_name': profile_name, 'applied_at': time.time(), 'cpu_count': multiprocessing.cpu_count(), 'memory_gb': os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.0 ** 3) }) return config # Global system optimizer instance _global_system_optimizer: Optional[SystemOptimizer] = None def get_global_system_optimizer() -> SystemOptimizer: """Get the global system optimizer.""" global _global_system_optimizer if _global_system_optimizer is None: _global_system_optimizer = SystemOptimizer() return _global_system_optimizer