""" 流体动力学插件性能优化模块 提供性能优化、内存管理和调试功能 """ import time import psutil import threading import numpy as np from collections import deque, defaultdict import gc class FluidPerformanceOptimizer: """ 流体性能优化器 提供性能监控、优化和调试功能,包括内存管理、多线程处理和自适应优化 """ def __init__(self, fluid_world): """ 初始化性能优化器 Args: fluid_world: 流体世界对象的引用 """ self.fluid_world = fluid_world self.optimization_enabled = True # 性能监控 self.frame_times = deque(maxlen=100) self.particle_counts = deque(maxlen=100) self.update_times = deque(maxlen=100) self.memory_usage = deque(maxlen=100) # 优化参数 self.max_particles = 5000 self.target_fps = 60 self.adaptive_resolution = True self.quality_level = 1.0 # 1.0为最高质量,0.1为最低质量 # 多线程支持 self.use_multithreading = False self.worker_threads = [] self.thread_lock = threading.Lock() self.thread_count = 2 # 内存管理 self.object_pools = defaultdict(list) # 对象池 self.max_pool_size = 1000 # 每个池的最大大小 self.memory_limit_mb = 500 # 内存限制(MB) # 自适应优化 self.adaptive_optimization = True self.optimization_history = deque(maxlen=50) # 优化历史 self.performance_trend = 0 # 性能趋势:正数表示改善,负数表示恶化 # 缓存系统 self.cache_enabled = True self.spatial_cache = {} # 空间缓存 self.cache_ttl = 5.0 # 缓存生存时间(秒) self.last_cache_cleanup = time.time() # 调试和分析 self.debug_mode = False self.profiling_enabled = False self.profiling_data = defaultdict(list) print("流体性能优化器初始化完成") def update_performance_stats(self, update_time=0): """ 更新性能统计信息 Args: update_time (float): 更新耗时 """ # 记录帧时间 current_time = time.time() if hasattr(self, 'last_update_time'): frame_time = current_time - self.last_update_time self.frame_times.append(frame_time) self.last_update_time = current_time # 记录粒子数量 particle_count = len(self.fluid_world.fluid_particles) self.particle_counts.append(particle_count) # 记录更新时间 self.update_times.append(update_time) # 记录内存使用情况 memory_mb = psutil.Process().memory_info().rss / 1024 / 1024 self.memory_usage.append(memory_mb) # 更新优化历史 self._update_optimization_history() def optimize_for_performance(self): """ 根据当前性能自适应优化 """ if not self.optimization_enabled: return # 获取当前性能指标 avg_frame_time = sum(self.frame_times) / len(self.frame_times) if self.frame_times else 0 current_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0 current_particles = len(self.fluid_world.fluid_particles) current_memory = self.memory_usage[-1] if self.memory_usage else 0 # 检查内存使用情况 if current_memory > self.memory_limit_mb: self._trigger_memory_cleanup() # 检查缓存是否需要清理 if time.time() - self.last_cache_cleanup > self.cache_ttl: self._cleanup_cache() # 根据FPS调整质量级别 if current_fps < self.target_fps * 0.7: # 性能严重不足 self.quality_level = max(0.1, self.quality_level * 0.9) self._reduce_simulation_quality() elif current_fps > self.target_fps * 1.1: # 性能良好 self.quality_level = min(1.0, self.quality_level * 1.05) self._increase_simulation_quality() # 根据粒子数量调整 if current_particles > self.max_particles * 0.9: self._reduce_particle_count() elif current_particles < self.max_particles * 0.5: self._increase_particle_count() # 根据系统资源调整 cpu_percent = psutil.cpu_percent() memory_percent = psutil.virtual_memory().percent if cpu_percent > 85: self._reduce_computation_load() if memory_percent > 85: self._trigger_memory_cleanup() def _reduce_simulation_quality(self): """ 降低模拟质量以提高性能 """ # 降低求解器精度 if hasattr(self.fluid_world, 'solver'): solver = self.fluid_world.solver solver.smoothing_radius *= 1.1 # 增大光滑半径减少计算量 solver.time_step = min(solver.time_step * 1.1, 0.05) # 增大时间步长 # 降低可视化质量 if hasattr(self.fluid_world, 'visualizer'): visualizer = self.fluid_world.visualizer visualizer.max_visible_particles = int(visualizer.max_visible_particles * 0.9) def _increase_simulation_quality(self): """ 提高模拟质量 """ # 提高求解器精度 if hasattr(self.fluid_world, 'solver'): solver = self.fluid_world.solver solver.smoothing_radius = max(solver.smoothing_radius * 0.95, 0.5) solver.time_step = max(solver.time_step * 0.95, 0.001) # 提高可视化质量 if hasattr(self.fluid_world, 'visualizer'): visualizer = self.fluid_world.visualizer visualizer.max_visible_particles = min(int(visualizer.max_visible_particles * 1.1), 20000) def _reduce_particle_count(self): """ 减少粒子数量 """ current_particles = len(self.fluid_world.fluid_particles) target_particles = int(current_particles * 0.9) # 移除多余的粒子 while len(self.fluid_world.fluid_particles) > target_particles: if self.fluid_world.fluid_particles: # 回收粒子对象到对象池 particle = self.fluid_world.fluid_particles.pop() self._recycle_object('particle', particle) def _increase_particle_count(self): """ 增加粒子数量 """ current_particles = len(self.fluid_world.fluid_particles) target_particles = int(current_particles * 1.1) # 从对象池获取粒子或创建新粒子 for _ in range(target_particles - current_particles): particle = self._get_object('particle') if particle is None: # 创建新粒子 particle = { 'position': Point3(0, 0, 0), 'velocity': Vec3(0, 0, 0), 'mass': 1.0, 'density': 1000.0, 'pressure': 0.0 } self.fluid_world.fluid_particles.append(particle) def _reduce_computation_load(self): """ 减少计算负载 """ # 降低更新频率 if hasattr(self.fluid_world, 'visualizer'): visualizer = self.fluid_world.visualizer visualizer.update_frequency = max(visualizer.update_frequency * 0.9, 15) # 简化物理计算 if hasattr(self.fluid_world, 'solver'): solver = self.fluid_world.solver solver.stiffness *= 0.95 # 降低刚度 solver.viscosity *= 0.95 # 降低粘度计算复杂度 def adaptive_substepping(self, dt): """ 自适应子步长 Args: dt (float): 帧时间增量 Returns: int: 子步数 """ # 根据当前性能调整子步数 avg_frame_time = sum(self.frame_times) / len(self.frame_times) if self.frame_times else 0 current_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0 # 如果性能良好,使用更多子步以提高精度 if current_fps > self.target_fps * 0.9: return min(10, int(self.fluid_world.time_step / dt) + 1) else: # 如果性能不佳,减少子步以保持稳定 return max(1, int(self.fluid_world.time_step / dt * 0.5)) def get_performance_report(self): """ 获取详细的性能报告 Returns: dict: 性能报告 """ avg_frame_time = sum(self.frame_times) / len(self.frame_times) if self.frame_times else 0 current_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0 avg_update_time = sum(self.update_times) / len(self.update_times) if self.update_times else 0 # 获取系统资源使用情况 cpu_percent = psutil.cpu_percent() memory_percent = psutil.virtual_memory().percent process_memory = psutil.Process().memory_info().rss / 1024 / 1024 # MB particle_count = len(self.fluid_world.fluid_particles) return { 'performance': { 'current_fps': current_fps, 'avg_frame_time': avg_frame_time, 'avg_update_time': avg_update_time, 'quality_level': self.quality_level }, 'resources': { 'cpu_percent': cpu_percent, 'memory_percent': memory_percent, 'process_memory_mb': process_memory }, 'fluid_objects_count': { 'particles': particle_count, 'domains': len(self.fluid_world.fluid_domains), 'emitters': len(self.fluid_world.fluid_emitters), 'obstacles': len(self.fluid_world.fluid_obstacles), }, 'optimization': { 'enabled': self.optimization_enabled, 'adaptive': self.adaptive_optimization, 'multithreading': self.use_multithreading, 'thread_count': len(self.worker_threads) }, 'memory': { 'usage_mb': process_memory, 'limit_mb': self.memory_limit_mb, 'pool_sizes': {k: len(v) for k, v in self.object_pools.items()} }, 'recommended_actions': self._get_recommendations() } def _get_recommendations(self): """ 获取性能优化建议 Returns: list: 优化建议列表 """ recommendations = [] avg_frame_time = sum(self.frame_times) / len(self.frame_times) if self.frame_times else 0 current_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0 particle_count = len(self.fluid_world.fluid_particles) process_memory = psutil.Process().memory_info().rss / 1024 / 1024 # MB if current_fps < self.target_fps * 0.7: recommendations.append(f"性能严重不足,当前FPS: {current_fps:.1f}") if particle_count > self.max_particles * 0.9: recommendations.append(f"粒子数量过多 ({particle_count}),考虑减少粒子数量") if process_memory > self.memory_limit_mb * 0.9: recommendations.append(f"内存使用接近限制 ({process_memory:.1f}MB / {self.memory_limit_mb}MB)") if psutil.cpu_percent() > 85: recommendations.append("CPU使用率过高,考虑启用多线程") if psutil.virtual_memory().percent > 85: recommendations.append("系统内存使用率过高") return recommendations def enable_multithreading(self, enabled=True, thread_count=2): """ 启用多线程处理 Args: enabled (bool): 是否启用多线程 thread_count (int): 线程数量 """ self.use_multithreading = enabled self.thread_count = thread_count if enabled: # 停止现有线程 self._stop_worker_threads() # 创建工作线程 for i in range(thread_count): thread = threading.Thread(target=self._worker_thread, args=(i,)) thread.daemon = True thread.start() self.worker_threads.append(thread) print(f"已启用多线程处理,线程数: {thread_count}") else: # 停止所有工作线程 self._stop_worker_threads() print("已禁用多线程处理") def _stop_worker_threads(self): """ 停止所有工作线程 """ self.use_multithreading = False for thread in self.worker_threads: thread.join(timeout=1.0) self.worker_threads.clear() def _worker_thread(self, thread_id): """ 工作线程函数 Args: thread_id (int): 线程ID """ while self.use_multithreading: try: # 处理流体粒子更新 with self.thread_lock: # 将粒子分配给不同线程处理 particles = self.fluid_world.fluid_particles if particles: particles_per_thread = max(1, len(particles) // len(self.worker_threads)) start_idx = thread_id * particles_per_thread end_idx = min(start_idx + particles_per_thread, len(particles)) # 更新分配给此线程的粒子 for i in range(start_idx, end_idx): if i < len(particles): particle = particles[i] # 在这里执行粒子更新 # 例如:应用重力、更新位置等 pass # 短暂休眠以避免过度占用CPU time.sleep(0.001) except Exception as e: if self.debug_mode: print(f"工作线程 {thread_id} 出错: {e}") time.sleep(0.01) # 出错后短暂休眠 def _update_optimization_history(self): """ 更新优化历史记录 """ if self.frame_times: current_fps = 1.0 / self.frame_times[-1] if self.frame_times[-1] > 0 else 0 self.optimization_history.append({ 'timestamp': time.time(), 'fps': current_fps, 'particle_count': len(self.fluid_world.fluid_particles), 'memory_mb': self.memory_usage[-1] if self.memory_usage else 0 }) # 计算性能趋势 if len(self.optimization_history) > 5: recent_fps = [record['fps'] for record in list(self.optimization_history)[-5:]] self.performance_trend = np.mean(np.diff(recent_fps)) if len(recent_fps) > 1 else 0 def enable_profiling(self, enabled=True): """ 启用性能分析 Args: enabled (bool): 是否启用性能分析 """ self.profiling_enabled = enabled if enabled: print("性能分析已启用") else: print("性能分析已禁用") def profile_function(self, func_name, duration): """ 记录函数执行时间 Args: func_name (str): 函数名称 duration (float): 执行时间(秒) """ if self.profiling_enabled: self.profiling_data[func_name].append(duration) def get_profiling_report(self): """ 获取性能分析报告 Returns: dict: 性能分析报告 """ if not self.profiling_enabled: return {} report = {} for func_name, durations in self.profiling_data.items(): if durations: report[func_name] = { 'count': len(durations), 'total_time': sum(durations), 'avg_time': np.mean(durations), 'min_time': min(durations), 'max_time': max(durations) } return report def _trigger_memory_cleanup(self): """ 触发内存清理 """ # 清理对象池中过多的对象 for obj_type, pool in self.object_pools.items(): if len(pool) > self.max_pool_size: # 保留一部分对象,删除多余的 del pool[self.max_pool_size:] # 强制进行垃圾回收 gc.collect() if self.debug_mode: print("内存清理完成") def _cleanup_cache(self): """ 清理过期缓存 """ current_time = time.time() expired_keys = [] for key, (value, timestamp) in self.spatial_cache.items(): if current_time - timestamp > self.cache_ttl: expired_keys.append(key) for key in expired_keys: del self.spatial_cache[key] self.last_cache_cleanup = current_time def cache_spatial_query(self, query_key, result): """ 缓存空间查询结果 Args: query_key: 查询键 result: 查询结果 """ if self.cache_enabled: self.spatial_cache[query_key] = (result, time.time()) def get_cached_spatial_query(self, query_key): """ 获取缓存的空间查询结果 Args: query_key: 查询键 Returns: 查询结果或None """ if not self.cache_enabled: return None if query_key in self.spatial_cache: result, timestamp = self.spatial_cache[query_key] if time.time() - timestamp <= self.cache_ttl: return result else: # 缓存过期,删除 del self.spatial_cache[query_key] return None def _get_object(self, obj_type): """ 从对象池获取对象 Args: obj_type (str): 对象类型 Returns: 对象或None """ if obj_type in self.object_pools and self.object_pools[obj_type]: return self.object_pools[obj_type].pop() return None def _recycle_object(self, obj_type, obj): """ 回收对象到对象池 Args: obj_type (str): 对象类型 obj: 要回收的对象 """ if len(self.object_pools[obj_type]) < self.max_pool_size: # 重置对象状态 if obj_type == 'particle': obj['position'] = Point3(0, 0, 0) obj['velocity'] = Vec3(0, 0, 0) obj['density'] = 1000.0 obj['pressure'] = 0.0 self.object_pools[obj_type].append(obj) def set_memory_limit(self, limit_mb): """ 设置内存限制 Args: limit_mb (float): 内存限制(MB) """ self.memory_limit_mb = limit_mb def set_quality_level(self, level): """ 设置质量级别 Args: level (float): 质量级别 (0.1-1.0) """ self.quality_level = max(0.1, min(1.0, level)) def cleanup(self): """ 清理性能优化器资源 """ # 停止多线程 self._stop_worker_threads() # 清理对象池 self.object_pools.clear() # 清理缓存 self.spatial_cache.clear() # 清理性能数据 self.frame_times.clear() self.particle_counts.clear() self.update_times.clear() self.memory_usage.clear() self.optimization_history.clear() self.profiling_data.clear() print("流体性能优化器资源已清理")