""" VR性能监控子系统 负责VR应用的性能监控、GPU计时、管线统计和性能诊断 """ import sys import gc import time # 可选依赖 try: import psutil PSUTIL_AVAILABLE = True except ImportError: PSUTIL_AVAILABLE = False try: import GPUtil GPUTIL_AVAILABLE = True except ImportError: GPUTIL_AVAILABLE = False try: import pynvml PYNVML_AVAILABLE = True except ImportError: PYNVML_AVAILABLE = False class VRPerformanceMonitor: """VR性能监控系统 功能: - 实时性能监控(CPU、内存、GPU) - GPU渲染时间统计 - 渲染管线分析 - 性能诊断和优化建议 """ def __init__(self, vr_manager): """初始化性能监控系统 Args: vr_manager: VRManager实例的引用 """ self.vr_manager = vr_manager # ===== 性能计数器 ===== self.frame_count = 0 self.last_fps_check = 0 self.last_fps_time = 0 self.vr_fps = 0 self.submit_failures = 0 self.pose_failures = 0 # ===== 性能监控配置 ===== self.performance_monitoring = False # 是否启用性能监控 self.debug_output_enabled = False # 是否启用调试输出 self.debug_mode = 'detailed' # 'brief' 或 'detailed' self.cpu_usage = 0.0 self.memory_usage = 0.0 self.gpu_usage = 0.0 self.gpu_memory_usage = 0.0 self.frame_times = [] # 存储最近帧时间 self.max_frame_time_history = 60 # 保存60帧的历史 self.last_performance_check = 0 self.performance_check_interval = 0.5 # 每0.5秒更新一次性能数据 # ===== 渲染管线监控 ===== self.enable_pipeline_monitoring = True # 是否启用管线监控 self.performance_mode_enabled = False # 性能优化模式(禁用监控以减少对象创建) self.performance_mode_trigger_frame = 600 # 第600帧后启用性能模式 self.wait_poses_time = 0.0 # waitGetPoses耗时 self.left_render_time = 0.0 # 左眼渲染耗时 self.right_render_time = 0.0 # 右眼渲染耗时 self.submit_time = 0.0 # 纹理提交耗时 self.left_render_count = 0 # 左眼渲染次数计数 self.right_render_count = 0 # 右眼渲染次数计数 self.total_frame_time = 0.0 # 总帧时间 self.vr_sync_wait_time = 0.0 # VR同步等待时间 # ===== 时间监控历史 ===== self.wait_poses_times = [] self.render_times = [] self.submit_times = [] self.sync_wait_times = [] self.pipeline_history_size = 30 # ===== GPU渲染时间监控 ===== self.enable_gpu_timing = False # 是否启用GPU时间监控(默认关闭) self.gpu_scene_render_ms = 0.0 # GPU场景渲染时间 self.gpu_pre_submit_ms = 0.0 # 提交前GPU时间 self.gpu_post_submit_ms = 0.0 # 提交后GPU时间 self.gpu_total_render_ms = 0.0 # GPU总渲染时间 self.gpu_compositor_render_ms = 0.0 # GPU合成器渲染时间 self.gpu_client_frame_interval_ms = 0.0 # 客户端帧间隔 self.gpu_timing_history = [] # GPU时间历史记录 self.gpu_timing_history_size = 30 # GPU时间历史记录大小 self.gpu_timing_failure_count = 0 # GPU时间获取失败次数 # ===== VR系统信息 ===== self.current_eye_resolution = (0, 0) self.recommended_eye_resolution = (0, 0) self.vr_display_frequency = 0.0 self.vr_vsync_enabled = True self.vsync_to_photons_ms = 0.0 # VSync到光子的延迟 self.target_frame_time_ms = 0.0 # 目标帧时间 self.vsync_window_ms = 0.0 # VSync时间窗口 self.async_reprojection_enabled = False # 异步重投影状态 self.motion_smoothing_enabled = False # 运动平滑状态 # ===== 性能报告间隔 ===== self.performance_report_interval = 1800 # 默认1800帧(30秒@60fps) # ===== 内部状态 ===== self._last_frame_time = None # 用于帧时间计算 # 初始化性能监控库 self._init_performance_monitoring() # ========== 性能报告方法 ========== def _print_performance_report(self): """输出VR性能报告""" if not self.performance_monitoring or not self.debug_output_enabled: return stats = self.get_performance_stats() # 简短模式输出 if self.debug_mode == 'brief': self._print_brief_performance_report(stats) return print("📊 ======= VR性能监控报告 =======") # 帧率和帧时间信息 print(f"🎯 渲染性能:") print(f" VR帧率: {stats['vr_fps']:.1f} FPS") print(f" 平均帧时间: {stats['frame_time_avg']:.2f} ms") print(f" 最小帧时间: {stats['frame_time_min']:.2f} ms") print(f" 最大帧时间: {stats['frame_time_max']:.2f} ms") print(f" 95%帧时间: {stats['frame_time_95th']:.2f} ms") # 系统性能 print(f"💻 系统性能:") print(f" CPU使用率: {stats['cpu_usage']:.1f}%") print(f" 内存使用率: {stats['memory_usage']:.1f}%") # GPU性能 print(f"🎮 GPU性能:") if self.gputil_available or self.nvidia_ml_available: print(f" GPU使用率: {stats['gpu_usage']:.1f}%") print(f" 显存使用率: {stats['gpu_memory_usage']:.1f}%") else: print(f" GPU监控: 不可用 (需要安装 GPUtil 或 pynvml)") print(f" 安装命令: pip install GPUtil nvidia-ml-py") # GPU渲染时间(OpenVR Frame Timing) if self.enable_gpu_timing: print(f"⚡ GPU渲染时间:") pipeline_stats = self._get_pipeline_stats() gpu_stats = pipeline_stats.get('gpu_timing', {}) gpu_current = pipeline_stats.get('current', {}) # 检查是否有可用的GPU时间数据 has_gpu_data = any( gpu_current.get(field, 0) > 0 for field in ['gpu_scene_render', 'gpu_total_render', 'gpu_pre_submit', 'gpu_post_submit', 'gpu_compositor_render'] ) if has_gpu_data: # 显示GPU时间统计(最近30帧平均) scene_render = gpu_stats.get('scene_render', {'avg': 0}) total_render = gpu_stats.get('total_render', {'avg': 0}) pre_submit = gpu_stats.get('pre_submit', {'avg': 0}) post_submit = gpu_stats.get('post_submit', {'avg': 0}) compositor = gpu_stats.get('compositor_render', {'avg': 0}) if scene_render['avg'] > 0: print(f" GPU场景渲染: {scene_render['avg']:.2f}ms (min:{scene_render['min']:.1f}, max:{scene_render['max']:.1f})") if total_render['avg'] > 0: print(f" GPU总渲染时间: {total_render['avg']:.2f}ms (min:{total_render['min']:.1f}, max:{total_render['max']:.1f})") if pre_submit['avg'] > 0: print(f" GPU提交前时间: {pre_submit['avg']:.2f}ms (min:{pre_submit['min']:.1f}, max:{pre_submit['max']:.1f})") if post_submit['avg'] > 0: print(f" GPU提交后时间: {post_submit['avg']:.2f}ms (min:{post_submit['min']:.1f}, max:{post_submit['max']:.1f})") if compositor['avg'] > 0: print(f" GPU合成器时间: {compositor['avg']:.2f}ms (min:{compositor['min']:.1f}, max:{compositor['max']:.1f})") # 显示当前帧GPU时间 print(f"🔍 当前帧GPU时间:") if gpu_current.get('gpu_scene_render', 0) > 0: print(f" 场景渲染: {gpu_current['gpu_scene_render']:.2f}ms") if gpu_current.get('gpu_total_render', 0) > 0: print(f" 总渲染: {gpu_current['gpu_total_render']:.2f}ms") if gpu_current.get('gpu_compositor_render', 0) > 0: print(f" 合成器: {gpu_current['gpu_compositor_render']:.2f}ms") # GPU时间瓶颈分析 current_total = gpu_current.get('gpu_total_render', 0) current_scene = gpu_current.get('gpu_scene_render', 0) if current_total > 12.0: # 假设72fps目标,留出一些余量 print(f" ⚠️ GPU总渲染时间过长: {current_total:.1f}ms") elif current_scene > 8.0: print(f" ⚠️ GPU场景渲染时间偏高: {current_scene:.1f}ms") else: print(f" GPU渲染时间: 暂无数据") if self.gpu_timing_failure_count > 0: print(f" 获取失败次数: {self.gpu_timing_failure_count}") else: print(f" 等待OpenVR Frame Timing数据...") else: print(f"⚡ GPU渲染时间: 已禁用") # VR特定指标 print(f"🥽 VR指标:") print(f" 总帧数: {stats['frame_count']}") print(f" 提交失败: {stats['submit_failures']}") print(f" 姿态失败: {stats['pose_failures']}") # 计算失败率 if stats['frame_count'] > 0: submit_fail_rate = (stats['submit_failures'] / stats['frame_count']) * 100 pose_fail_rate = (stats['pose_failures'] / stats['frame_count']) * 100 print(f" 提交失败率: {submit_fail_rate:.2f}%") print(f" 姿态失败率: {pose_fail_rate:.2f}%") # 渲染管线监控 target_frame_time = 13.9 # 默认目标帧时间(72Hz) if self.enable_pipeline_monitoring: pipeline_stats = self._get_pipeline_stats() print(f"⚙️ 渲染管线分析:") print(f" 当前分辨率: {pipeline_stats['vr_info']['eye_resolution'][0]}x{pipeline_stats['vr_info']['eye_resolution'][1]}") print(f" 推荐分辨率: {pipeline_stats['vr_info']['recommended_resolution'][0]}x{pipeline_stats['vr_info']['recommended_resolution'][1]}") print(f" 显示频率: {pipeline_stats['vr_info']['display_frequency']:.1f} Hz") # VSync和时序信息 if pipeline_stats['vr_info']['target_frame_time_ms'] > 0: print(f"🎯 VSync时序:") print(f" 目标帧时间: {pipeline_stats['vr_info']['target_frame_time_ms']:.2f}ms") print(f" VSync到光子: {pipeline_stats['vr_info']['vsync_to_photons_ms']:.2f}ms") print(f" VSync窗口: ±{pipeline_stats['vr_info']['vsync_window_ms']:.2f}ms") print(f" 异步重投影: {'启用' if pipeline_stats['vr_info']['async_reprojection'] else '禁用'}") print(f" 运动平滑: {'启用' if pipeline_stats['vr_info']['motion_smoothing'] else '禁用'}") # 分析帧时间是否在目标范围内 current_frame_time = stats['frame_time_avg'] target_frame_time = pipeline_stats['vr_info']['target_frame_time_ms'] if current_frame_time > 0 and target_frame_time > 0: frame_time_ratio = current_frame_time / target_frame_time if frame_time_ratio > 1.1: print(f" ⚠️ 帧时间超标: {current_frame_time:.1f}ms (目标:{target_frame_time:.1f}ms)") elif frame_time_ratio < 0.9: print(f" ✅ 帧时间充裕: {current_frame_time:.1f}ms (目标:{target_frame_time:.1f}ms)") else: print(f" ✓ 帧时间正常: {current_frame_time:.1f}ms (目标:{target_frame_time:.1f}ms)") # 🔧 性能优化诊断 print(f"🔧 优化诊断:") current = pipeline_stats.get('current', {}) if self.enable_pipeline_monitoring else {} # 🔍 渲染回调诊断 - 新增 self._print_render_callback_diagnostics() # waitGetPoses时序分析 wait_poses_time = current.get('wait_poses', 0) if wait_poses_time > 10: print(f" ⚠️ waitGetPoses时间过长: {wait_poses_time:.1f}ms") print(f" 可能原因: 错过VSync窗口,建议调整预测时间") elif wait_poses_time > 5: print(f" ⚠️ waitGetPoses时间偏高: {wait_poses_time:.1f}ms") else: print(f" ✓ waitGetPoses时间正常: {wait_poses_time:.1f}ms") # CPU-GPU并行度分析 - 增强诊断 gpu_total = current.get('gpu_total_render', 0) cpu_render_left = self.left_render_time cpu_render_right = self.right_render_time cpu_render_total = cpu_render_left + cpu_render_right print(f" 真实渲染时间对比:") print(f" CPU左眼: {cpu_render_left:.2f}ms") print(f" CPU右眼: {cpu_render_right:.2f}ms") print(f" CPU总计: {cpu_render_total:.2f}ms") print(f" GPU总计: {gpu_total:.2f}ms") if cpu_render_total < 1.0: print(f" ⚠️ CPU渲染时间异常短: {cpu_render_total:.2f}ms") print(f" 可能原因: 渲染回调未正确执行或渲染被跳过") elif gpu_total > 0 and cpu_render_total > 0: ratio = gpu_total / cpu_render_total if ratio > 10: print(f" ⚠️ GPU严重等待CPU: 比例{ratio:.1f}:1") print(f" 建议: 检查OpenGL命令提交时机和渲染状态") elif ratio > 3: print(f" ⚠️ GPU等待CPU: 比例{ratio:.1f}:1") print(f" 建议: 检查OpenGL命令提交是否及时") else: print(f" ✓ CPU-GPU时间匹配: 比例{ratio:.1f}:1") # 预测时间诊断 current_prediction = self.vr_manager.use_prediction_time * 1000 print(f" 预测时间设置: {current_prediction:.1f}ms") if current_prediction > 15: print(f" 建议: 预测时间较高,可能增加waitGetPoses延迟") elif current_prediction < 8: print(f" 注意: 预测时间较低,可能影响姿态准确性") else: print(f" ✓ 预测时间在合理范围内") # 优化状态总结 optimization_score = 0 if wait_poses_time < 8: optimization_score += 1 if stats['vr_fps'] > 60: optimization_score += 1 if stats.get('frame_time_avg', 0) < target_frame_time * 1.1: optimization_score += 1 if optimization_score >= 2: print(f" ✅ 优化效果良好 ({optimization_score}/3)") else: print(f" ⚠️ 仍有优化空间 ({optimization_score}/3)") # 显示详细统计信息(仅当管线监控启用时) if self.enable_pipeline_monitoring: print(f"🕐 各阶段耗时 (最近{self.pipeline_history_size}帧平均):") print(f" waitGetPoses: {pipeline_stats['wait_poses']['avg']:.2f}ms (min:{pipeline_stats['wait_poses']['min']:.1f}, max:{pipeline_stats['wait_poses']['max']:.1f})") print(f" 渲染总计: {pipeline_stats['render']['avg']:.2f}ms (min:{pipeline_stats['render']['min']:.1f}, max:{pipeline_stats['render']['max']:.1f})") print(f" 纹理提交: {pipeline_stats['submit']['avg']:.2f}ms (min:{pipeline_stats['submit']['min']:.1f}, max:{pipeline_stats['submit']['max']:.1f})") if pipeline_stats['sync_wait']['avg'] > 0: print(f" 同步等待: {pipeline_stats['sync_wait']['avg']:.2f}ms (min:{pipeline_stats['sync_wait']['min']:.1f}, max:{pipeline_stats['sync_wait']['max']:.1f})") print(f"🔍 当前帧详情:") print(f" 左眼渲染: {pipeline_stats['current']['left_render']:.2f}ms") print(f" 右眼渲染: {pipeline_stats['current']['right_render']:.2f}ms") print(f" 姿态获取: {pipeline_stats['current']['wait_poses']:.2f}ms") # 显示Running Start模式信息 print(f"🎯 Running Start模式:") print(f" 模式: Valve Running Start - 帧开始时获取姿态") print(f" 优势: VSync前3ms获取姿态,提供充足渲染时间") print(f" 预测时间: {self.vr_manager.use_prediction_time * 1000:.1f}ms") # 分析最大瓶颈 current = pipeline_stats['current'] bottleneck_analysis = [] if current['wait_poses'] > 5.0: bottleneck_analysis.append(f"姿态获取耗时过长({current['wait_poses']:.1f}ms)") if current['total_render'] > 8.0: bottleneck_analysis.append(f"渲染耗时过长({current['total_render']:.1f}ms)") if current['submit'] > 2.0: bottleneck_analysis.append(f"纹理提交耗时过长({current['submit']:.1f}ms)") if bottleneck_analysis: print(f"🚨 瓶颈分析:") for analysis in bottleneck_analysis: print(f" ⚠️ {analysis}") # 性能建议 self._print_performance_recommendations(stats) print("===============================") def _print_performance_recommendations(self, stats): """根据性能数据输出优化建议""" print(f"💡 性能建议:") recommendations = [] # FPS相关建议 if stats['vr_fps'] < 60: recommendations.append(" ⚠️ VR帧率过低,可能影响体验") # 帧时间相关建议 if stats['frame_time_avg'] > 16.7: # 60fps = 16.7ms recommendations.append(" ⚠️ 平均帧时间过高,建议降低渲染质量") if stats['frame_time_max'] > 50: recommendations.append(" ⚠️ 检测到严重卡顿,检查CPU/GPU负载") # CPU建议 if stats['cpu_usage'] > 80: recommendations.append(" 🔴 CPU使用率过高,可能存在CPU瓶颈") elif stats['cpu_usage'] > 60: recommendations.append(" 🟡 CPU使用率偏高,注意监控") # 内存建议 if stats['memory_usage'] > 85: recommendations.append(" 🔴 内存使用率过高,可能影响性能") # GPU建议 if self.gputil_available or self.nvidia_ml_available: if stats['gpu_usage'] > 95: recommendations.append(" 🔴 GPU使用率接近满载,存在GPU瓶颈") if stats['gpu_memory_usage'] > 90: recommendations.append(" 🔴 显存使用率过高,可能需要降低纹理质量") # GPU渲染时间建议 if self.enable_gpu_timing: if self.gpu_total_render_ms > 12.0: recommendations.append(" ⚠️ GPU总渲染时间过长,建议优化场景复杂度") if self.gpu_scene_render_ms > 8.0: recommendations.append(" ⚠️ GPU场景渲染时间偏高,考虑降低渲染质量") if self.gpu_compositor_render_ms > 3.0: recommendations.append(" ⚠️ GPU合成器时间过长,检查VR设置或叠加层") if self.gpu_timing_failure_count > 100: recommendations.append(" ⚠️ GPU时间统计频繁失败,可能需要更新OpenVR") # 失败率建议 submit_fail_rate = (stats['submit_failures'] / max(stats['frame_count'], 1)) * 100 if submit_fail_rate > 1: recommendations.append(" ⚠️ VR帧提交失败率较高,检查VR系统状态") if not recommendations: recommendations.append(" ✅ 性能表现良好,无明显问题") for rec in recommendations: print(rec) def _print_brief_performance_report(self, stats): """输出简短的VR性能报告""" # 创建一行简短摘要 summary = f"🥽 VR性能: {stats['vr_fps']:.1f}fps" if stats['frame_time_avg'] > 0: summary += f" | 帧时间: {stats['frame_time_avg']:.1f}ms" if self.psutil_available: summary += f" | CPU: {stats['cpu_usage']:.0f}%" summary += f" | 内存: {stats['memory_usage']:.0f}%" # 显示GPU信息,如果库不可用则显示提示 if self.gputil_available or self.nvidia_ml_available: summary += f" | GPU: {stats['gpu_usage']:.0f}%" else: summary += " | GPU: N/A" # 添加失败率指示 if stats['frame_count'] > 0: submit_fail_rate = (stats['submit_failures'] / stats['frame_count']) * 100 if submit_fail_rate > 0.1: summary += f" | 提交失败: {submit_fail_rate:.1f}%" # 添加管线关键信息 if self.enable_pipeline_monitoring: pipeline_stats = self._get_pipeline_stats() current = pipeline_stats['current'] # 显示关键瓶颈 if current['wait_poses'] > 5.0: summary += f" | 姿态: {current['wait_poses']:.1f}ms⚠️" elif current['wait_poses'] > 0: summary += f" | 姿态: {current['wait_poses']:.1f}ms" if current['total_render'] > 8.0: summary += f" | 渲染: {current['total_render']:.1f}ms⚠️" elif current['total_render'] > 0: summary += f" | 渲染: {current['total_render']:.1f}ms" # 添加GPU渲染时间信息 if self.enable_gpu_timing: gpu_total = current.get('gpu_total_render', 0) gpu_scene = current.get('gpu_scene_render', 0) if gpu_total > 12.0: summary += f" | GPU: {gpu_total:.1f}ms⚠️" elif gpu_total > 0: summary += f" | GPU: {gpu_total:.1f}ms" elif gpu_scene > 0: summary += f" | GPU场景: {gpu_scene:.1f}ms" # 显示目标帧时间对比 vr_info = pipeline_stats['vr_info'] if vr_info['target_frame_time_ms'] > 0: target = vr_info['target_frame_time_ms'] current_avg = stats['frame_time_avg'] if current_avg > target * 1.1: summary += f" | 目标:{target:.0f}ms⚠️" else: summary += f" | 目标:{target:.0f}ms" # 性能状态指示 if stats['vr_fps'] < 72: summary += " ⚠️" elif stats['vr_fps'] > 85: summary += " ✅" print(summary) # ========== 性能监控核心方法 ========== def _init_performance_monitoring(self): """初始化性能监控库""" self.psutil_available = False self.gputil_available = False self.nvidia_ml_available = False try: import psutil self.psutil = psutil self.psutil_available = True print("✓ psutil性能监控库已加载") except ImportError: print("⚠️ psutil库未安装,CPU和内存监控将不可用") try: import GPUtil self.gputil = GPUtil self.gputil_available = True print("✓ GPUtil GPU监控库已加载") except ImportError: print("⚠️ GPUtil库未安装,GPU监控将不可用") try: import pynvml self.pynvml = pynvml pynvml.nvmlInit() self.nvidia_ml_available = True print("✓ NVIDIA-ML GPU监控库已加载") except ImportError: print("⚠️ pynvml库未安装,NVIDIA GPU详细监控将不可用") except Exception as e: print(f"⚠️ NVIDIA-ML初始化失败: {e}") def _update_performance_metrics(self): """更新系统性能指标""" if not self.performance_monitoring: return current_time = time.time() # 限制更新频率 if current_time - self.last_performance_check < self.performance_check_interval: return self.last_performance_check = current_time try: # 更新CPU和内存使用率 if self.psutil_available: self.cpu_usage = self.psutil.cpu_percent(interval=None) memory = self.psutil.virtual_memory() self.memory_usage = memory.percent # 更新GPU使用率 self._update_gpu_metrics() except Exception as e: if self.frame_count % 600 == 0: # 每10秒输出一次错误 print(f"⚠️ 性能监控更新失败: {e}") def _update_gpu_metrics(self): """更新GPU相关指标""" try: # 方法1: 使用GPUtil if self.gputil_available: gpus = self.gputil.getGPUs() if gpus: gpu = gpus[0] # 使用第一个GPU self.gpu_usage = gpu.load * 100 self.gpu_memory_usage = gpu.memoryUtil * 100 # 方法2: 使用NVIDIA-ML (更精确) elif self.nvidia_ml_available: try: handle = self.pynvml.nvmlDeviceGetHandleByIndex(0) # GPU使用率 utilization = self.pynvml.nvmlDeviceGetUtilizationRates(handle) self.gpu_usage = utilization.gpu # GPU内存使用率 memory_info = self.pynvml.nvmlDeviceGetMemoryInfo(handle) self.gpu_memory_usage = (memory_info.used / memory_info.total) * 100 except Exception as e: # NVIDIA-ML可能无法在某些系统上工作 pass except Exception as e: # GPU监控失败,但不影响VR功能 pass def _track_frame_time(self): """记录帧时间 - 性能优化版本""" current_time = time.time() if self._last_frame_time is not None: frame_time = (current_time - self._last_frame_time) * 1000 # 转换为毫秒 # 🚀 性能优化:性能模式下跳过列表操作以减少内存分配 if not self.performance_mode_enabled: # 添加到帧时间历史 self.frame_times.append(frame_time) # 限制历史长度 if len(self.frame_times) > self.max_frame_time_history: self.frame_times.pop(0) self._last_frame_time = current_time # ========== GPU计时方法 ========== def _get_gpu_frame_timing(self, frames_ago=0): """获取GPU渲染时间统计 Args: frames_ago: 获取多少帧之前的数据,0表示当前帧 Returns: dict: GPU时间数据,如果获取失败返回None """ if not self.enable_gpu_timing or not self.vr_manager.vr_compositor: return None try: # 调用OpenVR的getFrameTiming API result, timing = self.vr_manager.vr_compositor.getFrameTiming(framesAgo=frames_ago) if not result: self.gpu_timing_failure_count += 1 if self.gpu_timing_failure_count % 300 == 1: # 每5秒输出一次错误 print("⚠️ OpenVR getFrameTiming调用失败") return None # 提取GPU时间数据(单位:毫秒) gpu_data = {} # 检查timing对象是否有GPU时间相关的属性 if hasattr(timing, 'm_flSceneRenderGpuMs'): gpu_data['scene_render'] = timing.m_flSceneRenderGpuMs self.gpu_scene_render_ms = timing.m_flSceneRenderGpuMs if hasattr(timing, 'm_flPreSubmitGpuMs'): gpu_data['pre_submit'] = timing.m_flPreSubmitGpuMs self.gpu_pre_submit_ms = timing.m_flPreSubmitGpuMs if hasattr(timing, 'm_flPostSubmitGpuMs'): gpu_data['post_submit'] = timing.m_flPostSubmitGpuMs self.gpu_post_submit_ms = timing.m_flPostSubmitGpuMs if hasattr(timing, 'm_flTotalRenderGpuMs'): gpu_data['total_render'] = timing.m_flTotalRenderGpuMs self.gpu_total_render_ms = timing.m_flTotalRenderGpuMs if hasattr(timing, 'm_flCompositorRenderGpuMs'): gpu_data['compositor_render'] = timing.m_flCompositorRenderGpuMs self.gpu_compositor_render_ms = timing.m_flCompositorRenderGpuMs if hasattr(timing, 'm_flClientFrameIntervalMs'): gpu_data['frame_interval'] = timing.m_flClientFrameIntervalMs self.gpu_client_frame_interval_ms = timing.m_flClientFrameIntervalMs # 将GPU时间数据添加到历史记录 if gpu_data: self.gpu_timing_history.append(gpu_data) if len(self.gpu_timing_history) > self.gpu_timing_history_size: self.gpu_timing_history.pop(0) # 调试信息 - 仅在第一次成功时输出 if not hasattr(self, '_gpu_timing_success_logged'): available_fields = list(gpu_data.keys()) print(f"✅ GPU时间统计已启用 - 可用字段: {available_fields}") self._gpu_timing_success_logged = True return gpu_data except AttributeError as e: # OpenVR Python绑定可能不包含某些字段 if self.gpu_timing_failure_count == 0: print(f"⚠️ GPU时间统计部分功能不可用: {e}") print(" 这可能是由于OpenVR Python绑定版本问题") self.gpu_timing_failure_count += 1 return None except Exception as e: self.gpu_timing_failure_count += 1 if self.gpu_timing_failure_count % 300 == 1: # 每5秒输出一次错误 print(f"⚠️ 获取GPU时间统计失败: {e}") return None def enable_gpu_timing_monitoring(self): """启用GPU时间监控""" self.enable_gpu_timing = True print("✓ VR GPU时间监控已启用") def disable_gpu_timing_monitoring(self): """禁用GPU时间监控""" self.enable_gpu_timing = False print("✓ VR GPU时间监控已禁用") # ========== 管线统计方法 ========== def _start_timing(self, operation_name): """开始计时操作 - 性能优化版本""" if not self.enable_pipeline_monitoring or self.performance_mode_enabled: return None # 🚀 性能优化:减少字典创建,只在必要时创建 return { 'operation': operation_name, 'start_time': time.perf_counter() } def _end_timing(self, timing_data): """结束计时并记录结果 - 性能优化版本""" if not self.enable_pipeline_monitoring or self.performance_mode_enabled or not timing_data: return 0.0 elapsed = (time.perf_counter() - timing_data['start_time']) * 1000 # 转换为毫秒 # 保存到相应的历史记录 operation = timing_data['operation'] if operation == 'wait_poses': self.wait_poses_time = elapsed self.wait_poses_times.append(elapsed) if len(self.wait_poses_times) > self.pipeline_history_size: self.wait_poses_times.pop(0) elif operation == 'left_render': self.left_render_time = elapsed elif operation == 'right_render': self.right_render_time = elapsed elif operation == 'submit': self.submit_time = elapsed self.submit_times.append(elapsed) if len(self.submit_times) > self.pipeline_history_size: self.submit_times.pop(0) elif operation == 'sync_wait': self.vr_sync_wait_time = elapsed self.sync_wait_times.append(elapsed) if len(self.sync_wait_times) > self.pipeline_history_size: self.sync_wait_times.pop(0) # 计算总渲染时间 total_render = self.left_render_time + self.right_render_time self.render_times.append(total_render) if len(self.render_times) > self.pipeline_history_size: self.render_times.pop(0) return elapsed def _get_pipeline_stats(self): """获取渲染管线统计信息""" def get_stats(times_list): if not times_list: return {'avg': 0.0, 'min': 0.0, 'max': 0.0} return { 'avg': sum(times_list) / len(times_list), 'min': min(times_list), 'max': max(times_list) } # 计算GPU时间统计 def get_gpu_field_stats(field_name): """从GPU时间历史记录中提取特定字段的统计信息""" values = [] for gpu_data in self.gpu_timing_history: if field_name in gpu_data: values.append(gpu_data[field_name]) return get_stats(values) return { 'wait_poses': get_stats(self.wait_poses_times), 'render': get_stats(self.render_times), 'submit': get_stats(self.submit_times), 'sync_wait': get_stats(self.sync_wait_times), 'gpu_timing': { 'scene_render': get_gpu_field_stats('scene_render'), 'pre_submit': get_gpu_field_stats('pre_submit'), 'post_submit': get_gpu_field_stats('post_submit'), 'total_render': get_gpu_field_stats('total_render'), 'compositor_render': get_gpu_field_stats('compositor_render'), 'frame_interval': get_gpu_field_stats('frame_interval') }, 'current': { 'wait_poses': self.wait_poses_time, 'left_render': self.left_render_time, 'right_render': self.right_render_time, 'submit': self.submit_time, 'sync_wait': self.vr_sync_wait_time, 'total_render': self.left_render_time + self.right_render_time, 'gpu_scene_render': self.gpu_scene_render_ms, 'gpu_pre_submit': self.gpu_pre_submit_ms, 'gpu_post_submit': self.gpu_post_submit_ms, 'gpu_total_render': self.gpu_total_render_ms, 'gpu_compositor_render': self.gpu_compositor_render_ms, 'gpu_frame_interval': self.gpu_client_frame_interval_ms }, 'vr_info': { 'eye_resolution': self.current_eye_resolution, 'recommended_resolution': self.recommended_eye_resolution, 'display_frequency': self.vr_display_frequency, 'vsync_enabled': self.vr_vsync_enabled, 'target_frame_time_ms': self.target_frame_time_ms, 'vsync_to_photons_ms': self.vsync_to_photons_ms, 'vsync_window_ms': self.vsync_window_ms, 'async_reprojection': self.async_reprojection_enabled, 'motion_smoothing': self.motion_smoothing_enabled, 'gpu_timing_enabled': self.enable_gpu_timing, 'gpu_timing_failures': self.gpu_timing_failure_count } } def test_pipeline_monitoring(self): """测试管线监控功能 - 用于调试和验证""" print("🔧 正在测试VR管线监控功能...") try: # 测试基本信息获取 print("📊 基本信息:") print(f" 当前分辨率: {self.current_eye_resolution}") print(f" 显示频率: {self.vr_display_frequency} Hz") print(f" 目标帧时间: {self.target_frame_time_ms:.2f}ms") # Running Start模式信息 print("🎯 Running Start模式:") print(f" 预测时间: {self.vr_manager.use_prediction_time * 1000:.1f}ms") print(f" 模式: Valve Running Start - 帧开始时获取姿态") # 测试管线统计 if self.enable_pipeline_monitoring: pipeline_stats = self._get_pipeline_stats() print("⚙️ 管线统计:") print(f" waitGetPoses历史: {len(self.wait_poses_times)}帧") print(f" 渲染历史: {len(self.render_times)}帧") print(f" 提交历史: {len(self.submit_times)}帧") # 测试性能报告 print("📋 生成详细性能报告:") self._print_performance_report() print("✅ 管线监控功能测试完成") else: print("⚠️ 管线监控已禁用,无法测试统计功能") except Exception as e: print(f"❌ 测试管线监控功能时发生错误: {e}") import traceback traceback.print_exc() def set_prediction_time(self, prediction_time_ms): """设置预测时间(仅用于update_task策略) Args: prediction_time_ms: 预测时间,单位毫秒(通常8-16ms) """ prediction_time_s = prediction_time_ms / 1000.0 if prediction_time_s < 0.005 or prediction_time_s > 0.020: print(f"⚠️ 预测时间超出推荐范围(5-20ms): {prediction_time_ms}ms") old_time = self.vr_manager.use_prediction_time * 1000 self.vr_manager.use_prediction_time = prediction_time_s print(f"✓ VR预测时间已设置: {old_time:.1f}ms → {prediction_time_ms:.1f}ms") # ========== 诊断工具方法 ========== def _print_render_callback_diagnostics(self): """输出渲染回调诊断信息 - 包含优化效果分析""" try: print(f"🔍 DrawCallback渲染诊断:") # 回调次数统计 left_count = self.left_render_count right_count = self.right_render_count print(f" 渲染次数: 左眼={left_count}, 右眼={right_count}") if left_count == 0 and right_count == 0: print(f" ❌ VR缓冲区未被渲染 - 这是严重问题!") return # 渲染次数平衡性检查 if abs(left_count - right_count) > 5: print(f" ⚠️ 左右眼渲染次数不平衡: 差异={abs(left_count - right_count)}") else: print(f" ✓ 左右眼渲染次数平衡") # 🔧 真实渲染时间分析 - 显示优化效果 left_render_time = self.left_render_time right_render_time = self.right_render_time total_render_time = left_render_time + right_render_time print(f" ⏱️ 精确渲染时间测量:") print(f" 左眼cbdata.upcall(): {left_render_time:.2f}ms") print(f" 右眼cbdata.upcall(): {right_render_time:.2f}ms") print(f" 总计: {total_render_time:.2f}ms") # 渲染性能评估 if total_render_time > 16.0: # 超过60FPS时间 print(f" 🔴 渲染时间过长: {total_render_time:.1f}ms (目标<13.9ms@72Hz)") print(f" 建议: 检查RenderPipeline优化是否生效") elif total_render_time > 10.0: print(f" 🟡 渲染时间偏高: {total_render_time:.1f}ms (可接受)") else: print(f" 🟢 渲染性能良好: {total_render_time:.1f}ms") # 🔧 渲染管线优化状态检查 self._check_rendering_optimizations() # OpenGL状态诊断 self._diagnose_opengl_state() except Exception as e: print(f" 渲染回调诊断失败: {e}") def _check_rendering_optimizations(self): """检查渲染优化状态""" try: print(f" 🔧 渲染优化状态:") # 检查RenderPipeline优化 if hasattr(self.vr_manager.world, 'render_pipeline') and self.vr_manager.world.render_pipeline: print(f" RenderPipeline: 已检测并优化") else: print(f" RenderPipeline: 未检测到(使用基础Panda3D)") # 检查GPU同步优化 if hasattr(self.vr_manager, '_smart_sync_logged'): last_sync_frame = getattr(self.vr_manager, '_last_gpu_sync_frame', 0) current_frame = self.frame_count frames_since_sync = current_frame - last_sync_frame print(f" 智能GPU同步: 已启用 (距离上次同步: {frames_since_sync}帧)") else: print(f" 智能GPU同步: 未初始化") # 检查对象池状态 matrix_pool_status = self.vr_manager.get_object_pool_status() print(f" 对象池: Mat4={matrix_pool_status['matrix_pool_size']}/{matrix_pool_status['matrix_pool_capacity']}") # 检查垃圾回收控制 gc_status = self.get_debug_status() if gc_status['gc_disabled']: print(f" GC控制: 已启用手动模式 (间隔:{gc_status['manual_gc_interval']}帧)") else: print(f" GC控制: 自动模式") except Exception as e: print(f" 优化状态检查失败: {e}") def _diagnose_opengl_state(self): """诊断OpenGL渲染状态""" try: # 检查VR缓冲区状态 if hasattr(self.vr_manager, 'vr_left_eye_buffer') and self.vr_manager.vr_left_eye_buffer: left_gsg = self.vr_manager.vr_left_eye_buffer.getGsg() left_valid = self.vr_manager.vr_left_eye_buffer.isValid() print(f" 左眼缓冲区: {'有效' if left_valid else '无效'}") if hasattr(self.vr_manager, 'vr_right_eye_buffer') and self.vr_manager.vr_right_eye_buffer: right_gsg = self.vr_manager.vr_right_eye_buffer.getGsg() right_valid = self.vr_manager.vr_right_eye_buffer.isValid() print(f" 右眼缓冲区: {'有效' if right_valid else '无效'}") # 检查纹理准备状态 if hasattr(self.vr_manager, 'textures_prepared'): print(f" 纹理准备状态: {'已准备' if self.vr_manager.textures_prepared else '未准备'}") # 检查纹理ID缓存 if hasattr(self.vr_manager, 'left_texture_id') and hasattr(self.vr_manager, 'right_texture_id'): left_id = self.vr_manager.left_texture_id or 0 right_id = self.vr_manager.right_texture_id or 0 print(f" 纹理ID缓存: 左眼={left_id}, 右眼={right_id}") if left_id == 0 or right_id == 0: print(f" ⚠️ 检测到无效的纹理ID,这可能导致提交失败") else: print(f" ✓ 纹理ID缓存正常") # 检查场景渲染状态 if hasattr(self.vr_manager.world, 'render') and self.vr_manager.world.render: render_children = len(self.vr_manager.world.render.getChildren()) print(f" 场景节点数: {render_children}") if render_children == 0: print(f" ⚠️ 场景为空,可能导致渲染时间异常短") except Exception as e: print(f" OpenGL状态诊断失败: {e}") # ========== 调试控制方法 ========== def enable_debug_output(self): """启用调试输出""" self.debug_output_enabled = True print("✓ VR调试输出已启用") def disable_debug_output(self): """禁用调试输出""" self.debug_output_enabled = False print("✓ VR调试输出已禁用") def set_debug_mode(self, mode): """设置调试模式 Args: mode: 'brief' 或 'detailed' """ if mode in ['brief', 'detailed']: self.debug_mode = mode print(f"✓ VR调试模式设置为: {mode}") else: print("⚠️ 调试模式只能是 'brief' 或 'detailed'") def toggle_debug_output(self): """切换调试输出状态""" self.debug_output_enabled = not self.debug_output_enabled status = "启用" if self.debug_output_enabled else "禁用" print(f"✓ VR调试输出已{status}") return self.debug_output_enabled def get_debug_status(self): """获取调试状态""" return { 'debug_enabled': self.debug_output_enabled, 'debug_mode': self.debug_mode, 'performance_monitoring': self.performance_monitoring, 'report_interval_frames': self.performance_report_interval, 'report_interval_seconds': self.performance_report_interval / 60, # 假设60fps 'gc_control_enabled': self.vr_manager._gc_control_enabled, 'gc_disabled': self.vr_manager._gc_disabled, 'manual_gc_interval': self.vr_manager._manual_gc_interval, } # ========== 配置方法 ========== def set_performance_check_interval(self, interval): """设置性能检查间隔 Args: interval: 检查间隔(秒),建议0.1-2.0之间 """ if 0.1 <= interval <= 5.0: self.performance_check_interval = interval print(f"✓ 性能监控间隔设置为 {interval:.1f} 秒") else: print("⚠️ 性能监控间隔应在0.1-5.0秒之间") def set_frame_time_history_size(self, size): """设置帧时间历史记录大小 Args: size: 历史记录大小(帧数),建议30-300之间 """ if 10 <= size <= 1000: self.max_frame_time_history = size # 清理超出的历史记录 if len(self.frame_times) > size: self.frame_times = self.frame_times[-size:] print(f"✓ 帧时间历史记录大小设置为 {size} 帧") else: print("⚠️ 帧时间历史记录大小应在10-1000帧之间") def set_performance_report_interval(self, frames): """设置性能报告输出间隔 Args: frames: 帧数间隔,建议300-7200之间(5秒-2分钟@60fps) """ if 300 <= frames <= 7200: # 修改_update_vr中的报告间隔 print(f"✓ 性能报告间隔设置为每 {frames} 帧(约 {frames/60:.1f} 秒@60fps)") # 这里可以添加一个实例变量来控制 self.performance_report_interval = frames else: print("⚠️ 性能报告间隔应在300-7200帧之间") # ========== 查询方法 ========== def get_performance_stats(self): """获取详细的性能统计信息""" stats = { 'vr_fps': self.vr_fps, 'frame_count': self.frame_count, 'submit_failures': self.submit_failures, 'pose_failures': self.pose_failures, 'cpu_usage': self.cpu_usage, 'memory_usage': self.memory_usage, 'gpu_usage': self.gpu_usage, 'gpu_memory_usage': self.gpu_memory_usage, } # 计算帧时间统计 if self.frame_times: stats['frame_time_avg'] = sum(self.frame_times) / len(self.frame_times) stats['frame_time_min'] = min(self.frame_times) stats['frame_time_max'] = max(self.frame_times) stats['frame_time_95th'] = sorted(self.frame_times)[int(len(self.frame_times) * 0.95)] else: stats['frame_time_avg'] = 0 stats['frame_time_min'] = 0 stats['frame_time_max'] = 0 stats['frame_time_95th'] = 0 return stats def get_current_performance_summary(self): """获取当前性能摘要(简短版本)""" stats = self.get_performance_stats() summary = f"VR性能: {stats['vr_fps']:.1f}fps" if stats['frame_time_avg'] > 0: summary += f" | 帧时间: {stats['frame_time_avg']:.1f}ms" if self.psutil_available: summary += f" | CPU: {stats['cpu_usage']:.0f}%" summary += f" | 内存: {stats['memory_usage']:.0f}%" # 显示GPU信息,如果库不可用则显示提示 if self.gputil_available or self.nvidia_ml_available: summary += f" | GPU: {stats['gpu_usage']:.0f}%" else: summary += " | GPU: N/A" return summary def get_performance_monitoring_config(self): """获取当前性能监控配置""" return { 'enabled': self.performance_monitoring, 'check_interval': self.performance_check_interval, 'frame_history_size': self.max_frame_time_history, 'report_interval': self.performance_report_interval, 'psutil_available': self.psutil_available, 'gputil_available': self.gputil_available, 'nvidia_ml_available': self.nvidia_ml_available } def print_performance_monitoring_status(self): """输出性能监控状态""" config = self.get_performance_monitoring_config() print("🔧 ===== VR性能监控配置 =====") print(f" 监控状态: {'✅ 启用' if config['enabled'] else '❌ 禁用'}") print(f" 检查间隔: {config['check_interval']:.1f} 秒") print(f" 帧时间历史: {config['frame_history_size']} 帧") print(f" 报告间隔: {config['report_interval']} 帧") print(f" 可用库:") print(f" psutil (CPU/内存): {'✅' if config['psutil_available'] else '❌'}") print(f" GPUtil (GPU): {'✅' if config['gputil_available'] else '❌'}") print(f" NVIDIA-ML (GPU): {'✅' if config['nvidia_ml_available'] else '❌'}") print("=============================") # ========== 控制方法 ========== def enable_performance_monitoring(self): """启用性能监控""" self.performance_monitoring = True print("✓ VR性能监控已启用") def disable_performance_monitoring(self): """禁用性能监控""" self.performance_monitoring = False print("✓ VR性能监控已禁用") def force_performance_report(self): """强制输出一次性能报告""" print("🔄 手动触发性能报告...") self._print_performance_report() def reset_performance_counters(self): """重置性能计数器""" self.frame_count = 0 self.last_fps_check = 0 self.last_fps_time = 0 self.vr_fps = 0 self.submit_failures = 0 self.pose_failures = 0 self.frame_times.clear() print("✅ 性能计数器已重置")