saumwacht-godot/tools/menu_benchmark.gd
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

83 lines
3.9 KiB
GDScript

extends Node
## Menu load time and frame cost on the current machine (no general performance claim).
## Run: godot --path . --resolution 1920x1080 res://tools/menu_benchmark.tscn -- --label=after
var main: Node3D
func _ready() -> void:
call_deferred("run")
func viewports() -> Array[RID]:
var list: Array[RID] = [get_viewport().get_viewport_rid()]
for node: Node in get_tree().root.find_children("*", "SubViewport", true, false):
if (node as SubViewport).render_target_update_mode != SubViewport.UPDATE_DISABLED:
list.append((node as SubViewport).get_viewport_rid())
return list
func run() -> void:
var label := "run"
for arg: String in OS.get_cmdline_user_args():
if arg.begins_with("--label="):
label = arg.substr(8)
Soundscape.enabled = false
WaveManager.set_physics_process(false)
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
var started: int = Time.get_ticks_usec()
main = load("res://scenes/main.tscn").instantiate()
add_child(main)
var instanced: int = Time.get_ticks_usec()
await RenderingServer.frame_post_draw
var first_frame: int = Time.get_ticks_usec()
var in_game: bool = "--in-game" in OS.get_cmdline_user_args()
var stage_ready_ms: float = -1.0
var menu: Node = main.hud.get("main_menu")
if menu != null:
while not (menu.stage.is_ready("glutpakt") and menu.stage.is_ready("wurzelbund")):
await get_tree().process_frame
stage_ready_ms = (Time.get_ticks_usec() - started) / 1000.0
if in_game:
main.hud._overlay_action.pressed.emit()
label += "-build"
await get_tree().create_timer(1.0).timeout
for rid: RID in viewports():
RenderingServer.viewport_set_measure_render_time(rid, true)
var warm_until: int = Time.get_ticks_msec() + 2500
while Time.get_ticks_msec() < warm_until:
await get_tree().process_frame
var frames: Array[float] = []
var gpu: Array[float] = []
var cpu_render: Array[float] = []
var draw_calls: Array[float] = []
var last: int = Time.get_ticks_usec()
var end: int = Time.get_ticks_msec() + 6000
while Time.get_ticks_msec() < end:
await RenderingServer.frame_post_draw
var now: int = Time.get_ticks_usec()
frames.append((now - last) / 1000.0)
last = now
var g: float = 0.0
var c: float = 0.0
for rid: RID in viewports():
g += RenderingServer.viewport_get_measured_render_time_gpu(rid)
c += RenderingServer.viewport_get_measured_render_time_cpu(rid)
gpu.append(g)
cpu_render.append(c)
draw_calls.append(Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME))
frames.sort()
var mean := func(values: Array[float]) -> float:
var total: float = 0.0
for v: float in values: total += v
return total / maxf(1, values.size())
var report := {
"label": label, "window": get_window().size, "canvas": get_viewport().get_visible_rect().size,
"renderer": RenderingServer.get_current_rendering_method(), "gpu": RenderingServer.get_video_adapter_name(),
"driver": RenderingServer.get_video_adapter_api_version(), "engine": Engine.get_version_info().string,
"os": OS.get_name() + " " + OS.get_version(), "cpu": OS.get_processor_name(),
"instantiate_ms": (instanced - started) / 1000.0, "first_frame_ms": (first_frame - started) / 1000.0, "stage_ready_ms": stage_ready_ms,
"frames": frames.size(), "frame_ms_mean": mean.call(frames), "frame_ms_p95": frames[int(frames.size() * .95)],
"gpu_ms_mean": mean.call(gpu), "render_cpu_ms_mean": mean.call(cpu_render),
"draw_calls_mean": mean.call(draw_calls), "video_mem_mb": Performance.get_monitor(Performance.RENDER_VIDEO_MEM_USED) / 1048576.0,
"static_mem_mb": Performance.get_monitor(Performance.MEMORY_STATIC) / 1048576.0,
"vsync": "disabled", "phase": GameState.phase_name(), "viewports_measured": viewports().size()}
var path := "res://docs/phase20-logs/perf-%s-%dx%d.json" % [label, get_window().size.x, get_window().size.y]
var file := FileAccess.open(path, FileAccess.WRITE)
file.store_string(JSON.stringify(report, "\t"))
file.close()
print("MENU_BENCHMARK: ", JSON.stringify(report))
await Soundscape.quit_game()