Files
whale-town/scripts/PerformanceMonitor.gd
2025-12-05 19:00:14 +08:00

266 lines
7.3 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
## 性能监控类
## 监控游戏性能指标包括FPS、内存使用、网络延迟等
# 单例实例
static var instance: PerformanceMonitor = null
# 性能数据
var fps_history: Array[float] = []
var memory_history: Array[int] = []
var network_latency_history: Array[float] = []
# 监控配置
var max_history_size: int = 300 # 保存5分钟的数据60fps
var update_interval: float = 1.0 # 更新间隔(秒)
var last_update_time: float = 0.0
var monitoring_enabled: bool = true # 性能监控开关
# 性能阈值
var fps_warning_threshold: float = 20.0
var fps_critical_threshold: float = 5.0
var memory_warning_threshold: int = 512 * 1024 * 1024 # 512MB
var latency_warning_threshold: float = 200.0 # 200ms
# 统计数据
var frame_count: int = 0
var total_frame_time: float = 0.0
func _init():
"""初始化性能监控器"""
if instance == null:
instance = self
func _ready():
"""准备性能监控"""
set_process(true)
print("[PERF] Performance monitor initialized")
func _process(delta: float):
"""每帧更新性能数据"""
frame_count += 1
total_frame_time += delta
# 延迟启动性能监控,避免初始化时的误报
if frame_count < 120: # 前2秒不监控60fps * 2秒
return
# 定期更新性能统计
var current_time = Time.get_unix_time_from_system()
if current_time - last_update_time >= update_interval:
_update_performance_stats()
last_update_time = current_time
## 获取性能监控器实例
static func get_instance() -> PerformanceMonitor:
"""获取性能监控器单例实例"""
if instance == null:
instance = PerformanceMonitor.new()
return instance
## 更新性能统计
func _update_performance_stats():
"""更新性能统计数据"""
if not monitoring_enabled:
return
# 更新FPS
var current_fps = Engine.get_frames_per_second()
_add_to_history(fps_history, current_fps)
# 更新内存使用使用可用的内存API
var total_memory = OS.get_static_memory_peak_usage()
_add_to_history(memory_history, total_memory)
# 检查性能警告
_check_performance_warnings(current_fps, total_memory)
## 添加数据到历史记录
func _add_to_history(history: Array, value) -> void:
"""
添加数据到历史记录数组
@param history: 历史记录数组
@param value: 要添加的值
"""
history.append(value)
if history.size() > max_history_size:
history.pop_front()
## 检查性能警告
func _check_performance_warnings(fps: float, memory: int) -> void:
"""
检查性能是否达到警告阈值
@param fps: 当前FPS
@param memory: 当前内存使用
"""
# 临时禁用FPS警告因为游戏启动时可能有短暂的FPS下降
# 只在FPS持续很低时才报告
if fps < 1.0 and fps > 0: # 只有在FPS极低且不为0时才报告
print("[WARNING] [SYSTEM] Severe FPS drop detected: ", fps)
# 内存警告
if memory > memory_warning_threshold:
print("[WARNING] [SYSTEM] High memory usage: ", memory / (1024.0 * 1024.0), "MB")
## 记录网络延迟
static func record_network_latency(latency_ms: float) -> void:
"""
记录网络延迟
@param latency_ms: 延迟时间(毫秒)
"""
var monitor = get_instance()
monitor._add_to_history(monitor.network_latency_history, latency_ms)
# 检查延迟警告
if latency_ms > monitor.latency_warning_threshold:
preload("res://scripts/ErrorHandler.gd").log_network_warning(
"High network latency: " + str(latency_ms) + "ms",
{"latency": latency_ms, "threshold": monitor.latency_warning_threshold}
)
## 获取当前FPS
static func get_current_fps() -> float:
"""获取当前FPS"""
return Engine.get_frames_per_second()
## 获取平均FPS
static func get_average_fps() -> float:
"""获取平均FPS"""
var monitor = get_instance()
if monitor.fps_history.is_empty():
return 0.0
var total = 0.0
for fps in monitor.fps_history:
total += fps
return total / monitor.fps_history.size()
## 获取最低FPS
static func get_min_fps() -> float:
"""获取最低FPS"""
var monitor = get_instance()
if monitor.fps_history.is_empty():
return 0.0
var min_fps = monitor.fps_history[0]
for fps in monitor.fps_history:
if fps < min_fps:
min_fps = fps
return min_fps
## 获取内存使用情况
static func get_memory_usage() -> Dictionary:
"""
获取内存使用情况
@return: 内存使用信息字典
"""
var total_memory = OS.get_static_memory_peak_usage()
return {
"total_bytes": total_memory,
"total_mb": total_memory / (1024.0 * 1024.0),
"peak_usage": total_memory
}
## 获取网络延迟统计
static func get_network_latency_stats() -> Dictionary:
"""
获取网络延迟统计
@return: 延迟统计信息
"""
var monitor = get_instance()
if monitor.network_latency_history.is_empty():
return {
"average": 0.0,
"min": 0.0,
"max": 0.0,
"samples": 0
}
var total = 0.0
var min_latency = monitor.network_latency_history[0]
var max_latency = monitor.network_latency_history[0]
for latency in monitor.network_latency_history:
total += latency
if latency < min_latency:
min_latency = latency
if latency > max_latency:
max_latency = latency
return {
"average": total / monitor.network_latency_history.size(),
"min": min_latency,
"max": max_latency,
"samples": monitor.network_latency_history.size()
}
## 获取性能报告
static func get_performance_report() -> Dictionary:
"""
获取完整的性能报告
@return: 性能报告字典
"""
return {
"fps": {
"current": get_current_fps(),
"average": get_average_fps(),
"minimum": get_min_fps()
},
"memory": get_memory_usage(),
"network": get_network_latency_stats(),
"timestamp": Time.get_unix_time_from_system()
}
## 重置性能数据
static func reset_performance_data() -> void:
"""重置所有性能数据"""
var monitor = get_instance()
monitor.fps_history.clear()
monitor.memory_history.clear()
monitor.network_latency_history.clear()
monitor.frame_count = 0
monitor.total_frame_time = 0.0
preload("res://scripts/Utils.gd").debug_print("Performance data reset", "PERF")
## 启用/禁用性能监控
static func set_monitoring_enabled(enabled: bool) -> void:
"""启用或禁用性能监控"""
var monitor = get_instance()
monitor.monitoring_enabled = enabled
preload("res://scripts/Utils.gd").debug_print("Performance monitoring " + ("enabled" if enabled else "disabled"), "PERF")
## 检查性能监控是否启用
static func is_monitoring_enabled() -> bool:
"""检查性能监控是否启用"""
return get_instance().monitoring_enabled
## 导出性能数据
static func export_performance_data(file_path: String = "user://performance_log.json") -> bool:
"""
导出性能数据到文件
@param file_path: 文件路径
@return: 是否成功
"""
var monitor = get_instance()
var data = {
"fps_history": monitor.fps_history,
"memory_history": monitor.memory_history,
"network_latency_history": monitor.network_latency_history,
"export_timestamp": Time.get_unix_time_from_system(),
"performance_report": get_performance_report()
}
var file = FileAccess.open(file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(data)
file.store_string(json_string)
file.close()
preload("res://scripts/Utils.gd").debug_print("Performance data exported to: " + file_path, "PERF")
return true
else:
preload("res://scripts/ErrorHandler.gd").log_error("Failed to export performance data to: " + file_path)
return false